30

I was wondering if this was the best solution:

  • Put the .applescript files under version control
  • Create an installation script to compile the files with osacompile

But there is also the .scptd directory. Or I could put both .applescript and .scpt files under version control?

What is the best solution?

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
charlax
  • 25,125
  • 19
  • 60
  • 71
  • I would only put code in the repo, then code is The Truth and there is only versions of code to dispute, not also versions of compiled code that may disagree with source code. – fearmint Oct 04 '11 at 21:03
  • I'm not sure what you mean by version control. – epetousis Oct 16 '11 at 04:38
  • 1
    @charlax, after getting a few upvotes to confirm that this works for people other than me, I feel pretty confident in my answer. You should try implementing my answer. (selecting it even ;-) – Bruno Bronosky Aug 09 '13 at 19:08

4 Answers4

28

I love @DanielTrebbien's solution, but it is a little too complex for me to expect people to implement in order to use for my github project. A simpler option that just empowers you to see text changes in the diff is to tell the diff process to textconv with osadecompile.

Add to .gitattributes

*.scpt diff=scpt

Add to .git/config

[diff "scpt"]
  textconv = osadecompile
  binary=true

Here is sample diff from my AppleScript-droplet github project

$ git diff
--- a/AppleScript-droplet.app/Contents/Resources/Scripts/main.scpt
+++ b/AppleScript-droplet.app/Contents/Resources/Scripts/main.scpt
@@ -1,3 +1,3 @@
-on open filelist
-       ## Set useTerminal to true to run the script in a terminal
-       set useTerminal to true
+on open file_list
+       ## Set use_terminal to true to run the script in a terminal
+       set use_terminal to true

Big thanks to @DanielTrebbien for his answer that lead me to osadecompile.

Community
  • 1
  • 1
