mirror of https://github.com/keeweb/keeweb
macos installer
parent
6a34fffcc4
commit
b8ce1b5cc1
@ -0,0 +1,40 @@
|
||||
const { spawnSync } = require('child_process');
|
||||
|
||||
module.exports = function (grunt) {
|
||||
grunt.registerMultiTask(
|
||||
'osacompile',
|
||||
'Builds an executable .app package with osacompile',
|
||||
async function () {
|
||||
const done = this.async();
|
||||
const opt = this.options();
|
||||
|
||||
for (const file of this.files) {
|
||||
const dest = file.dest;
|
||||
const src = file.src[0];
|
||||
|
||||
const args = [];
|
||||
if (opt.language) {
|
||||
args.push('-l', opt.language);
|
||||
}
|
||||
args.push('-o', dest);
|
||||
args.push(src);
|
||||
|
||||
grunt.log.writeln(`Running: osacompile ${args.join(' ')}`);
|
||||
|
||||
const res = spawnSync('osacompile', args);
|
||||
|
||||
if (res.status) {
|
||||
grunt.warn(
|
||||
`osacompile exit code ${
|
||||
res.status
|
||||
}.\nSTDOUT:\n${res.stdout.toString()}\nSTDERR:\n${res.stderr.toString()}`
|
||||
);
|
||||
}
|
||||
|
||||
grunt.log.writeln(`Built ${dest}`);
|
||||
}
|
||||
|
||||
done();
|
||||
}
|
||||
);
|
||||
};
|
@ -1,52 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleAllowMixedLocalizations</key>
|
||||
<true/>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>English</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>applet</string>
|
||||
<key>CFBundleIconFile</key>
|
||||
<string>applet</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>com.apple.ScriptEditor.id.KeeWeb-Installer</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>KeeWeb Installer</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>1.0</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>aplt</string>
|
||||
<key>LSMinimumSystemVersionByArchitecture</key>
|
||||
<dict>
|
||||
<key>x86_64</key>
|
||||
<string>10.6</string>
|
||||
</dict>
|
||||
<key>LSRequiresCarbon</key>
|
||||
<true/>
|
||||
<key>WindowState</key>
|
||||
<dict>
|
||||
<key>bundleDividerCollapsed</key>
|
||||
<true/>
|
||||
<key>bundlePositionOfDivider</key>
|
||||
<real>0.0</real>
|
||||
<key>dividerCollapsed</key>
|
||||
<false/>
|
||||
<key>eventLogLevel</key>
|
||||
<integer>2</integer>
|
||||
<key>name</key>
|
||||
<string>ScriptWindowState</string>
|
||||
<key>positionOfDivider</key>
|
||||
<real>421</real>
|
||||
<key>savedFrame</key>
|
||||
<string>20 90 700 672 0 0 1280 777 </string>
|
||||
<key>selectedTab</key>
|
||||
<string>description</string>
|
||||
</dict>
|
||||
</dict>
|
||||
</plist>
|
Binary file not shown.
@ -1 +0,0 @@
|
||||
APPLaplt
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Before Width: | Height: | Size: 362 B |
@ -1,5 +0,0 @@
|
||||
{\rtf1\ansi\ansicpg1252\cocoartf1504\cocoasubrtf830
|
||||
{\fonttbl}
|
||||
{\colortbl;\red255\green255\blue255;}
|
||||
{\*\expandedcolortbl;;}
|
||||
}
|
@ -1,177 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>files</key>
|
||||
<dict>
|
||||
<key>Resources/Scripts/main.scpt</key>
|
||||
<data>
|
||||
hsRwl39Q/JbFKwwQ/MLvOD3Mf4Q=
|
||||
</data>
|
||||
<key>Resources/applet.icns</key>
|
||||
<data>
|
||||
vSn/k+EzqMViG5RcXNXpodKsdyk=
|
||||
</data>
|
||||
<key>Resources/applet.rsrc</key>
|
||||
<data>
|
||||
8fN/GtxUP559toTqTl+V3wCZeoU=
|
||||
</data>
|
||||
<key>Resources/description.rtfd/TXT.rtf</key>
|
||||
<data>
|
||||
U1/ikutWmrJdAXLoU25d4KUS06c=
|
||||
</data>
|
||||
</dict>
|
||||
<key>files2</key>
|
||||
<dict>
|
||||
<key>Resources/Scripts/main.scpt</key>
|
||||
<dict>
|
||||
<key>hash</key>
|
||||
<data>
|
||||
hsRwl39Q/JbFKwwQ/MLvOD3Mf4Q=
|
||||
</data>
|
||||
<key>hash2</key>
|
||||
<data>
|
||||
t7kR7hl6N/mOn8SxdBAqRDqpnWm/sWW4XJ4jYDK4U5I=
|
||||
</data>
|
||||
</dict>
|
||||
<key>Resources/applet.icns</key>
|
||||
<dict>
|
||||
<key>hash</key>
|
||||
<data>
|
||||
vSn/k+EzqMViG5RcXNXpodKsdyk=
|
||||
</data>
|
||||
<key>hash2</key>
|
||||
<data>
|
||||
NcZgMymH9fQebOOAufbFmH8w7f0RfzDMZRykqiqlrGE=
|
||||
</data>
|
||||
</dict>
|
||||
<key>Resources/applet.rsrc</key>
|
||||
<dict>
|
||||
<key>hash</key>
|
||||
<data>
|
||||
8fN/GtxUP559toTqTl+V3wCZeoU=
|
||||
</data>
|
||||
<key>hash2</key>
|
||||
<data>
|
||||
eBEutqxEKm3EiJlpx6YIakFWJU2RKjnLue7r2J/WmJo=
|
||||
</data>
|
||||
</dict>
|
||||
<key>Resources/description.rtfd/TXT.rtf</key>
|
||||
<dict>
|
||||
<key>hash</key>
|
||||
<data>
|
||||
U1/ikutWmrJdAXLoU25d4KUS06c=
|
||||
</data>
|
||||
<key>hash2</key>
|
||||
<data>
|
||||
vGT9c0omY5YveJ9Gjv3lLYFVn64gjtcT7Nc6UAWGXh4=
|
||||
</data>
|
||||
</dict>
|
||||
</dict>
|
||||
<key>rules</key>
|
||||
<dict>
|
||||
<key>^Resources/</key>
|
||||
<true/>
|
||||
<key>^Resources/.*\.lproj/</key>
|
||||
<dict>
|
||||
<key>optional</key>
|
||||
<true/>
|
||||
<key>weight</key>
|
||||
<real>1000</real>
|
||||
</dict>
|
||||
<key>^Resources/.*\.lproj/locversion.plist$</key>
|
||||
<dict>
|
||||
<key>omit</key>
|
||||
<true/>
|
||||
<key>weight</key>
|
||||
<real>1100</real>
|
||||
</dict>
|
||||
<key>^Resources/Base\.lproj/</key>
|
||||
<dict>
|
||||
<key>weight</key>
|
||||
<real>1010</real>
|
||||
</dict>
|
||||
<key>^version.plist$</key>
|
||||
<true/>
|
||||
</dict>
|
||||
<key>rules2</key>
|
||||
<dict>
|
||||
<key>.*\.dSYM($|/)</key>
|
||||
<dict>
|
||||
<key>weight</key>
|
||||
<real>11</real>
|
||||
</dict>
|
||||
<key>^(.*/)?\.DS_Store$</key>
|
||||
<dict>
|
||||
<key>omit</key>
|
||||
<true/>
|
||||
<key>weight</key>
|
||||
<real>2000</real>
|
||||
</dict>
|
||||
<key>^(Frameworks|SharedFrameworks|PlugIns|Plug-ins|XPCServices|Helpers|MacOS|Library/(Automator|Spotlight|LoginItems))/</key>
|
||||
<dict>
|
||||
<key>nested</key>
|
||||
<true/>
|
||||
<key>weight</key>
|
||||
<real>10</real>
|
||||
</dict>
|
||||
<key>^.*</key>
|
||||
<true/>
|
||||
<key>^Info\.plist$</key>
|
||||
<dict>
|
||||
<key>omit</key>
|
||||
<true/>
|
||||
<key>weight</key>
|
||||
<real>20</real>
|
||||
</dict>
|
||||
<key>^PkgInfo$</key>
|
||||
<dict>
|
||||
<key>omit</key>
|
||||
<true/>
|
||||
<key>weight</key>
|
||||
<real>20</real>
|
||||
</dict>
|
||||
<key>^Resources/</key>
|
||||
<dict>
|
||||
<key>weight</key>
|
||||
<real>20</real>
|
||||
</dict>
|
||||
<key>^Resources/.*\.lproj/</key>
|
||||
<dict>
|
||||
<key>optional</key>
|
||||
<true/>
|
||||
<key>weight</key>
|
||||
<real>1000</real>
|
||||
</dict>
|
||||
<key>^Resources/.*\.lproj/locversion.plist$</key>
|
||||
<dict>
|
||||
<key>omit</key>
|
||||
<true/>
|
||||
<key>weight</key>
|
||||
<real>1100</real>
|
||||
</dict>
|
||||
<key>^Resources/Base\.lproj/</key>
|
||||
<dict>
|
||||
<key>weight</key>
|
||||
<real>1010</real>
|
||||
</dict>
|
||||
<key>^[^/]+$</key>
|
||||
<dict>
|
||||
<key>nested</key>
|
||||
<true/>
|
||||
<key>weight</key>
|
||||
<real>10</real>
|
||||
</dict>
|
||||
<key>^embedded\.provisionprofile$</key>
|
||||
<dict>
|
||||
<key>weight</key>
|
||||
<real>20</real>
|
||||
</dict>
|
||||
<key>^version\.plist$</key>
|
||||
<dict>
|
||||
<key>weight</key>
|
||||
<real>20</real>
|
||||
</dict>
|
||||
</dict>
|
||||
</dict>
|
||||
</plist>
|
@ -0,0 +1,11 @@
|
||||
{
|
||||
"env": {
|
||||
"applescript": true
|
||||
},
|
||||
"globals": {
|
||||
"app": false
|
||||
},
|
||||
"rules": {
|
||||
"no-console": "off"
|
||||
}
|
||||
}
|
@ -0,0 +1,15 @@
|
||||
#!/bin/bash
|
||||
set -euxo pipefail
|
||||
|
||||
rm -rf package/osx/KeeWeb\ Installer.app
|
||||
|
||||
osacompile \
|
||||
-l JavaScript \
|
||||
-o package/osx/KeeWeb\ Installer.app \
|
||||
package/osx/installer/main.js
|
||||
|
||||
cp graphics/icon.icns package/osx/KeeWeb\ Installer.app/Contents/Resources/applet.icns
|
||||
codesign --remove-signature package/osx/KeeWeb\ Installer.app
|
||||
|
||||
CS_ID=$(cat keys/codesign.json | jq -j '.identities.app')
|
||||
codesign -s "$CS_ID" package/osx/KeeWeb\ Installer.app
|
@ -0,0 +1,85 @@
|
||||
#!/usr/bin/env osascript -l JavaScript
|
||||
|
||||
ObjC.import('Foundation');
|
||||
ObjC.import('stdlib');
|
||||
|
||||
const app = Application.currentApplication();
|
||||
app.includeStandardAdditions = true;
|
||||
|
||||
const args = getArgs();
|
||||
if (args.update) {
|
||||
const waitPid = args.waitPid | 0;
|
||||
if (waitPid) {
|
||||
waitForExitOrKill(waitPid);
|
||||
}
|
||||
|
||||
const dmg = checkFilePath(args.dmg, 'dmg');
|
||||
const target = checkFilePath(args.target, 'app');
|
||||
|
||||
const targetOwner = app.doShellScript(`stat -f '%Su' ${target}`);
|
||||
const setAdminRights = targetOwner === 'root';
|
||||
|
||||
const tmpDir = dmg + '.mount';
|
||||
|
||||
let script = `set -euxo pipefail
|
||||
hdiutil detach ${tmpDir} 2>/dev/null || true
|
||||
rm -rf ${tmpDir}
|
||||
mkdir -p ${tmpDir}
|
||||
hdiutil attach -readonly -nobrowse -mountpoint ${tmpDir} ${dmg}
|
||||
rm -rf ${target}
|
||||
cp -pR ${tmpDir}/KeeWeb.app ${target}
|
||||
hdiutil detach ${tmpDir}
|
||||
rm -rf ${tmpDir}
|
||||
`;
|
||||
const scriptOptions = {};
|
||||
if (setAdminRights) {
|
||||
script += `chown -R 0 ${target}`;
|
||||
scriptOptions.administratorPrivileges = true;
|
||||
}
|
||||
app.doShellScript(script, scriptOptions);
|
||||
} else if (args.install) {
|
||||
app.doShellScript('chown -R 0 /Applications/KeeWeb.app', { administratorPrivileges: true });
|
||||
} else {
|
||||
throw 'Unknown operation';
|
||||
}
|
||||
|
||||
function getArgs() {
|
||||
// https://github.com/JXA-Cookbook/JXA-Cookbook/wiki/Shell-and-CLI-Interactions#arguments
|
||||
const objcArgs = $.NSProcessInfo.processInfo.arguments;
|
||||
const argc = objcArgs.count;
|
||||
const args = {};
|
||||
for (let i = 0; i < argc; i++) {
|
||||
const arg = ObjC.unwrap(objcArgs.objectAtIndex(i));
|
||||
const match = arg.match(/^--([^=]+)(=(.*))?/);
|
||||
if (match) {
|
||||
const argName = match[1].replace(/-./g, (m) => m[1].toUpperCase());
|
||||
args[argName] = match[3] || true;
|
||||
}
|
||||
}
|
||||
return args;
|
||||
}
|
||||
|
||||
function waitForExitOrKill(pid) {
|
||||
for (let i = 0; i < 10; i++) {
|
||||
const psCount = Application('System Events').processes.whose({ unixId: pid }).length;
|
||||
if (psCount === 0) {
|
||||
return;
|
||||
}
|
||||
delay(1);
|
||||
}
|
||||
app.doShellScript(`kill ${pid}`);
|
||||
}
|
||||
|
||||
function checkFilePath(path, ext) {
|
||||
if (!path) {
|
||||
throw `File not specified: ${ext}`;
|
||||
}
|
||||
if (!path.endsWith('.' + ext)) {
|
||||
throw `Bad file extension: ${ext} (${path})`;
|
||||
}
|
||||
const file = Application('System Events').files.byName(path);
|
||||
if (!file.exists()) {
|
||||
throw `File doesn't exist: ${ext} (${path})`;
|
||||
}
|
||||
return file.posixPath().replace(/ /g, '\\ ');
|
||||
}
|
Loading…
Reference in New Issue