├── Backup Ulysses on Quit (all in one).kmmacros ├── Backup-Ulysses-on-Quit.jpg ├── Backup-Ulysses-on-Quit.kmmacros ├── README.md ├── backup-ulysses-simpler.sh └── backup-ulysses.sh /Backup Ulysses on Quit (all in one).kmmacros: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Activate 7 | Normal 8 | CreationDate 9 | 459387347.72605699 10 | IsActive 11 | 12 | Macros 13 | 14 | 15 | Actions 16 | 17 | 18 | DisplayKind 19 | None 20 | IncludeStdErr 21 | 22 | IsActive 23 | 24 | IsDisclosed 25 | 26 | MacroActionType 27 | ExecuteShellScript 28 | Path 29 | /usr/local/scripts/backup-ulysses.sh 30 | Text 31 | #!/bin/zsh -f 32 | # Purpose: Make extra Ulysses backups because you're paranoid. No I'm not. Yes you are. Ok, yeah, that's fair. 33 | # 34 | # 35 | # I sent an earlier version of this to the Ulysses developers, and was told: 36 | # "It sounds like the only thing that can harm your texts now is a zombie apocalypse at 37 | # the Dropbox headquarters or the heat death of the universe." 38 | # 39 | # 40 | # 41 | # From: Timothy J. Luoma 42 | # Mail: luomat at gmail dot com 43 | # Date: 2016-03-09 44 | 45 | 46 | # This is where the archives will be saved when finishes 47 | # it will be created if it does not exist 48 | ARCHIVE_DIR="$HOME/Dropbox/Backups/Ulysses/" 49 | 50 | 51 | ####|####|####|####|####|####|####|####|####|####|####|####|####|####|#### 52 | # 53 | # You should not need to change anything below this line, 54 | # although you are welcome to if you know what you are doing. 55 | # 56 | ####|####|####|####|####|####|####|####|####|####|####|####|####|####|#### 57 | 58 | 59 | # short name of this file without path or extension 60 | NAME="backup-ulysses" 61 | 62 | if [ -e "$HOME/.path" ] 63 | then 64 | source "$HOME/.path" 65 | else 66 | PATH='/usr/local/scripts:/usr/local/bin:/usr/bin:/usr/sbin:/sbin:/bin' 67 | fi 68 | 69 | zmodload zsh/datetime 70 | 71 | TIME=`strftime "%Y-%m-%d--%H.%M.%S" "$EPOCHSECONDS"` 72 | 73 | function timestamp { strftime "%Y-%m-%d--%H.%M.%S" "$EPOCHSECONDS" } 74 | 75 | LOG="$HOME/Library/Logs/$NAME.log" 76 | 77 | function msg { 78 | 79 | echo "$NAME: $@" | tee -a "$LOG" 80 | 81 | # If growlnotify is installed in $PATH 82 | # use it to report messages 83 | if (( $+commands[growlnotify] )) 84 | then 85 | 86 | growlnotify \ 87 | --appIcon "Ulysses" \ 88 | --identifier "$NAME" \ 89 | --message "$@" \ 90 | --title "$NAME" 91 | fi 92 | 93 | } 94 | 95 | 96 | ####|####|####|####|####|####|####|####|####|####|####|####|####|####|#### 97 | # 98 | # make sure the folder that we want to backup actually exists 99 | # 100 | 101 | cd "$HOME/Library/Containers" 102 | 103 | if [ ! -d "com.soulmen.ulysses3" ] 104 | then 105 | msg "No com.soulmen.ulysses3 found in $PWD" 106 | exit 0 107 | fi 108 | 109 | 110 | 111 | ####|####|####|####|####|####|####|####|####|####|####|####|####|####|#### 112 | # 113 | # This is where we actually create the backup of the folder 114 | # 115 | # The filename will be something like this: 116 | # 117 | # com.soulmen.ulysses3.2016-03-09--16.52.51.tar.xz 118 | # 119 | # for March 9th at 4:52pm 120 | 121 | if (( $+commands[xz] )) 122 | then 123 | 124 | ARCHIVE="com.soulmen.ulysses3.`timestamp`.tar.xz" 125 | 126 | tar \ 127 | --options='xz:compression-level=9' \ 128 | --xz \ 129 | --verbose \ 130 | -c \ 131 | -f "$ARCHIVE" \ 132 | "com.soulmen.ulysses3" 133 | 134 | else 135 | 136 | ARCHIVE="com.soulmen.ulysses3.`timestamp`.tar.bz2" 137 | 138 | tar \ 139 | --verbose \ 140 | -y \ 141 | -c \ 142 | -f "$ARCHIVE" \ 143 | "com.soulmen.ulysses3" 144 | 145 | fi 146 | 147 | 148 | EXIT="$?" 149 | 150 | if [ "$EXIT" != "0" ] 151 | then 152 | msg "tar failed (\$EXIT = $EXIT)" 153 | 154 | exit 0 155 | fi 156 | 157 | 158 | ####|####|####|####|####|####|####|####|####|####|####|####|####|####|#### 159 | ## 160 | ## Move the .tar.xz pr .tar.bz2 file to the 'ARCHIVE_DIR' 161 | ## which is defined above 162 | ## 163 | 164 | 165 | [[ ! -d "$ARCHIVE_DIR" ]] && mkdir -p "$ARCHIVE_DIR" 166 | 167 | mv "$ARCHIVE" "$ARCHIVE_DIR" 2>&1 | tee -a "$LOG" 168 | 169 | EXIT="$?" 170 | 171 | if [ "$EXIT" = "0" ] 172 | then 173 | msg "Ran Successfully" 174 | else 175 | msg "FAILED Created $ARCHIVE but failed to move it to $ARCHIVE_DIR" 176 | fi 177 | 178 | 179 | 180 | exit 0 181 | #EOF 182 | 183 | TimeOutAbortsMacro 184 | 185 | TrimResults 186 | 187 | TrimResultsNew 188 | 189 | UseText 190 | 191 | 192 | 193 | CreationDate 194 | 480060183.58307898 195 | IsActive 196 | 197 | ModificationDate 198 | 482322360.98100501 199 | Name 200 | Backup Ulysses on Quit 201 | Triggers 202 | 203 | 204 | Application 205 | 206 | BundleIdentifier 207 | com.soulmen.ulysses3 208 | Name 209 | Ulysses 210 | NewFile 211 | /Applications/Ulysses.app 212 | 213 | FireType2 214 | Quit 215 | MacroTriggerType 216 | Application 217 | RepeatTime 218 | 60 219 | Target 220 | Specific 221 | 222 | 223 | UID 224 | D5F8DF7B-4E68-4859-B2B2-BCA5D1455C81 225 | 226 | 227 | Name 228 | Global Macro Group 229 | ToggleMacroUID 230 | 4948A9C1-5CD3-4AA1-A25D-9D29C5471ED8 231 | UID 232 | DA8512F7-F323-46B1-8319-752E0495CFD0 233 | 234 | 235 | 236 | -------------------------------------------------------------------------------- /Backup-Ulysses-on-Quit.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tjluoma/backup-ulysses/61b6d2b7cffc7f682b2b7826f5ba6c2ff5b3b54b/Backup-Ulysses-on-Quit.jpg -------------------------------------------------------------------------------- /Backup-Ulysses-on-Quit.kmmacros: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Activate 7 | Normal 8 | CreationDate 9 | 459387347.72605699 10 | IsActive 11 | 12 | Macros 13 | 14 | 15 | Actions 16 | 17 | 18 | DisplayKind 19 | Briefly 20 | IncludeStdErr 21 | 22 | IsActive 23 | 24 | IsDisclosed 25 | 26 | MacroActionType 27 | ExecuteShellScript 28 | Path 29 | /usr/local/scripts/backup-ulysses.sh 30 | Text 31 | 32 | TimeOutAbortsMacro 33 | 34 | TrimResults 35 | 36 | TrimResultsNew 37 | 38 | UseText 39 | 40 | 41 | 42 | CreationDate 43 | 0.0 44 | IsActive 45 | 46 | ModificationDate 47 | 479846975.57548499 48 | Name 49 | Backup Ulysses on Quit 50 | Triggers 51 | 52 | 53 | Application 54 | 55 | BundleIdentifier 56 | com.soulmen.ulysses3 57 | Name 58 | Ulysses 59 | NewFile 60 | /Applications/Ulysses.app 61 | 62 | FireType2 63 | Quit 64 | MacroTriggerType 65 | Application 66 | RepeatTime 67 | 60 68 | Target 69 | Specific 70 | 71 | 72 | UID 73 | D5F8DF7B-4E68-4859-B2B2-BCA5D1455C81 74 | 75 | 76 | Name 77 | Global Macro Group 78 | ToggleMacroUID 79 | 4948A9C1-5CD3-4AA1-A25D-9D29C5471ED8 80 | UID 81 | DA8512F7-F323-46B1-8319-752E0495CFD0 82 | 83 | 84 | 85 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # backup-ulysses 2 | 3 | Backup your entire Ulysses preferences folder (which includes your sheets, preferences, etc) 4 | 5 | 6 | 7 | ## Simpler Options (added 2016-04-14) 8 | 9 | 10 | `backup-ulysses-simpler.sh` and `Backup Ulysses on Quit (all in one).kmmacros` have been added to the repo. 11 | 12 | `Backup Ulysses on Quit (all in one).kmmacros` is a Keyboard Maestro macro that _already_ has the script `backup-ulysses-simpler.sh` embedded in it. 13 | 14 | Assuming you already have Keyboard Maestro installed, all you need to do is double-click on `Backup Ulysses on Quit (all in one).kmmacros` and it will be imported into your Keyboard Maestro setup. 15 | 16 | Every time the Ulysses app quits, the script will run, and a backup will be placed in ~/Dropbox/Backups/Ulysses. 17 | 18 | If you want it saved to a different location, all you have to do is edit the line 19 | 20 | `ARCHIVE_DIR="$HOME/Dropbox/Backups/Ulysses/"` 21 | 22 | in the script. 23 | 24 | (`$HOME` refers to your Mac OS X home directory, which is usually something like /Users/JSmith/ or /Users/JohnSmith/) 25 | 26 | 27 | ## Original Option 28 | 29 | 30 | Will use [dropbox_uploader.sh](https://github.com/andreafabrizi/Dropbox-Uploader/blob/master/dropbox_uploader.sh) if found, but can easily be used without it (see comments in script). 31 | 32 | Upon seeing this script, a Ulysses customer support representative stated to me: 33 | 34 | > It sounds like the only thing that can harm your texts now is a zombie apocalypse at the 35 | > Dropbox headquarters or the heat death of the universe. 36 | 37 | (Warning: Usual disclaimers apply, use at your own risk, etc etc.) 38 | 39 | ## How to use 40 | 41 | The easiest way to use this is to set up a [Keyboard Maestro](http://www.keyboardmaestro.com/main/) macro which runs every time [Ulysses](http://www.ulyssesapp.com/) quits, like so: 42 | 43 | ![](Backup-Ulysses-on-Quit.jpg) 44 | 45 | You can download and use 46 | [my Keyboard Maestro macro](https://raw.githubusercontent.com/tjluoma/backup-ulysses/master/Backup-Ulysses-on-Quit.kmmacros) 47 | if you wish, just be sure to change `/usr/local/scripts/backup-ulysses.sh` to the appropriate path on your Mac. 48 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /backup-ulysses-simpler.sh: -------------------------------------------------------------------------------- 1 | #!/bin/zsh -f 2 | # Purpose: Make extra Ulysses backups because you're paranoid. No I'm not. Yes you are. Ok, yeah, that's fair. 3 | # 4 | # 5 | # I sent an earlier version of this to the Ulysses developers, and was told: 6 | # "It sounds like the only thing that can harm your texts now is a zombie apocalypse at 7 | # the Dropbox headquarters or the heat death of the universe." 8 | # 9 | # 10 | # 11 | # From: Timothy J. Luoma 12 | # Mail: luomat at gmail dot com 13 | # Date: 2016-03-09 14 | 15 | 16 | # This is where the archives will be saved when finishes 17 | # it will be created if it does not exist 18 | ARCHIVE_DIR="$HOME/Dropbox/Backups/Ulysses/" 19 | 20 | 21 | ####|####|####|####|####|####|####|####|####|####|####|####|####|####|#### 22 | # 23 | # You should not need to change anything below this line, 24 | # although you are welcome to if you know what you are doing. 25 | # 26 | ####|####|####|####|####|####|####|####|####|####|####|####|####|####|#### 27 | 28 | 29 | # short name of this file without path or extension 30 | NAME="backup-ulysses" 31 | 32 | if [ -e "$HOME/.path" ] 33 | then 34 | source "$HOME/.path" 35 | else 36 | PATH='/usr/local/scripts:/usr/local/bin:/usr/bin:/usr/sbin:/sbin:/bin' 37 | fi 38 | 39 | zmodload zsh/datetime 40 | 41 | TIME=`strftime "%Y-%m-%d--%H.%M.%S" "$EPOCHSECONDS"` 42 | 43 | function timestamp { strftime "%Y-%m-%d--%H.%M.%S" "$EPOCHSECONDS" } 44 | 45 | LOG="$HOME/Library/Logs/$NAME.log" 46 | 47 | function msg { 48 | 49 | echo "$NAME: $@" | tee -a "$LOG" 50 | 51 | # If growlnotify is installed in $PATH 52 | # use it to report messages 53 | if (( $+commands[growlnotify] )) 54 | then 55 | 56 | growlnotify \ 57 | --appIcon "Ulysses" \ 58 | --identifier "$NAME" \ 59 | --message "$@" \ 60 | --title "$NAME" 61 | fi 62 | 63 | } 64 | 65 | 66 | ####|####|####|####|####|####|####|####|####|####|####|####|####|####|#### 67 | # 68 | # make sure the folder that we want to backup actually exists 69 | # 70 | 71 | cd "$HOME/Library/Containers" 72 | 73 | if [ ! -d "com.soulmen.ulysses3" ] 74 | then 75 | msg "No com.soulmen.ulysses3 found in $PWD" 76 | exit 0 77 | fi 78 | 79 | 80 | 81 | ####|####|####|####|####|####|####|####|####|####|####|####|####|####|#### 82 | # 83 | # This is where we actually create the backup of the folder 84 | # 85 | # The filename will be something like this: 86 | # 87 | # com.soulmen.ulysses3.2016-03-09--16.52.51.tar.xz 88 | # 89 | # for March 9th at 4:52pm 90 | 91 | if (( $+commands[xz] )) 92 | then 93 | 94 | ARCHIVE="com.soulmen.ulysses3.`timestamp`.tar.xz" 95 | 96 | tar \ 97 | --options='xz:compression-level=9' \ 98 | --xz \ 99 | --verbose \ 100 | -c \ 101 | -f "$ARCHIVE" \ 102 | "com.soulmen.ulysses3" 103 | 104 | else 105 | 106 | ARCHIVE="com.soulmen.ulysses3.`timestamp`.tar.bz2" 107 | 108 | tar \ 109 | --verbose \ 110 | -y \ 111 | -c \ 112 | -f "$ARCHIVE" \ 113 | "com.soulmen.ulysses3" 114 | 115 | fi 116 | 117 | 118 | EXIT="$?" 119 | 120 | if [ "$EXIT" != "0" ] 121 | then 122 | msg "tar failed (\$EXIT = $EXIT)" 123 | 124 | exit 0 125 | fi 126 | 127 | 128 | ####|####|####|####|####|####|####|####|####|####|####|####|####|####|#### 129 | ## 130 | ## Move the .tar.xz pr .tar.bz2 file to the 'ARCHIVE_DIR' 131 | ## which is defined above 132 | ## 133 | 134 | 135 | [[ ! -d "$ARCHIVE_DIR" ]] && mkdir -p "$ARCHIVE_DIR" 136 | 137 | mv "$ARCHIVE" "$ARCHIVE_DIR" 2>&1 | tee -a "$LOG" 138 | 139 | EXIT="$?" 140 | 141 | if [ "$EXIT" = "0" ] 142 | then 143 | msg "Saved $ARCHIVE to $ARCHIVE_DIR" 144 | else 145 | msg "Created $ARCHIVE but failed to move it to $ARCHIVE_DIR" 146 | fi 147 | 148 | 149 | 150 | exit 0 151 | #EOF 152 | -------------------------------------------------------------------------------- /backup-ulysses.sh: -------------------------------------------------------------------------------- 1 | #!/bin/zsh -f 2 | # Purpose: Make extra Ulysses backups because you're paranoid. No I'm not. Yes you are. Ok, yeah, that's fair. 3 | # 4 | # From: Timothy J. Luoma 5 | # Mail: luomat at gmail dot com 6 | # Date: 2016-03-09 7 | 8 | 9 | # this is the directory where backup files will be moved _to_ after they are created 10 | # You will almost certainly want to change this 11 | ARCHIVE_DIR='/Volumes/Data/Backups/Ulysses/' 12 | 13 | ## If you want to just move the backup to your Dropbox folder, 14 | ## just uncomment the next line and set it to the proper path 15 | 16 | # ARCHIVE_DIR=/path/to/Dropbox/Backups/Ulysses/ 17 | 18 | 19 | ####|####|####|####|####|####|####|####|####|####|####|####|####|####|#### 20 | # 21 | # if 'dropbox_uploader.sh' exists, use it to upload a copy to 22 | # a folder in Dropbox. In my case the folder name is 23 | # 24 | # ~/Dropbox/NoSync/Ulysses-Backups/ 25 | # 26 | # but for dropbox_uploader.sh we just need the '/NoSync/Ulysses-Backups/' part 27 | 28 | DROPBOX_DIR='/NoSync/Ulysses-Backups/' 29 | 30 | 31 | 32 | 33 | ####|####|####|####|####|####|####|####|####|####|####|####|####|####|#### 34 | # 35 | # You should not need to change anything below this line, 36 | # although you are welcome to if you know what you are doing. 37 | # 38 | ####|####|####|####|####|####|####|####|####|####|####|####|####|####|#### 39 | 40 | 41 | # short name of this file without path or extension 42 | NAME="$0:t:r" 43 | 44 | if [ -e "$HOME/.path" ] 45 | then 46 | source "$HOME/.path" 47 | else 48 | PATH='/usr/local/scripts:/usr/local/bin:/usr/bin:/usr/sbin:/sbin:/bin' 49 | fi 50 | 51 | zmodload zsh/datetime 52 | 53 | TIME=`strftime "%Y-%m-%d--%H.%M.%S" "$EPOCHSECONDS"` 54 | 55 | function timestamp { strftime "%Y-%m-%d--%H.%M.%S" "$EPOCHSECONDS" } 56 | 57 | LOG="$HOME/Library/Logs/$NAME.log" 58 | 59 | function msg { 60 | 61 | echo "$NAME: $@" | tee -a "$LOG" 62 | 63 | if (( $+commands[po.sh] )) 64 | then 65 | 66 | po.sh "$NAME: $@" 67 | 68 | fi 69 | } 70 | 71 | 72 | ####|####|####|####|####|####|####|####|####|####|####|####|####|####|#### 73 | # 74 | # make sure the folder that we want to backup actually exists 75 | # 76 | 77 | cd "$HOME/Library/Containers" 78 | 79 | if [ ! -d "com.soulmen.ulysses3" ] 80 | then 81 | msg "No com.soulmen.ulysses3 found in $PWD" 82 | exit 0 83 | fi 84 | 85 | 86 | 87 | ####|####|####|####|####|####|####|####|####|####|####|####|####|####|#### 88 | # 89 | # This is where we actually create the backup of the folder 90 | # 91 | # The filename will be something like this: 92 | # 93 | # com.soulmen.ulysses3.2016-03-09--16.52.51.tar.xz 94 | # 95 | # for March 9th at 4:52pm 96 | 97 | if (( $+commands[xz] )) 98 | then 99 | 100 | ARCHIVE="com.soulmen.ulysses3.`timestamp`.tar.xz" 101 | 102 | tar \ 103 | --options='xz:compression-level=9' \ 104 | --xz \ 105 | --verbose \ 106 | -c \ 107 | -f "$ARCHIVE" \ 108 | "com.soulmen.ulysses3" 109 | 110 | else 111 | 112 | ARCHIVE="com.soulmen.ulysses3.`timestamp`.tar.bz2" 113 | 114 | tar \ 115 | --verbose \ 116 | -y \ 117 | -c \ 118 | -f "$ARCHIVE" \ 119 | "com.soulmen.ulysses3" 120 | 121 | fi 122 | 123 | 124 | EXIT="$?" 125 | 126 | if [ "$EXIT" != "0" ] 127 | then 128 | msg "tar failed (\$EXIT = $EXIT)" 129 | 130 | exit 0 131 | fi 132 | 133 | ####|####|####|####|####|####|####|####|####|####|####|####|####|####|#### 134 | # 135 | # if 'dropbox_uploader.sh' exists, use it to upload a copy to 136 | # a folder in Dropbox. 137 | 138 | if (( $+commands[dropbox_uploader.sh] )) 139 | then 140 | 141 | dropbox_uploader.sh -s -p upload "$ARCHIVE" "$DROPBOX_DIR" 2>&1 | tee -a "$LOG" 142 | 143 | EXIT="$?" 144 | 145 | if [ "$EXIT" != "0" ] 146 | then 147 | msg "Failed to upload $ARCHIVE to Dropbox dir: $DROPBOX_DIR (EXIT = $EXIT)" 148 | fi 149 | fi 150 | 151 | ####|####|####|####|####|####|####|####|####|####|####|####|####|####|#### 152 | # 153 | # Move the .tar.xz file to the 'ARCHIVE_DIR' defined above 154 | # 155 | 156 | mv "$ARCHIVE" "$ARCHIVE_DIR" 2>&1 | tee -a "$LOG" 157 | 158 | EXIT="$?" 159 | 160 | if [ "$EXIT" = "0" ] 161 | then 162 | msg "Saved $ARCHIVE to $ARCHIVE_DIR" 163 | else 164 | msg "Created $ARCHIVE but failed to move it to $ARCHIVE_DIR" 165 | fi 166 | 167 | 168 | 169 | exit 0 170 | #EOF 171 | --------------------------------------------------------------------------------