From ed78dd6adf81c2dc2650c02ea808d0645f1b04a8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Nicouleaud?= Date: Wed, 27 Jun 2018 17:32:48 +0200 Subject: [PATCH 1/2] gui: Add synced dir to macOS favorites with python script Apple removed the `sfltool add-item` subcommand in macOS 10.13 (High Sierra): https://openradar.appspot.com/35722438 We were using it to add the sync folder to the Finder's favorite items on previous macOS releases. The `sfltool` CLI is actually a frontend to the `sharedfilelistd` XPC service. The latter reads/writes from bplist files (e.g. `~/Library/Application\ Support/com.apple.sharedfilelist`). Talking to the XPC service was not a straightforward option. Writing directly to those files could easily break. And the npm packages we tried were losing data in the process. A deprecated API exists to add favorite items: https://developer.apple.com/documentation/coreservices/klssharedfilelistfavoriteitems Having an embedded binary working on multiple macOS releases is not so easy, so we used the built-in macOS python for this, since it includes bindings for the relevant API. We're not the only ones to use the deprecated API: https://github.com/nextcloud/desktop/blob/master/src/common/utility_mac.cpp#L30 So hopefully we should be able to find a solution in case it is finally removed in some future macOS release. --- electron-builder.yml | 3 +++ gui/js/shortcut.js | 19 +++++++++++------- gui/scripts/macos-add-favorite.py | 33 +++++++++++++++++++++++++++++++ 3 files changed, 48 insertions(+), 7 deletions(-) create mode 100755 gui/scripts/macos-add-favorite.py diff --git a/electron-builder.yml b/electron-builder.yml index 8efc97641..e4a741f1a 100644 --- a/electron-builder.yml +++ b/electron-builder.yml @@ -12,7 +12,10 @@ files: - gui/main.js - gui/node_modules - gui/ports.js +- gui/scripts/** - package.json +asarUnpack: +- gui/scripts/** directories: buildResources: gui/assets win: diff --git a/gui/js/shortcut.js b/gui/js/shortcut.js index 2589e42d8..542048df2 100644 --- a/gui/js/shortcut.js +++ b/gui/js/shortcut.js @@ -1,7 +1,6 @@ const lnk = require('lnk') const os = require('os') const path = require('path') -const url = require('url') const childProcess = require('child_process') const log = require('../../core/app').logger({ @@ -28,9 +27,16 @@ const execSync = (cmd) => { log.debug(output) } -const sfltoolAddFavorite = (path) => { - const item = url.resolve('file://', path) - execSync(`sfltool add-item com.apple.LSSharedFileList.FavoriteItems ${item}`) +function quotePath (path) { + return `"${path.replace(/"/g, '\\"')}"` +} + +const macosAddFavoriteScript = path + .resolve(__dirname, '../scripts/macos-add-favorite.py') + .replace('/app.asar/', '/app.asar.unpacked/') + +const macosAddFavorite = (path) => { + execSync(`/usr/bin/python ${quotePath(macosAddFavoriteScript)} ${quotePath(path)}`) } // For Darwin <=> macOS version mapping, see: @@ -44,9 +50,8 @@ module.exports.addFileManagerShortcut = (config) => { win10PinToHome(config.syncPath) } else if (platform === 'win32' && major >= 6) { winAddLink(config.syncPath) - } else if (platform === 'darwin' && major >= 15) { - // sfltool is available since 10.11 (El Capitan) - sfltoolAddFavorite(config.syncPath) + } else if (platform === 'darwin') { + macosAddFavorite(config.syncPath) } else { throw new Error(`Not registering shortcut on ${platform} ${major}`) } diff --git a/gui/scripts/macos-add-favorite.py b/gui/scripts/macos-add-favorite.py new file mode 100755 index 000000000..f4dcb42cb --- /dev/null +++ b/gui/scripts/macos-add-favorite.py @@ -0,0 +1,33 @@ +#!/usr/bin/python + +from Cocoa import NSURL +from CoreFoundation import CFArrayGetCount, CFArrayGetValueAtIndex, kCFAllocatorDefault +from Foundation import NSBundle +from LaunchServices import kLSSharedFileListFavoriteItems +from objc import loadBundleFunctions +from sys import argv + +# For some reason, these functions cannot be imported directly and must be +# manually loaded from the SharedFileList bundle +SFL_bundle = NSBundle.bundleWithIdentifier_('com.apple.coreservices.SharedFileList') +functions = [ + ('LSSharedFileListCreate', '^{OpaqueLSSharedFileListRef=}^{__CFAllocator=}^{__CFString=}@'), + ('LSSharedFileListCopySnapshot', '^{__CFArray=}^{OpaqueLSSharedFileListRef=}o^I'), + ('LSSharedFileListInsertItemURL', '^{OpaqueLSSharedFileListItemRef=}^{OpaqueLSSharedFileListRef=}^{OpaqueLSSharedFileListItemRef=}^{__CFString=}^{OpaqueIconRef=}^{__CFURL=}^{__CFDictionary=}^{__CFArray=}'), + ('kLSSharedFileListItemBeforeFirst', '^{OpaqueLSSharedFileListItemRef=}'), +] +loadBundleFunctions(SFL_bundle, globals(), functions) + +# The path to added to the Finder's favorites +path = argv[1] + +# Make it an URL object (which is a valid favorite item) +item = NSURL.alloc().initFileURLWithPath_(path) + +# Retrieve the favorite items list +favorite_items = LSSharedFileListCreate(kCFAllocatorDefault, + kLSSharedFileListFavoriteItems, None) + +# Add the item to the top of the list +LSSharedFileListInsertItemURL(favorite_items, kLSSharedFileListItemBeforeFirst, + None, None, item, None, None) From b19433476ea174b25d03a4786c66b05202a653a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Nicouleaud?= Date: Wed, 27 Jun 2018 18:11:09 +0200 Subject: [PATCH 2/2] build: 3.8.1-alpha.5 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 503243081..75e2b1e09 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "CozyDrive", "productName": "Cozy Drive", "private": true, - "version": "3.8.0-beta.1", + "version": "3.8.1-alpha.5", "description": "Cozy Drive is a synchronization tool for your files and folders with Cozy Cloud.", "homepage": "https://github.com/cozy-labs/cozy-desktop", "author": "Cozy Cloud (https://cozycloud.cc/)",