Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,18 @@ Install the official [Slack app](https://slack.com/downloads/mac) (not the App S
curl -fsSL https://raw.githubusercontent.com/3kh0/slick/main/install.sh | bash
```

If Slack is installed somewhere else, pass its app bundle with `--slack-app`:

```bash
./install.sh --slack-app "$HOME/Documents/Apps/Slack.app"
```

When using the remote installer, pass the option to `bash` like this:

```bash
curl -fsSL https://raw.githubusercontent.com/3kh0/slick/main/install.sh | bash -s -- --slack-app "$HOME/Documents/Apps/Slack.app"
```

If you prefer doing it by hand, grab the latest prebuilt app from the [releases page](https://github.com/3kh0/slick/releases/latest) and pick the build for your Mac (check > About This Mac > Chip if unsure):

- `Slick-build-N-mac-arm64` — **Apple Silicon** (if there is a M in the name)
Expand Down
24 changes: 19 additions & 5 deletions install.sh
Original file line number Diff line number Diff line change
Expand Up @@ -43,15 +43,29 @@ exit(LSSetDefaultHandlerForURLScheme("slack" as NSString as CFString, id as NSSt
EOF
}

if [ "${1:-}" = "--restore-handler" ]; then
handler com.tinyspeck.slackmacgap && echo "slack:// now opens the official Slack again." || die "could not restore handler"
exit 0
fi
while [ "$#" -gt 0 ]; do
case "$1" in
--slack-app)
[ "$#" -ge 2 ] || die "--slack-app needs a path"
SLACK="${2%/}"
shift 2
;;
--restore-handler)
handler com.tinyspeck.slackmacgap && echo "slack:// now opens the official Slack again." || die "could not restore handler"
exit 0
;;
*) die "unknown option: $1" ;;
esac
done

step "Checking prerequisites"
[ "$(uname -s)" = "Darwin" ] || die "Slick only supports macOS :("
[ -f "$SLACK/Contents/Resources/app.asar" ] \
|| die "Slack not found at $SLACK, please install it from slack.com first."
SLACK="$(cd "$(dirname "$SLACK")" && pwd)/$(basename "$SLACK")"
SLACK_CONFIG="$HOME/Library/Application Support/Slick/slick/slack-app-path"
mkdir -p "$(dirname "$SLACK_CONFIG")"
printf '%s\n' "$SLACK" > "$SLACK_CONFIG"

if [ -f "$ROOT/scripts/byoe/build-handoff-app.js" ]; then
node -e 'process.exit(parseInt(process.versions.node, 10) >= 18 ? 0 : 1)' 2>/dev/null \
Expand Down Expand Up @@ -99,7 +113,7 @@ if [ -f "$ROOT/scripts/byoe/build-handoff-app.js" ]; then
step "Building $APP (Build $BUILD)"
node "$ROOT/scripts/byoe/build-handoff-app.js" --target "$APP" \
--profile "$HOME/Library/Application Support/Slack" \
--app-version "$VERSION" --build-number "$BUILD" --allow-non-tmp --force >/dev/null
--slack-app "$SLACK" --app-version "$VERSION" --build-number "$BUILD" --allow-non-tmp --force >/dev/null

step "Installing icon"
"$ROOT/scripts/byoe/set-icon.sh" 2>&1 | while IFS= read -r line; do printf ' %s\n' "$line"; done
Expand Down
23 changes: 16 additions & 7 deletions scripts/byoe/build-handoff-app.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,13 @@ const { spawnSync } = require('child_process');

const ROOT = path.resolve(__dirname, '..', '..');
const DEFAULT_SOURCE_APP = path.join(ROOT, 'byoe/node_modules/electron/dist/Electron.app');
const SLACK_RESOURCES = '/Applications/Slack.app/Contents/Resources';
const SLACK_ASAR = path.join(SLACK_RESOURCES, 'app.asar');
const ENTITLEMENTS = path.join(ROOT, 'scripts/release/entitlements.plist');
const DEFAULTS = {
target: '/tmp/slick/Slick.app',
profile: '/tmp/slick/profile',
appVersion: '1.0.0',
buildNumber: '0',
slackApp: '/Applications/Slack.app',
sourceApp: process.env.SLICK_SOURCE_APP || DEFAULT_SOURCE_APP,
force: false,
allowNonTmp: false,
Expand All @@ -24,13 +23,15 @@ function usage() {
console.error(`Usage:
node scripts/byoe/build-handoff-app.js [--target <app>] [--profile <dir>] [--app-version <x.y.z>]
[--build-number <n>]
[--slack-app <Slack.app>]
[--source-app <Electron.app>] [--force] [--allow-non-tmp]

Defaults:
--target ${DEFAULTS.target}
--profile ${DEFAULTS.profile}
--app-version ${DEFAULTS.appVersion}
--build-number ${DEFAULTS.buildNumber}
--slack-app ${DEFAULTS.slackApp}
--source-app ${DEFAULTS.sourceApp}`);
process.exit(2);
}
Expand All @@ -42,6 +43,7 @@ function parseArgs(argv) {
else if (argv[i] === '--profile') o.profile = argv[++i] || usage();
else if (argv[i] === '--app-version') o.appVersion = argv[++i] || usage();
else if (argv[i] === '--build-number') o.buildNumber = argv[++i] || usage();
else if (argv[i] === '--slack-app') o.slackApp = argv[++i] || usage();
else if (argv[i] === '--source-app') o.sourceApp = argv[++i] || usage();
else if (argv[i] === '--force') o.force = true;
else if (argv[i] === '--allow-non-tmp') o.allowNonTmp = true;
Expand Down Expand Up @@ -179,17 +181,23 @@ const { app, dialog, shell, Menu, MenuItem } = require('electron');
const SLICK_ROOT = path.join(process.resourcesPath, 'slick');
const PROFILE = process.env.SLICK_HANDOFF_PROFILE || path.join(app.getPath('appData'), 'Slick');
const DEFAULT_THEME = ${JSON.stringify(defaultTheme)};
const SLACK_RESOURCES = ${JSON.stringify(SLACK_RESOURCES)};
const SLACK_ASAR = ${JSON.stringify(SLACK_ASAR)};
const DEFAULT_SLACK_APP = ${JSON.stringify(path.resolve(opts.slackApp))};
const SLACK_PATH_CONFIG = path.join(PROFILE, 'slick', 'slack-app-path');
let SLACK_APP = DEFAULT_SLACK_APP;
try {
SLACK_APP = fs.readFileSync(SLACK_PATH_CONFIG, 'utf8').trim() || DEFAULT_SLACK_APP;
} catch {}
const SLACK_RESOURCES = path.join(SLACK_APP, 'Contents', 'Resources');
const SLACK_ASAR = path.join(SLACK_RESOURCES, 'app.asar');
const SLICK_VERSION = ${JSON.stringify(opts.appVersion)};
const SLICK_BUILD = parseInt(${JSON.stringify(opts.buildNumber)}, 10) || 0;
const updater = require(path.join(SLICK_ROOT, 'scripts/byoe/updater.js')).create({ version: SLICK_VERSION, build: SLICK_BUILD, profile: PROFILE });
const RELEASES_URL = updater.RELEASES_URL;
const slackUpdater = require(path.join(SLICK_ROOT, 'scripts/byoe/slack-updater.js')).create({ version: SLICK_VERSION, profile: PROFILE });
const slackUpdater = require(path.join(SLICK_ROOT, 'scripts/byoe/slack-updater.js')).create({ version: SLICK_VERSION, profile: PROFILE, slackApp: SLACK_APP });

function slackElectronMajor() {
try {
const plist = '/Applications/Slack.app/Contents/Frameworks/Electron Framework.framework/Resources/Info.plist';
const plist = path.join(SLACK_APP, 'Contents/Frameworks/Electron Framework.framework/Resources/Info.plist');
const raw = require('child_process').execFileSync(
'/usr/bin/plutil', ['-extract', 'CFBundleVersion', 'raw', '-o', '-', plist], { encoding: 'utf8' },
);
Expand All @@ -214,7 +222,7 @@ function handlePreflight(problem) {
type: 'error',
title: 'Slick',
message: 'Slack is not installed',
detail: 'Slick needs the official Slack app at /Applications/Slack.app. Install it from slack.com, then open Slick again.',
detail: 'Slick needs the official Slack app at ' + SLACK_APP + '. Install it there or reinstall Slick with --slack-app, then open Slick again.',
buttons: ['Quit'],
});
return false;
Expand Down Expand Up @@ -359,6 +367,7 @@ try {

function boot() {
app.setPath('userData', PROFILE);
process.env.SLICK_SLACK_APP = SLACK_APP;
installPatch();
seedSettings();
updater.scheduleUpdateChecks();
Expand Down
2 changes: 1 addition & 1 deletion scripts/byoe/inject.js
Original file line number Diff line number Diff line change
Expand Up @@ -388,7 +388,7 @@ app.on('session-created', ap);

function installNotificationSounds() {
if (process.platform !== 'darwin') return;
const R = '/Applications/Slack.app/Contents/Resources';
const R = path.join(process.env.SLICK_SLACK_APP || '/Applications/Slack.app', 'Contents', 'Resources');
const s = path.join(app.getPath('home'), 'Library', 'Sounds');
let names;
try {
Expand Down
16 changes: 7 additions & 9 deletions scripts/byoe/slack-updater.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,6 @@ const https = require('https');
const { execFile, execFileSync } = require('child_process');

const MAC = process.platform === 'darwin';
const SLACK_APP = '/Applications/Slack.app';
const SLACK_INFO_PLIST = path.join(SLACK_APP, 'Contents/Info.plist');
const FRAMEWORK_PLIST_REL = 'Contents/Frameworks/Electron Framework.framework/Resources/Info.plist';
const SLACK_BUNDLE_ID = 'com.tinyspeck.slackmacgap';
const LATEST_REDIRECT = 'https://slack.com/ssb/download-osx-universal';
Expand Down Expand Up @@ -61,8 +59,6 @@ function plistValue(plist, key) {
}
const electronMajorOf = (app) => parseInt(plistValue(path.join(app, FRAMEWORK_PLIST_REL), 'CFBundleVersion'), 10) || 0;
const bundleIdOf = (app) => plistValue(path.join(app, 'Contents/Info.plist'), 'CFBundleIdentifier');
const installedVersion = () => plistValue(SLACK_INFO_PLIST, 'CFBundleShortVersionString');

// Move a bundle dir onto another path: cheap rename within a volume, ditto copy across.
function moveDir(from, to) {
try {
Expand All @@ -72,7 +68,9 @@ function moveDir(from, to) {
}
}

function create({ profile, version }) {
function create({ profile, version, slackApp = '/Applications/Slack.app' }) {
const slackInfoPlist = path.join(slackApp, 'Contents/Info.plist');
const installedVersion = () => plistValue(slackInfoPlist, 'CFBundleShortVersionString');
if (!MAC) {
const noop = () => {};
return {
Expand Down Expand Up @@ -168,17 +166,17 @@ function create({ profile, version }) {
clearStaging()
);

const backup = `${SLACK_APP}.slick-old`;
const backup = `${slackApp}.slick-old`;
try {
fs.rmSync(backup, { recursive: true, force: true });
if (fs.existsSync(SLACK_APP)) fs.renameSync(SLACK_APP, backup);
moveDir(stagedApp, SLACK_APP);
if (fs.existsSync(slackApp)) fs.renameSync(slackApp, backup);
moveDir(stagedApp, slackApp);
fs.rmSync(backup, { recursive: true, force: true });
log(`installed Slack ${marker.version}`);
} catch (e) {
// Restore whatever we moved so the user is never left without Slack.
try {
if (!fs.existsSync(SLACK_APP) && fs.existsSync(backup)) fs.renameSync(backup, SLACK_APP);
if (!fs.existsSync(slackApp) && fs.existsSync(backup)) fs.renameSync(backup, slackApp);
} catch {}
log(`failed to install staged Slack: ${msg(e)}`);
} finally {
Expand Down