mirror of
https://github.com/audacity/audacity-actions.git
synced 2025-12-11 14:04:34 -06:00
164 lines
4.6 KiB
JavaScript
164 lines
4.6 KiB
JavaScript
const plist = require('simple-plist');
|
|
const fetch = require('node-fetch');
|
|
|
|
const helpers = require('../lib/helpers.js');
|
|
const fileUtils = require('./fileUtils.js');
|
|
|
|
const entitlements = `${workspaceDir}/mac/Audacity.entitlements`;
|
|
|
|
async function signFile(file, identity, args) {
|
|
args = args || [];
|
|
|
|
return helpers.execWithLog('xcrun', [
|
|
'codesign', '--verbose=3',
|
|
'--timestamp',
|
|
'--sign', identity,
|
|
'--options', 'runtime',
|
|
'--entitlements', entitlements,
|
|
'--force',
|
|
...args,
|
|
file
|
|
]);
|
|
}
|
|
|
|
async function fixupRPath(file) {
|
|
const output = (await helpers.getExecOutput('otool', ['-L', file])).stdout;
|
|
|
|
const libs = output.split('\n').
|
|
filter(line => line.indexOf('@rpath') != -1).
|
|
map(line => line.match(/@rpath\/.+\.dylib/)[0]);
|
|
|
|
if (libs.length == 0) {
|
|
return;
|
|
}
|
|
|
|
const loaderCommands =
|
|
(await helpers.getExecOutput('otool', ['-l', file])).stdout.
|
|
split('\n').
|
|
map(line => line.trim()).
|
|
filter(line => line.search(/path\s+@(?:executable|loader)_path/) != -1).
|
|
map(line => line.match(/path\s+(@(?:executable|loader)_path.*)\s+\(/)[1]).
|
|
map(line => ['-delete_rpath', line]).flat(Infinity);
|
|
|
|
|
|
const nameToolArgs = libs.map(lib => {
|
|
return ['-change', lib, lib.replace('@rpath', '@executable_path/../Frameworks') ]
|
|
}).flat(Infinity);
|
|
|
|
helpers.log(`Fixing rpath for ${file}`);
|
|
|
|
return helpers.execWithLog('install_name_tool', [
|
|
...nameToolArgs,
|
|
...loaderCommands,
|
|
file
|
|
])
|
|
|
|
}
|
|
|
|
async function singApp(appLocation, identity) {
|
|
if (!identity) {
|
|
helpers.log("Skipping code signings, as there is no codesign identity provided");
|
|
return ;
|
|
}
|
|
|
|
const bundleContens = await fileUtils.getAudacityMacOSBundleFiles(appLocation);
|
|
|
|
exeFiles = bundleContens.MacOS;
|
|
modules = bundleContens.modules;
|
|
frameworks = bundleContens.Frameworks.dylib;
|
|
|
|
binaries = [ ...exeFiles, ...modules, ...frameworks ];
|
|
|
|
for (const file of binaries) {
|
|
await fixupRPath(file);
|
|
}
|
|
|
|
for (const file of [/*...exeFiles,*/ ...modules]) {
|
|
await signFile(file, identity);
|
|
}
|
|
|
|
await signFile(appLocation, identity, [ '--deep' ]);
|
|
|
|
// Validate the signautre
|
|
await helpers.execWithLog('codesign', [
|
|
'--verify',
|
|
'--deep',
|
|
'--verbose=4',
|
|
'--strict',
|
|
appLocation
|
|
])
|
|
}
|
|
|
|
async function signDMG(dmgPath, appIdentifier, codesignIdentifier) {
|
|
if (!codesignIdentifier) {
|
|
helpers.log("Skipping code signings, as there is no codesign identity provided");
|
|
return ;
|
|
}
|
|
|
|
await helpers.execWithLog('xcrun', [
|
|
'codesign', '--verbose',
|
|
'--timestamp',
|
|
'--identifier', appIdentifier,
|
|
'--sign', codesignIdentifier,
|
|
dmgPath
|
|
]);
|
|
}
|
|
|
|
async function notarizeDMG(dmgPath, appIdentifier, notarizationUser, notarizationPassword) {
|
|
if (!notarizationUser || !notarizationUser) {
|
|
helpers.log("Skipping notarization, as there are np credentials provided");
|
|
return ;
|
|
}
|
|
|
|
helpers.log(`Notarizing DMG: ${dmgPath}`)
|
|
const notarizationResult = await helpers.getExecOutput('xcrun', [
|
|
'altool', '--notarize-app',
|
|
'--primary-bundle-id', appIdentifier,
|
|
'--file', dmgPath,
|
|
'--username', notarizationUser,
|
|
'--password', notarizationPassword,
|
|
'--output-format', 'xml'
|
|
]);
|
|
|
|
const requestId = plist.parse(notarizationResult.stdout)['notarization-upload']['RequestUUID'];
|
|
|
|
for(;;) {
|
|
await helpers.sleep(30000);
|
|
|
|
const notarizationInfo = await helpers.getExecOutput('xcrun', [
|
|
'altool',
|
|
'--notarization-info', requestId,
|
|
'--username', notarizationUser,
|
|
'--password', notarizationPassword,
|
|
'--output-format', 'xml'
|
|
]);
|
|
|
|
const parsedInfo = plist.parse(notarizationInfo.stdout);
|
|
|
|
const status = parsedInfo['notarization-info']['Status'];
|
|
|
|
if(status == 'success') {
|
|
return
|
|
} else if (status != 'in progress') {
|
|
const logUrl = parsedInfo['notarization-info']['LogFileURL'];
|
|
|
|
if (logUrl) {
|
|
const logResponse = await fetch(logUrl);
|
|
|
|
if (logResponse.ok) {
|
|
const log = await logResponse.text();
|
|
throw Error(`Notarization failed:\n${log}`);
|
|
}
|
|
}
|
|
|
|
throw Error(notarizationInfo.stdout);
|
|
}
|
|
}
|
|
}
|
|
|
|
module.exports = {
|
|
singApp: singApp,
|
|
signDMG: signDMG,
|
|
notarizeDMG: notarizeDMG,
|
|
}
|