What is template_product?

To simplify and somewhat automate the process of building ups products, we designed the template_product product, initially to be just a template you would copy somewhere by hand and customize. Later we added some simple scripts to automate the initial copy-and-customize process.

This page walks through a session of using template_product to create a new product called newprod. In actual use, one would of course use a product name that had something to do with the software one was releasing.

Using the template_product product

About this example

Here is an example of using the template_product product to make a product out of a C source code file. This example goes through the process of making a simple product and putting it into kits. Each step shows the process being done step by step on a terminal, with the information you type shown in bold, like

<hostname> echo hi 
hi
<hostname>

And when the example shows a file before and after editing, the areas changed will be highlighted in bold, like:

This is the file before

is changed to:

This is the file after

Getting the template_product product

We start by getting the template_product from the distribution node. If you already have template_product installed on your system, you can skip this step. These instructions will install it into main products area on your system.
<dcdsv0> setup upd
<dcdsv0> upd install template_product

cloning template_product

Next we will setup template_product, make a directory to hold our new product, called newprod, and clone the template product into this new area, with a script in template_product. Note that after unwinding files into your area, template_product asks you for the product name and initial version.
<dcdsv0> setup template_product
<dcdsv0> mkdir /tmp/newprod
<dcdsv0> cd /tmp/newprod
<dcdsv0> CloneTemplate
installing template product files in /tmp/newprod
/tmp/newprod/.
/tmp/newprod/.header
/tmp/newprod/.manifest
/tmp/newprod/ups
/tmp/newprod/ups/Version
/tmp/newprod/ups/INSTALL_NOTE
/tmp/newprod/ups/setup.csh
/tmp/newprod/ups/setup.sh
/tmp/newprod/ups/unsetup.csh
/tmp/newprod/ups/unsetup.sh
/tmp/newprod/ups/current
/tmp/newprod/ups/uncurrent
/tmp/newprod/ups/configure
/tmp/newprod/ups/unconfigure
/tmp/newprod/ups/action.table
/tmp/newprod/ups/INSTALL_NOTE.bak
/tmp/newprod/ups/Version.bak
/tmp/newprod/Makefile
/tmp/newprod/README
/tmp/newprod/test
/tmp/newprod/test/TestScript
/tmp/newprod/Makefile.bak
/tmp/newprod/README.bak
97 blocks
Product name? newprod
Product version? v1_0

The files listed above have now been copied into your new product directory, and the Makefile and ups table file have been customized for the product name and version. Note that even though it prints the full pathname to the created files, you are still sitting in the new product directory.

Adding your program sources to the template

Next we need to add our actual program we want in the product. For this example, we'll use a simple "hello world" C program. Since it is really difficult to show using an editor in a web page like this, I'm just using echo to create the file; for anything real you would want to use your favorite editor, or copy in the sources from sowmehere else.
<dcdsv0> mkdir src
<dcdsv0> cd src
<dcdsv0> echo "main() { printf(\"hello world\\n\"); }" > hello.c

Adding build instructions for your product

We'll add a target to a local Makefile in the src directory to install our program in a productd bin directory, and try it out. Once again, I'm just using echo to create the file; for anything real you would want to use your favorite editor, or copy in the Makefile from sowmehere else.
<dcdsv0> echo "install:; cp hello ../bin" > Makefile
<dcdsv0> mkdir ../bin 
<dcdsv0> make hello install
cc    -o hello hello.c 
cp hello ../bin

At this point, we should make a note that the two commands we just typed (cc and cp) are the build instructions for this product, which we'll be adding to the toplevel Makefile.

