jeudi 3 mars 2011

Two scripts for packaging a source tree from a local repository

I'm currently maintaining a double build of some software projects, on both Windows and Linux. Svn is of course a great help, because it allows me to easily switch from one machine to another and finding my whole tree unchanged (with a network-hosted repository, of course). I could also use some virtual machine, but I happen to have enough machines available: my main laptop recently switched (more on this later!), and I still have Windows at work and at home. So it is kind of easier to work on separate machines, not to mention that virtual machines can have some specific trouble that you need to deal with, instead of focusing on your project.

Part of the job is letting the users try your code, users that don't necessarily have access to the svn repository, nor have/use the same dev tools you do. So the classical way is to upload somewhere the whole tree as a single archive, and let them fool around with the app.

A well-known post from Joel Spolsky (here in french) covers a list of what is required in dev teams to achieve a high quality level. And point n°2 is "Can you make a build in one step?". Besides the build process, this implies an efficient source tree release step, and that's what I'll talk about here. But what exactly does "release" mean ?

"Releasing" means here going from a source tree, with all binaries compiled and unit-tests done, to a single file uploaded somewhere, so users can download it the next morning. We do not cover here producing the more complex "self-installing" files, (linux .deb or .rpm, or windows .msi or .exe), only a regular archive, containing the whole source tree along with the needed binaries.

You can find below the two scripts, one for windows (.bat), and one for Linux (.sh). The Linux version only needs regular tools that should be available on every distribution, while the Windows versions needs 2 additional tools, the archiver and the svn command-line client. Yes, I know what you think: if you are using svn, then you have the command-line svn client ! Well, no, not necessarily. On windows, I use TortoiseSvn,  really nice and with a perfect shell integration. This gui software is not just a wrapper around the svn command-line client, it has its own binaries. So you need to install some other svn client if you're a TortoiseSvn user (they are available here).
For the archiver, I highly recommend 7-zip: has both GUI and CLI, high performance, good documentation, shell integration... and LGPL'ed ! Can't wait to have it on Linux.

The interesting point is that the two scripts here are project-independent: you just drop them in your root folder... and there you go! A simple double-clic will generate an archive (.zip or .tar.gz), containing a copy of the local repository, with the name like:

XXXXX_YYYYMMDD-HHMM_win32.zip for the windows version
XXXXX_YYYYMMDD-HHMM_linux.tar.gz for the linux version
with XXXXX being the project name, simply extracted from the root folder name. You can also run them from the command-line.

The only tweaking you need to do is edit the additional "upload" scripts, where the ftp command is issued: this is the only part that can not be automatic, as there is no way to automatically determine what the host is.

Inside the scripts, nothing really complicated, but I'm quite happy to achieve some bash scripting as well as I am used to do with windows scripting. I miss the 'goto' command, but I must say that bash is more efficient, even though I am more used to cmd.exe. The scripts mainly do an svn export, add the binaries (that shoudn't be versioned), and compress the whole thing, renaming it with the current date/time. Has been tested on XP-SP3 and Ubuntu 10.10, let me know if you experience some trouble.

Download link

Linux/bash version:

#!/bin/bash
echo Packaging linux archive

curpath=$(pwd)
name=$(basename $curpath)
#echo name=$name

now=$(date +%Y%m%d-%H%M)
fn=${name}_${now}_linux

echo "step 1 : export tree to temp path"
svn export . $HOME/tmp/$name

echo "step 2 : add binaries (not versioned)"
cp bin/* /tmp/$name/bin
cp lib/* /tmp/$name/lib

echo "step 3 : archive and compress"
cd /tmp
tar cfz $curpath/$fn.tar.gz $name
cd $curpath

echo "step 4 : cleanup"
rm -r $HOME/tmp/$name

echo "step 5 : upload"
./upload.sh

echo "done, file $fn.tar.gz available !"
read -p "press a key"


Windows version

@echo off
title Packaging windows archive

:: here, little trick to get the folder's name
set curr_path=%cd%
call :sp %curr_path%
::echo name=%name%

set archiver=C:\Program Files\7-Zip\7z.exe
set svnclient=C:\Program Files\Subversion\bin\svn.exe

:: step 0 : make sure all the tools are available
if not exist "%archiver%" goto err1
if not exist "%svnclient%" goto err2

echo step 1 : export tree to temp path
svn export . %temp%\%name% --native-eol CRLF

echo step 2 : add binaries (not versioned)
copy bin %temp%\%name%\bin > nul
copy lib %temp%\%name%\lib > nul

echo step 3 : compress
set year=%date:~6,4%
set month=%date:~3,2%
set day=%date:~0,2%
set hour=%time:~0,2%
if /I %hour% LSS 10 set hour=0%hour:~1,1%
set mn=%time:~3,2%
set now=%year%%month%%day%-%hour%%mn%
echo now=%now%
pause
"%archiver%" a "%name%_%now%_win32.zip" %temp%\%name% > nul

echo step 4 : cleanup
del /Q /S %temp%\%name%\* >nul
rd /S /Q %temp%\%name%

echo step 5 : upload
call upload.bat

echo done, file %name%_%now%_win32.zip available !
pause
goto :eof
============================================================
:err1
echo FAIL: archiver %archiver% not present !
pause
goto :eof
============================================================
:err2
echo FAIL: svnclient %svnclient% not present !
pause
goto :eof
============================================================
:sp
::echo sp, arg1=%1
set name=%~n1
goto :eof
============================================================