E pur si muove

Preserving modification times in subversion

Wednesday, November 26, 2008

This is an oft requested feature apparently. But who know if and when it will be there. Usually things get done when someone has an itch to scratch, but given that no one has done this yet -but it's been requested for ages- it seems that it must either be really difficult or work arounds are easier. Turns out that in my case a work around is a lot easier.

I need to build various bits of software on various platforms and they can have local modifications. In the case of Python for example we strip out the bit where it looks up the modules search path in the registry on Windows (instead of clobbering a hopefully unique string in the resulting binary by a hopefully non-existing registry key like py2exe does IIRC - I'm surprised that hasn't blow up in anyones face yet but nevermind). Anyway, the point of this is that the natural format to store all of this in was in unpacked form in the revision control system, subversion in our case, so we can diff and merge as we like. Problem with this is that when we check out the source on a build host all timestamps are lost and for some projects this messes up the makefile logic and things break down horribly and randomly on the build hosts. I got tired of finding this out every time and adding yet another random touch to the build scripts so was looking for something better.

Turns out that this is actually suprisingly easy to do. I just store the timestamps of the unpacked tarball in a file, and call touch on all files first thing in our build script. These shell functions are not bomb-proof yet (it won't cope with spaces in filenames e.g.) but do the job for now:

create() {
    if [ -f .mtimes ]; then
        echo "E: .mtimes exists already!" >&2
        exit 1

    for file in $(find . -print); do
        mtime=$(stat --format=%y "$file")
        echo $file $mtime >> .mtimes

restore() {
    if [ ! -f .mtimes ]; then
        echo "E: No .mtimes file found!" >&2
        exit 1

    while read file mtime; do
        # This would be the simple GNU option, POSIX however...
        #touch --date="$mtime" $file
        CCYY=$(echo $mtime | cut -d- -f1)
        MM=$(echo $mtime | cut -d- -f2)
        DD=$(echo $mtime | cut -d- -f3 | cut -d' ' -f1)
        hh=$(echo $mtime | cut -d' ' -f2 | cut -d: -f1)
        mm=$(echo $mtime | cut -d' ' -f2 | cut -d: -f2)
        SS=$(echo $mtime | cut -d' ' -f2 | cut -d: -f3 | cut -d. -f1)
        touch -t $CCYY$MM$DD$hh$mm.$SS $file
    done < .mtimes

Note that stat is a GNU tool in the coreutils package, so create() will only work on a GNU-based system. restore() however should work on all POSIX compliant systems (and so far it seems to do so).

Only thing is that touching each and every file is a rather slow process... And before you ask, I actually do the timestamp conversion at creation time as that happens less often, but this seems clearer.

Subscribe to: Posts (Atom)