Bash Basics I: Building multiple Blender branches

In this introductory lesson I will share a simple shell script that I use when building both bf and freestyle branches. This is meant as merely a reference and not a definitive-one-and-only solution. As always this is geared towards new users looking for a simple beginners tutorial that is slightly more involved and practical than outputting “Hello World” into a text file.

Currently I am only interested in the main Blender Foundation (bf) branch and the freestyle branch so those are the only ones I will be covering. If you have been visiting my site for awhile you may be familiar with the Blender 2.5 Builds page where I share my builds. This shell script will not only update and build the branches it will also package them into tar.gz packages for distribution.

Create a new file and call it 'udpate.sh'. Add the shebang line.

#!/bin/bash

 

A shebang line consists of a number sign and an exclamation point character ("#!"), then optionally any amount of whitespace, then followed by the (absolute) path to the interpreter program that will provide the interpretation. The shebang is looked for and used when a script is invoked directly (as with a regular executable), and largely to the end of making scripts look and act similarly to regular executables, to the operating system and to the user.

The file can not yet be executed. Use chmod to add executable rights to all users.

$ chmod a+x update.sh

 

Attempt to execute the script.

$ ./update.sh 

 

If you see nothing you are in the clear, however you may see an error like the one below.

bash: ./update.sh: /bin/bash^M: bad interpreter: No such file or directory

 

This happens for a couple reasons: You are using a script that was initially created on Windows, or the editor you are using adds an end of line character of ^M that Linux does not recognize. Creating the file in vim is one way to avoid this, however you can install the 'tofrodos' package that contains the 'fromdos' command that will do all the work for you.

$ sudo apt-get install tofrodos
$ fromdos update.sh

 

In the home directory I have a folder called 'blender-svn' that contains all the sub directories for the source code and compiled output.

/blender-svn$ ls
blender  build  install  soc-2008-mxcurioni  update.sh

 

The folders called 'blender' and 'soc-2008-mxcurioni' contain the source code for each branch. The 'cd' command will navigate the script into the source directory of the bf branch and run the 'svn up' command to update the source code to the latest revision. When updates are complete the script navigates to the parent directory via 'cd ..'. It then repeats the process for the freestyle branch.

#update bf branch
cd blender/
svn up
declare -a INFO
INFO=($(`echo svn info`))
VERSION=${INFO[11]}
cd ..

#update freestyle branch
cd soc-2008-mxcurioni/
svn up
cd ..

 

In the bf branch block you will see 3 extra lines than in the freestyle branch block. I want to query the information of the build and store the result into an array. The first line explicitly declares an array called INFO. The next line takes the echoed output and stores it into the INFO array.

declare -a INFO
INFO=($(`echo svn info`))

 

Here is an example of what the output looks like:

/blender-svn/blender$ svn info
Path: .
URL: https://svn.blender.org/svnroot/bf-blender/trunk/blender
Repository Root: https://svn.blender.org/svnroot/bf-blender
Repository UUID: 954f8c5b-7b00-dc11-b283-0030488c597c
Revision: 27702
Node Kind: directory
Schedule: normal
Last Changed Author: nazgul
Last Changed Rev: 27702
Last Changed Date: 2010-03-23 18:09:33 -0400 (Tue, 23 Mar 2010)

 

The output is stored as indexes based on the spaces. To experiment with the individual indexes and the data being held in each one use the echo command. The index I am looking for is the one that contains the revision number.

$ echo ${INFO[0]}
Path
$ echo ${INFO[5]}
Root
$ echo ${INFO[9]}
954f8c5b-7b00-dc11-b283-0030488c597c

 

getting closer...

$ echo ${INFO[11]}
27702

 

There it is! Now that we know which array index the revision number is held in store that into a variable called REVISION.

REVISION=${INFO[11]}

 

