Tarball as a remote git repo

I have two computers that do not share a network link, let’s say for simplicity sake that one of the machines is disconnected. I however do want to share my ever growing .emacs.d directory of emacs-lisp goodness.
Since the emacs configuration is actually code the obvious choice is to use source control management software to keep it in sync and among the newer SCMs I’m most familiar with Git.
Ideally I wanted to mimic the way git works but without a network, that is I wanted to be able to simply push my changes by issuing a simple enough command.
I came across this article which suggests to create a remote repo on a usb thumb drive and push and pull from it. It’s a very good idea and I’ve used it a couple of times.

However due to the relatively long period between my synchronization sessions I had to refer back to the article to remind myself of the steps, which after a few times made me want to script the process.

Having sat down to plan the automation it occurred to me that what I really wanted is to have the ability to dump to a tarball and update from a tarball as if that was a real repo, I didn’t want to be looking for that last thumb drive that I’ve created the ‘remote’ repo on.

So my requirements became simple: create a sync-object which I’ll be able to serialize and de-serialize myself in any way,  independently from the script and once de-serialized allow update an older repo from, and then dispose of the object. coming to think of it this is really like a ‘patch’ for a git repo.

Below is the script I came up with, the usage, I believe is quite straight forward:
to create an update object called dotemacs.osx.tgz I type the following:
git-tarball.sh push ~/dotemacs.osx.tgz

to update an existing git repo from dotemacs.osx.tgz I type:
git-tarball.sh pull ~/sync/dotemacs.osx.tgz

#!/bin/bash

execute_commands=1
trace_commands=1

function run_cmd ()
{
    cmd=$1

    if [ $trace_commands -eq 1 ]
        then
        echo "run: $cmd"
    fi

    if [ $execute_commands -eq 1 ]
        then
        $cmd
    fi
}
function push_to_repo ()
{

        if [ "$#" -lt 1 ]
            then die "1 arguments required, $# provided (type git remote for a list of repos)"
        fi
        run_cmd "git push $1"

        # trickery to find the repo dir based on the repo name
        # git remote shows a list that needs reducing there are two entries per repo
        # as follows
        # osxproxy      file:///foo/temp/remote_repo/dotemacs/ (fetch)
        # osxproxy      file:///foo/temp/remote_repo/dotemacs/ (push)
        # the grep -m 1 (max count) reduces the list to the first enrty
        # awk uses the second field where space is the field seperator
        # and finally sed removed the 'file://' prefix

        REPO_PATH=`git remote -v | grep -m 1 $1 | awk '{print $2}' | sed -e 's!file://!!1'`
        #remove the trailing slash
        REPO_NAME=`echo $REPO_PATH | sed -e 's!/$!!'`

        D_NAME=`dirname $REPO_PATH`
        B_NAME=`basename $REPO_PATH`
        PREV_DIR=`pwd`
        #tarball the bastard
        #first get out of the way any old copies
        REPO_DIR=`dirname $REPO_PATH`
        # echo "repo is $REPO_PATH and dir is $REPO_DIR"
        run_cmd "mv $REPO_NAME.tgz $REPO_NAME.renamed.at.$(date +%Y%m%d).tgz"

        run_cmd "cd $D_NAME"
        run_cmd "tar -czf ./$B_NAME.tgz ./$B_NAME"
        run_cmd "cd $PREV_DIR"

        #copy the file to the given path
        if [ "$#" -eq 2 ]
            then
            run_cmd "cp $REPO_NAME.tgz $2"
        fi

}
function pull_from_repo ()
{
        repo_name=$1
        run_cmd "git pull $repo_name master"
}
function create_repo ()
{
        REMOTE_REPO_NAME=$1

        if [ "$#" -eq 2 ]
        then
            REMOTE_REPO_DIR=$2
        else
            REMOTE_REPO_DIR="/mcradle/temp/remote_repo/$1_$(date +%Y%m%d)/"
            #echo "remote repo dir is $REMOTE_REPO_DIR"
        fi
        REMOTE_REPO_GIT_DIR="$REMOTE_REPO_DIR$REMOTE_REPO_NAME.git"
        run_cmd "mkdir $REMOTE_REPO_DIR"
        run_cmd "mkdir $REMOTE_REPO_GIT_DIR"
        run_cmd "git clone --local --bare --no-hardlinks . $REMOTE_REPO_GIT_DIR"
        run_cmd "git remote add $REMOTE_REPO_NAME $REMOTE_REPO_GIT_DIR"
        run_cmd "git push $REMOTE_REPO_NAME master"
}
function destory_repo ()
{
      REMOTE_REPO_NAME=$1
        run_cmd "git remote rm $REMOTE_REPO_NAME"
}
function push_to_tarball ()
{
    temp_dir="/tmp/$(basename $0).$$.tmp/"
    run_cmd "mkdir $temp_dir"
    #repo_name="autopush_$(date +%Y%m%d_%H%M)"
    repo_name="autopush_$(date +%Y%m%d)"
    copy_to=$1
    create_repo $repo_name $temp_dir
    push_to_repo $repo_name $copy_to
    destory_repo $repo_name
    run_cmd "rm -rf $temp_dir"
}
function pull_from_tarball ()
{
    #this expects a tarball as a paramter
    TARBALL=`readlink -f $1`
    temp_dir="/tmp/$(basename $0).$$.tmp/"
    prev_dir=`pwd`
    repo_name="autopull_$(date +%Y%m%d)"
    run_cmd "mkdir $temp_dir"
    run_cmd "cd $temp_dir"
    run_cmd "tar -xzf $TARBALL"
    repo_file=`readlink -f *.git`
    repo_file="file://$repo_file/"
    run_cmd "cd $prev_dir"
    run_cmd "git remote add $repo_name $repo_file"
    pull_from_repo $repo_name
    destory_repo $repo_name
    run_cmd "rm -rf $temp_dir"
}

if [ "$#" -lt 2 ]
then die "2 arguments required, $# provided."
fi

case "$1" in
push)

        push_to_tarball $2
        exit 0
        ;;

pull)
        pull_from_tarball $2
        exit 0
        ;;
*)
        echo "Usage: cd to the same dir where the .git directory is and type $0 {push new_tarball|pull existing_t\
arball}"
        exit 1
        ;;
esac

exit 0

comments:

  1. It needs a little bit of cleaning up, there are left-overs of experiments I did before landing on the design which makes it over complicated, need consistency when it comes to variable names (case for one)
  2. I don’t understand the effects of creating a new remote repo every sync and then destroying it, don’t know what it takes down with it and if git can handle many of these joining and leaving the repo.
  3. It works for me, and is fast and cool
  4. If had to do it all over I probably would have used python.
  5. This Is sunny side up, error checking could be useful
Advertisements
This entry was posted in open source, remote, source control, sync, Technology, Uncategorized and tagged , , , , , , . Bookmark the permalink.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s