To arrange our Makefile so it knows what it needs to about our product, we make a few changes to the top page or so of the Makefile. The template looks something like the following (I've trimmed out the comments here so you can see it on one screen:


           SHELL=/bin/sh
             DIR=$(DEFAULT_DIR)
            PROD=newprod
     PRODUCT_DIR=MYPROD_DIR
            VERS=v1_0
       UPS_STYLE=new
          DEPEND=
  TABLE_FILE_DIR=ups
      TABLE_FILE=newprod.table
           CHAIN=development
      UPS_SUBDIR=ups
 ADDPRODUCT_HOST=fnkits
DISTRIBUTIONFILE=$(DEFAULT_DISTRIBFILE)
          FLAVOR=$(DEFAULT_NULL_FLAVOR)
              OS=GENERIC_UNIX
           QUALS=
            CUST=none 
OLD_ADDPRODUCT_HOST=dcdsv0
ADDDIRS =.
ADDFILES=
ADDEMPTY=
  ADDCMD=
   LOCAL=/usr/products/$(OS)$(CUST)/$(VERS)$(QUALS)
 DOCROOT=/afs/fnal/files/docs/products/$(PROD)

PREFIX=$(DEFAULT_PREFIX)

VERSIONFILES=Makefile README $(UPS_SUBDIR)/INSTALL_NOTE $(UPS_SUBDIR)/Version

#------------------------------------------------------------------

all: proddir_is_set build_prefix

clean:
        rm -f $(PREFIX) 

spotless:

test: proddir_is_set clean FORCE
        sh test/TestScript

sources from
Since we have a compiled program as our product, we need to make this a "flavored" product (which involves changing the lines for OS=,FLAVOR=,QUALS=,and CUST=), and we need to tell it the build instructions for our product. You can make these changes with whatever text editor you feel most comfortable with, the file should look like: 
           SHELL=/bin/sh
             DIR=$(DEFAULT_DIR)
            PROD=newprod
     PRODUCT_DIR=MYPROD_DIR
            VERS=v1_0
       UPS_STYLE=new
          DEPEND=
  TABLE_FILE_DIR=ups
      TABLE_FILE=newprod.table
           CHAIN=development
      UPS_SUBDIR=ups
 ADDPRODUCT_HOST=fnkits
          FLAVOR=$(DEFAULT_FLAVOR)
              OS=$(DEFAULT_OS)
           QUALS=
            CUST=$(DEFAULT_CUST) 
DISTRIBUTIONFILE=$(DEFAULT_DISTRIBFILE)

OLD_ADDPRODUCT_HOST=dcdsv0
ADDDIRS =.
ADDFILES=
ADDEMPTY=
  ADDCMD=
   LOCAL=/usr/products/$(OS)$(CUST)/$(VERS)$(QUALS)
 DOCROOT=/afs/fnal/files/docs/products/$(PROD)

PREFIX=$(DEFAULT_PREFIX)

VERSIONFILES=Makefile README $(UPS_SUBDIR)/INSTALL_NOTE $(UPS_SUBDIR)/Version

#------------------------------------------------------------------

all: proddir_is_set build_prefix 
        -mkdir bin
        cd src; make hello install
clean:
        rm -f $(PREFIX) 

spotless:
        rm -rf bin

test: proddir_is_set clean FORCE
        sh test/TestScript


(press here with your middle mouse button to see the before image on a separate screen)

validating the product

Now we can setup and test our product. 
<dcdsv0> setup newprod v1_0 -r `pwd` -M ups -m newprod.table
<dcdsv0> hello
hello world
<dcdsv0> unsetup newprod v1_0
<dcdsv0> hello
sh: hello: command not found

At this point we should change the test/TestScript file so that it tests our software. In this case, it would run our hello program and verify its output something like
#!/bin/sh
hello | "grep hello world" > /dev/null

which will exit with a successful exit code if hello prints "hello world", and fail otherwise.

Of course for a more complicated package, writing a good test script can be much more of a challenge, but try to at least add some basic test to make sure the product works.

Adding the product to the distribution node

Finally, if we are happy with this product, we can add it to the distribution node.
<dcdsv0> cd /tmp/newprod
<dcdsv0> make kits
rm -f /tmp/build-newprod-v1_0   
creating .manifest...
creating /tmp/newprod/../newprodSunOS+5v1_0.tar...
/tmp/newprod/../newprodSunOS+5v1_0.tar:
-rw-rw-r-- mengel/oss        0 Apr  1 11:19 1998 .header
-rw-rw-r-- mengel/oss      381 Apr  1 11:18 1998 .manifest
-rwxrwxr-x mengel/oss        5 Apr  1 11:07 1998 ./ups/Version
-rwxr-xr-x mengel/oss       55 Apr  1 11:07 1998 ./ups/INSTALL_NOTE
-rwxr-xr-x mengel/oss       43 Apr  1 11:07 1998 ./ups/setup.csh
-rwxr-xr-x mengel/oss       49 Apr  1 11:07 1998 ./ups/setup.sh
-rwxr-xr-x mengel/oss       43 Apr  1 11:07 1998 ./ups/unsetup.csh
-rwxr-xr-x mengel/oss       49 Apr  1 11:07 1998 ./ups/unsetup.sh
-rwxr-xr-x mengel/oss       15 Apr  1 11:07 1998 ./ups/current
-rwxr-xr-x mengel/oss       15 Apr  1 11:07 1998 ./ups/uncurrent
-rwxr-xr-x mengel/oss       15 Apr  1 11:07 1998 ./ups/configure
-rwxr-xr-x mengel/oss       15 Apr  1 11:07 1998 ./ups/unconfigure
-rwxr-xr-x mengel/oss      462 Apr  1 11:07 1998 ./ups/action.table
-rw-r--r-- mengel/oss    19858 Apr  1 11:14 1998 ./Makefile
-rw-r--r-- mengel/oss      190 Mar 30 17:21 1998 ./README
-rwxr-xr-x mengel/oss       87 Feb  5 16:32 1998 ./test/TestScript
-rw-rw-r-- mengel/oss       36 Apr  1 11:08 1998 ./src/hello.c
-rw-rw-r-- mengel/oss       26 Apr  1 11:09 1998 ./src/Makefile
-rwxrwxr-x mengel/oss     5380 Apr  1 11:09 1998 ./src/hello
-rwxrwxr-x mengel/oss     5380 Apr  1 11:09 1998 ./bin/hello

upd addproduct  -h fnkits  -T "/tmp/newprod/../newprodSunOS+5v1_0.tar"  \
 -M ups  -m action.table  -U ups  -f SunOS+5
upderr::upderr_syslog - successful ups declare newprod v1_0 \
 -T ftp://fnkits/ftp/products/newprod/v1_0/SunOS+5.tar -f SunOS+5 \
 -r /ftp/products/newprod/v1_0/SunOS+5 -z /ftp/upsdb -q "" \
 -M /ftp/upsdb/newprod -m v1_0.table
rm -f "/tmp/newprod/../newprodSunOS+5v1_0.tar"


And we can check that our product arrived there using upd list. 
<dcdsv0> upd list -a newprod
DATABASE=/ftp/upsdb 
        Product=newprod Version=v1_0    Flavor=SunOS+5
                Qualifiers=""   Chain=""


removing the product from the distribution node

And finally, we can remove the product from kits using the Makefile. 
<dcdsv0> make delproduct
upd delproduct -h fnkits -f SunOS+5  newprod v1_0
upderr::upderr_syslog - successful ups undeclare newprod v1_0 -f SunOS+5
<dcdsv0>

Adding the product source to a CVS repository

At this point, your product meets the standards for a product able to be checked into one of the lab CVS repositories, so that the revisions to the software can be tracked, and other folks who might need to can find it, get a particular version, and build it if they need to. You can add it like: 
<dcdsv0> setup osscvs
<dcdsv0> cvs import newprod v1_0 fermilab