Tuesday, July 23, 2013

Automated Deployment of Dart Packages on a Static Site


As of last night, I have one script to automate a portion of the deployment of the ICE Code Editor. Said script examines the contents of the dart2js-generated JavaScript for inclusion in an application cache manifest file. Tonight, I hope to automate another piece of the deployment—copying packages from the system cache into my GitHub pages repository.

Dart Pub is a pretty awesome tool. Among its qualities is that it will consolidate all installed packages in a single system (or user) directory, creating a symbolic link in the current application. This saves a bit of space and ensures that all package:XXX import statement will always resolve. The only downside is that symbolic links will not work on GitHub pages. Instead, I need the real packages.

As an Emacs user, I am quite good at copying the packages directory into Emacs for a quick conversion to a rm-the-symlinks and cp-the-system-packages. But I should be able to do better.

My first thought was to parse the output of ls -l packages/ with awk. The output is standard enough that I ought to be able to do it without too much work:
➜  ice-beta git:(gh-pages) ✗ ls -l packages 
total 24
lrwxrwxrwx 1 chris chris 64 Jul 23 18:47 browser -> /home/chris/.pub-cache/hosted/pub.dartlang.org/browser-0.6.5/lib
lrwxrwxrwx 1 chris chris 63 Jul 23 18:47 crypto -> /home/chris/.pub-cache/hosted/pub.dartlang.org/crypto-0.6.5/lib
lrwxrwxrwx 1 chris chris 72 Jul 23 18:47 ice_code_editor -> /home/chris/.pub-cache/hosted/pub.dartlang.org/ice_code_editor-0.0.9/lib
lrwxrwxrwx 1 chris chris 60 Jul 23 18:47 js -> /home/chris/.pub-cache/hosted/pub.dartlang.org/js-0.0.24/lib
lrwxrwxrwx 1 chris chris 61 Jul 23 18:47 meta -> /home/chris/.pub-cache/hosted/pub.dartlang.org/meta-0.6.5/lib
lrwxrwxrwx 1 chris chris 65 Jul 23 18:47 unittest -> /home/chris/.pub-cache/hosted/pub.dartlang.org/unittest-0.6.5/lib
But a bit of research turned up the readlink tool (I thought it was just a C command):
➜  ice-beta git:(gh-pages) ✗ readlink packages/browser 
/home/chris/.pub-cache/hosted/pub.dartlang.org/browser-0.6.5/lib
So my decache.sh script can iterate through each file in pub's packages directory, read the link, delete the exiting record, replacing it with the contents of the system cache:
#!/bin/sh

cd packages
for file in *; do
    link=`readlink $file`
    echo "$file ($link)"
    rm $file
    cp -r $link $file
done
And that works!

While I am at it, I ought to make the script idempotent. If I re-run it immediately after de-caching, it will copy the contents into the sub-directory, which is not quite right. All that is really needed is an if statement to exit with an error if the packages directory is already de-cached. Of course, if statements in Bash are a pain.

I think the only reason that Bash is not a more widely used language is because nobody can remember where to put the damn square brackets. It turns out that you put the damn square brackets around a boolean statement and before the semi-colon and then keyword:
#!/bin/sh

cd packages
for file in *; do
    if [ ! -L $file ]; then
        echo "Already decached."
        exit 1
    fi

    link=`readlink $file`
    echo "$file ($link)"
    rm $file
    cp -r $link $file
done
The -L test operator returns true if the argument is a symbolic link. If it is not—it the packages sub-directory is already de-cached, then I exit with non-zero status.

That does the trick:
➜  ice-beta git:(gh-pages) ✗ ./decache.sh             
browser (/home/chris/.pub-cache/hosted/pub.dartlang.org/browser-0.6.5/lib)
crypto (/home/chris/.pub-cache/hosted/pub.dartlang.org/crypto-0.6.5/lib)
ice_code_editor (/home/chris/.pub-cache/hosted/pub.dartlang.org/ice_code_editor-0.0.9/lib)
js (/home/chris/.pub-cache/hosted/pub.dartlang.org/js-0.0.24/lib)
meta (/home/chris/.pub-cache/hosted/pub.dartlang.org/meta-0.6.5/lib)
unittest (/home/chris/.pub-cache/hosted/pub.dartlang.org/unittest-0.6.5/lib)
➜  ice-beta git:(gh-pages) ✗ ./decache.sh             
Already decached.
➜  ice-beta git:(gh-pages) ✗ echo $?
1
That seems a good stopping point for tonight. Back to OSCON partying… er, preparation!


Day #821



No comments:

Post a Comment