Bruno Bronosky
  • 66,273
  • 12
  • 162
  • 149
  • this works great for seeing changes, but doesn't help with merging. Unfortunately, you're still trying to merge binary files, which gets tricky. – Darrick Herwehe Nov 04 '15 at 22:13
  • 1
    @DarrickHerwehe, merging binaries is worse than tricky. It's impossible. What you'll have to do to merge is `osadecompile` both versions of the file and do a manual merge. For this I use `vimdiff` and when I get it looking right, I copy-pasta the text back into the AppleScript GUI. Definitely not awesome, but better than merging Photoshop binaries. – Bruno Bronosky Nov 10 '15 at 17:35
  • This solution would also be handy for Script Libraries. In this case, you don't need to handle the fact *.scptd bundles contain multiple files. Also, when you have a Script Library with an SDEF, you don't need to fix those horrible problems. Merging (normally, AppleScripts hardly need to be merged since most of the time it's a one mens show) has to be done manually without the aid of git. That would be an acceptable trade off. – doekman Apr 01 '17 at 13:17
17

Edit: The now is a "official" gitfilter to do this, called osagitfilter. It builds on this idea and fixes some quirks of osacompile...


If using git, you can use a filter driver to transparently (1) decompile SCPT files so that only the AppleScript source code is committed (called "cleaning" the binary SCPT) and (2) recompile back to SCPT when checking out (called "smudging" the AppleScript source).

First add the following shell script named git-ascr-filter to /usr/local/bin:

#!/bin/sh
if [ $# -ne 2 ]; then
    echo "Usage: $0 --clean/--smudge FILE">&2
    exit 1
else
    if [ "$1" = "--clean" ]; then
        osadecompile "$2" | sed 's/[[:space:]]*$//'
    elif [ "$1" = "--smudge" ]; then
        TMPFILE=`mktemp -t tempXXXXXX`
        if [ $? -ne 0 ]; then
            echo "Error: \`mktemp' failed to create a temporary file.">&2
            exit 3
        fi
        if ! mv "$TMPFILE" "$TMPFILE.scpt" ; then
            echo "Error: Failed to create a temporary SCPT file.">&2
            rm "$TMPFILE"
            exit 4
        fi
        TMPFILE="$TMPFILE.scpt"
        # Compile the AppleScript source on stdin.
        if ! osacompile -l AppleScript -o "$TMPFILE" ; then
            rm "$TMPFILE"
            exit 5
        fi
        cat "$TMPFILE" && rm "$TMPFILE"
    else
        echo "Error: Unknown mode '$1'">&2
        exit 2
    fi
fi

Make sure to chmod a+x the script.

Configure the 'ascr' filter by running:

git config filter.ascr.clean "git-ascr-filter --clean %f"
git config filter.ascr.smudge "git-ascr-filter --smudge %f"

Then add to .gitattributes:

*.scpt filter=ascr

Now whenever you make a change to a SCPT file and git add it, the decompiled AppleScript source will be staged instead of the binary SCPT. Also, whenever you check out a SCPT file (which is really stored as an AppleScript blob in the repository), the SCPT file is re-created on disk.

doekman
  • 18,750
  • 20
  • 65
  • 86
Daniel Trebbien
  • 38,421
  • 18
  • 121
  • 193
  • Thanks for osadecompile lead. I came up with a different solution to the problem, but couldn't have done it without you. – Bruno Bronosky Mar 05 '13 at 18:43
  • 1
    I have a feeling this approach would avoid the issue that scpt files are not viewable in github, but I worry that anyone else who clones the repository needs to add this also. – studgeek Jan 26 '14 at 04:49
  • @studgeek: That is correct. The AppleScript source code would be viewable in GitHub and anyone who clones the repository would have to install the `git-ascr-filter` script and run the two `git config` commands. – Daniel Trebbien Mar 12 '14 at 13:36
  • Outstanding work. I created this script, followed the instructions for configuring my git repo, checked in the changes, pushed them to GitHub, and like magic, my AppleScript program showed up as text on GitHub (instead of binary as it was previously). – mhucka Jan 12 '16 at 04:05
  • Promising solution, but I don't get it to work :-) For some reason, git sees the AppleScript file as binary... The command `git-ascr-filter` works just fine, when used manually. I also added the filter global, and the gitattributes too. I use SourceTree and GitHub Desktop, but also tried command line. Any pointers how to debug? – doekman May 24 '16 at 11:58
  • @doekman Can you try adding a new compiled AppleScript via the command line (using `git add` to see if there is any console output)? Maybe there is a problem with staging AppleScripts using the filter driver once the SCPT was already committed as a binary. – Daniel Trebbien May 25 '16 at 11:06
  • @Daniel I created a new script, and used the console (`git add filename.scpt`) to add it, but there was no output... – doekman May 26 '16 at 09:03
  • @doekman It appears that git silently fails if the `git-ascr-filter` script is not in the path. Does `which git-ascr-filter` print anything? – Daniel Trebbien May 26 '16 at 13:51
  • It gives `/usr/local/bin/git-ascr-filter` as output (as expected). When I use `git-ascr-filter` on the command line, it just works as expected... – doekman May 26 '16 at 15:20
  • @doekman I was able to reproduce the issue that you are seeing in SourceTree Version 2.3 (the latest version as of this writing). TIL Mac apps have their own PATH that is not the same as the terminal PATH: https://jira.atlassian.com/browse/SRCTREE-3583 In effect, the `git-ascr-filter` script is not being seen by the app. One work-around that I have tested with SourceTree is to install git via Homebrew and then tell SourceTree to use Homebrew git (go to **SourceTree > Preferences…** In the "Git" section, click the "Use System Git" button and select `/usr/local/bin/git`). – Daniel Trebbien May 26 '16 at 20:56
  • @Daniel: that didn't work either. I'm now following a different path (I saved the AppleScript as text. An advantage: I can use any editor now). Thanks for the support! – doekman Jun 01 '16 at 15:09
  • I gave it another try. It works on the command line! GitHub Desktop shows the commits, so that's nice. In GitHub Desktop there is a problem: the program shows it's a binary, so no diff. And when committing, a binary is committed. Would be nice to get this working... – doekman Apr 01 '17 at 13:12
  • Is there also a way to put Script Bundles (scptd) files with an scripting dictionary (sdef) in git? When I do a `osadecompile`, I get the actual handler text in the applescript file (for example: `display dialog`), but when I use `osacompile` it gives an error message. When opening such a script file with TextMate, I get the raw code («event ...»), so it's possible. How to decompile/compile those scripts? – doekman Apr 04 '17 at 17:55
  • @doekman I am not sure. You might try asking a question on Stack Overflow or [Ask Different](http://apple.stackexchange.com). – Daniel Trebbien Apr 06 '17 at 11:53
  • 1
    I found out: TextMate uses it's own binary to decompile AppleScript. It's on GitHub: https://github.com/textmate/applescript.tmbundle/tree/master/Support/bin Still have to test if it's possible to create an scptd+sdef though... – doekman Apr 11 '17 at 12:41
  • 1
    @doekman I think that this is the source code for the binary: https://github.com/textmate/textmate/blob/master/Applications/decompile_as/src/decompile_as.mm – Daniel Trebbien Apr 11 '17 at 13:45
  • @DanielTrebbien: Thanks for the source link, but I'm not an Xcode-guru. I posted my follow-up question here: http://stackoverflow.com/questions/43386718/how-to-compile-an-applescript-script-library-scptd-with-an-scripting-definitio – doekman Apr 13 '17 at 08:04
  • @DanielTrebbien: Do you mind if I edit your article, and link to [osagitfilter](https://github.com/doekman/osagitfilter/) project, written and maintained by me? I think it would be useful. – doekman Jan 30 '20 at 10:32
7

I always put the .applescript (plain text files) in version control (SVN). This way I can easily compare between different versions, and it is also quite easy if for multiusers. You can highlight the changes that has been made by other users. This is not possible with binary files, like compiled script files.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
dj bazzie wazzie
  • 3,472
  • 18
  • 23
  • Thanks! And then you compile it with `osacompile`? – charlax Dec 07 '11 at 21:46
  • 1
    If you're using xcode turn the 'save exec-only' flag on and the files are compiled at build time. For plain applescript files I keep my source files in svn and save it as compiled script when needed. if you think you still need osacompile (to load script objects from plain applescript files for instance) you can also use 'run script file theFile' command instead as long as the run handler returns itself (return me) at the end. – dj bazzie wazzie Dec 22 '11 at 13:46
2

I keep the plain text .applescript files in Git, and I have a simple Bash script that I run every time I want to make a build of the app, which takes care of compiling the AppleScript. Here's my script:

#!/usr/bin/env bash

APPNAME="My Awesome App"

# make sure we're in the right place
if [ ! -d ".git" ]; then
    echo "ERROR: This script must be run from the root of the repository."
    exit
fi

# clear out old build
rm -r dist/*
mkdir -p "dist/$APPNAME.app/"

# copy files
cp -r app/* "dist/$APPNAME.app/"

# compile all applescript
cd "dist/$APPNAME.app/Contents/Resources/Scripts/"
for f in *.applescript
do
    osacompile -o "`basename -s .applescript "$f"`.scpt" "$f"
    rm "$f"
done

This script assumes that you have your entire app (i.e. the Contents/ folder and everything in it) inside the folder app/ in the root of your Git repository. It copies everything over to a new copy of the app in dist/, then compiles all AppleScript files in the Contents/Resources/Scripts/ folder of the new copy.

To use this yourself, I recommend copying my script to bin/build.sh in the root of your repository, running chmod +x bin/build.sh to make it executable, and then just run ./bin/build.sh any time you want a new build of your app.

Hayden Schiff
  • 3,280
  • 19
  • 41