ServiceStation icon indicating copy to clipboard operation
ServiceStation copied to clipboard

Sync settings between systems

Open gordon8214 opened this issue 5 years ago • 12 comments

I have a laptop and a desktop, and I have dozens of rules set up on the desktop. I really don't want to have to go and manually recreate them all on the laptop. It would be fantastic to be able to sync settings and scripts with iCloud.

gordon8214 avatar May 13 '20 06:05 gordon8214

I should note that for anyone who wants to sync their settings manually, you just need to copy rules.json from ~/Library/Group Containers/4G65N8LGGS.ServiceStationAppGroup/ to the same location on your new system, as well as any scripts from ~/Library/Application Scripts/com.knurling.ServiceStation.Attendant/.

gordon8214 avatar May 13 '20 06:05 gordon8214

Syncing across devices is on the list – thanks for making a topic.

Will likely use Apple's CloudKit:

https://developer.apple.com/icloud/cloudkit/

https://developer.apple.com/library/archive/documentation/DataManagement/Conceptual/CloudKitQuickStart/Introduction/Introduction.html

For the time being, yes, you can back up and manually sync the Rules file located at:

~/Library/Group Containers/4G65N8LGGS.ServiceStationAppGroup/rules.json

pkamb avatar May 13 '20 18:05 pkamb

Hmm, what I like to do is store all configs in a central location managed by Resilio Sync (could easily be Dropbox, Syncthing, a Git repo etc) and then create symlinks to. E.g.

CENTRAL_STORE=/path/to/repo/settings/servicestation
LOCAL_CFG="$HOME/Library/Group Containers/4G65N8LGGS.ServiceStationAppGroup"
mkdir -p $CENTRAL_STORE
mv "$LOCAL_CFG/rules.json" $CENTRAL_STORE
ln -s $CENTRAL_STORE/rules.json $LOCAL_CFG

But, when I tried this method with ServiceStation, it deleted my symlink instead and replaced it with a "real" file.

luckman212 avatar May 14 '20 02:05 luckman212

it deleted my symlink instead and replaced it with a "real" file.

Service Station uses Swift Codable to encode the Rules and Data(contentsOf: url)/rulesData.write(to: url, options: [.atomic]) to read/write to the file system. I'll look in to if there are any issues with this approach and symlinks.

pkamb avatar May 14 '20 18:05 pkamb

it deleted my symlink instead and replaced it with a "real" file.

Service Station uses Swift Codable to encode the Rules and Data(contentsOf: url)/rulesData.write(to: url, options: [.atomic]) to read/write to the file system. I'll look in to if there are any issues with this approach and symlinks.

I believe removing .atomic would fix this. The atomic write is writing a copy of the file to a new location then copying it in place of the symlink.

gordon8214 avatar May 14 '20 18:05 gordon8214

I'm not a filesystem expert, but I believe that APFS's copy-on-write behavior largely makes the atomic option unnecessary. The main benefit of using this option would be to avoid an issue in which a write error when saving the file to disk would end up corrupting the original file. APFS performs all writes this way at the filesystem level though (e.g., writes the data to a new location on disk, then updates the filesystem to point to the newly-written data after the write is successful).

gordon8214 avatar May 14 '20 19:05 gordon8214

I agree the atomic write seems like the culprit. A better method might be to attempt to detect if rules.json or other configs are symlinks and if so, resolve the original location and write to that (atomically if desired)

luckman212 avatar May 14 '20 20:05 luckman212

Out of interest, what happens if you use a hard link (ln) rather than symlink (ln -s)?

gingerbeardman avatar May 15 '20 08:05 gingerbeardman

I tried removing .atomic and running the script above to install a ln -s alias file.

Upon running Service Station, that results in the error:

Error Domain=NSCocoaErrorDomain Code=257 "The file “rules.json” couldn’t be opened because you don’t have permission to view it." UserInfo={NSFilePath=/Users/user/Library/Group Containers/4G65N8LGGS.ServiceStationAppGroup/rules.json, NSUnderlyingError=0x600000c99260 {Error Domain=NSPOSIXErrorDomain Code=1 "Operation not permitted"}}

I believe the issue is that the app has file access to the alias by way of being in its Group Container, but it does NOT have Sandbox-escaped access to the source of the alias.

Described here: https://stackoverflow.com/questions/12850786/mac-os-app-how-to-resolve-alias-and-read-original-file-within-sandbox


Using a ln hard link does seem to mirror the changes in both locations and avoid Sandbox problems. That is probably the better way to go unless the symlink is needed for some reason?

.atomic must be removed in this case as well, which will require an app update.

pkamb avatar May 23 '20 09:05 pkamb

A hardlink might solve the problem locally on 1 machine, but then the problem becomes this:

The link gets destroyed when the prefs are changed on the other machine: Dropbox, Resilio Sync etc will unlink the original and link the updated copy. This works fine when it's just a file referenced by a symlink, since the location is the same. But, hardlinks are linked by inode, so this breaks the linkage, thus prefs are no longer updated.

luckman212 avatar May 23 '20 13:05 luckman212

Oh, damn, is this stalemate then?

gingerbeardman avatar May 23 '20 16:05 gingerbeardman

Seems so for now. I think it might be "easier" to just import CloudKit and use that for sync vs any more mucking around with the fragility of sandbox/hardlinks.

luckman212 avatar May 23 '20 22:05 luckman212