There are other trickier methods (and maybe more efficient by someone else's standards) using various string parsing commands to obtain the revision number. However I will leave that research up to your own initiative to find.

Next we navigate back into each source directory and compile using scons.

#build bf branch
cd blender/
python scons/scons.py -j 2
cd ..

#build freestyle branch
cd soc-2008-mxcurioni/
python scons/scons.py -j 2
cd ..

 

If you do not use scons it will be up to you to modify the aforementioned cod blocks to work with your preferred compiling method. The '-j 2' option is specific to my laptop which has a dual core processor. If you have a single core you should omit this option. If your computer has multiple cores you may use a higher number to take advantage of them all.

This script will be able to take an argument. The argument will determine whether or not to package the recent builds. The argument to package the builds will be a simple value of “1”. You would pass an argument like so:

$ ./update.sh 1

 

Bash will automatically assign the first argument to a variable called $1. If there as a second argument then it would be stored in $2, and so on ($0 is the name of the script). There is no need to declare these variables.

Add an if-statement that queries for a string of “1”.

if [ "$1" == "1" ]; then

 

It is important here to surround both the $1 variable and the value of 1 in quotes to explicitly define them as string variables and not integers. If no argument was passed (meaning that I do not plan to package my builds) and the the if-statement was written without quotes there would be an error.

if [ $1 == 1 ]; then

 

Bash would kick an error because it can not compare a null value to an integer.

./update.sh: line 27: [: ==: unary operator expected

 

Moving on, store the path to my home directory in HOMEDIR.

	#copy to home
HOMEDIR="/home/ed/"

 

Store the string that will be the name of the bf branch folder. The string “bs.25-” is concatenated with the revision number and then concatenated with the “_Linux64” string.

	BFDIR="blender25-linux64-"$REVISION

 

Example output:

$ echo $BFDIR
blender25-linux64-27702

 

Copy the b2.5 folder to the home directory under the new name.

	cp -r install/b2.5/ $HOMEDIR$BFDIR

 

The compiled output is in the install folder. By default Blender compiles to a folder called 'Linux2'. However you can assign the location manually in the user-config.py folder using BF_INSTALLDIR.

/blender-svn/blender$ less user-config.py
BF_BUILDDIR = '../build/b2.5'
BF_INSTALLDIR = '../install/b2.5'

/blender-svn/soc-2008-mxcurioni$ less user-config.py
BF_BUILDDIR = '../build/f2.5'
BF_INSTALLDIR = '../install/f2.5'

 

To concatenate to string variables simply place the variable together without a space.

Example output:
$ echo $HOMEDIR$BFDIR
/home/ed/blender25-linux64-27702

 

Now I create the directory string for the freestyle build and copy that to the home directory with its new name.

	FSDIR="freestyle25-linux64-"$REVISION
cp -r install/f2.5/ $HOMEDIR$FSDIR

 

Navigate to the home directory.

	#move to home
cd $HOMEDIR

 

Its now time to package the directories for distribution. Create a new string variable called TARPKG which contains the name of what will be the output tar.gz file.

	#package both branches
TARPKG=$BFDIR".tar.gz"

 

Example output:

$ echo $TARPKG
blender25-linux64-27702.tar.gz

 

Use the 'tar' command to compress the directory. When using the tar command I normally use the -zcvf options. Details of what each does is listed below:

-z: filter the archive through gzip

-c: create a new archive

-v: verbosely list files processed

-f: use archive file or device ARCHIVE

 

It then creates a new tar.gz file using the contents of the directory stored in BFDIR and using the TARPKG string as the name.

	tar -zcvf $TARPKG $BFDIR

 

Remove the directory.

	rm -r $BFDIR"/"

Repeat the process for the freestyle branch and add 'fi' which terminates the if-statement. 

	TARPKG=$FSDIR".tar.gz"
tar -zcvf $TARPKG $FSDIR
rm -r $FSDIR"/"
fi

 

This part is optional, I like to add a little feedback when the entire process is complete.

echo "==================="
echo "----DONE----"
echo "==================="

 

The entire script:

#!/bin/bash

#update bf branch
cd blender/
svn up
declare -a INFO
INFO=($(`echo svn info`))
REVISION=${INFO[11]}
cd ..

#update freestyle branch
cd soc-2008-mxcurioni/
svn up
cd ..

#build bf branch
cd blender/
python scons/scons.py -j 2
cd ..

#build freestyle branch
cd soc-2008-mxcurioni/
python scons/scons.py -j 2
cd ..

if [ "$1" == "1" ]; then
#copy to home
HOMEDIR="/home/ed/"
BFDIR="blender25-linux64-"$REVISION
cp -r install/b2.5/ $HOMEDIR$BFDIR

FSDIR="freestyle25-linux64-"$REVISION
cp -r install/f2.5/ $HOMEDIR$FSDIR

#move to home
cd $HOMEDIR

#package both branches
TARPKG=$BFDIR".tar.gz"
tar -zcvf $TARPKG $BFDIR
rm -r $BFDIR"/"

TARPKG=$FSDIR".tar.gz"
tar -zcvf $TARPKG $FSDIR
rm -r $FSDIR"/"
fi

echo "==================="
echo "----DONE----"
echo "==================="

 

Now when I want to build and package all I need to is run the following command:

/blender-svn$ ./update.sh 1

 

Or if I just want to build without packaging:

/blender-svn$ ./update.sh

 

I hope this simple script helps new users in developing an understanding how shell scripts can automate repetitive tasks. Nothing I stated here is a concrete-only-way-possible solution. There is always other ways to approach tasks like this. I hope this gives you a starting point in writing your own shell scripts.

 

- Ed