Using deb packages to distribute code

    In this article I want to talk about how you can implement a deb package build system for some abstract project. There are several advantages in the distribution and deployment of package-based software:
    • Atomicity of the package (presentation of the product as a single file);
    • The presence of scripts pre / post installation / removal of software;
    • It is possible to specify dependencies for software.
    In addition, when deploying software based on packages, rather than based on SVN, you are guaranteed to be protected from problems with .svn folders .

    Project structure


    And so, consider some my-app web project under SVN control with the following file structure:
    / | -config
     | | -parameters.ini
     | -htdocs
     | | -index.php
     | -libs
     | -templates
    


    Package structure


    To build packages, we need a certain set of files and scripts, which we will place in the .package folder, which in turn will be added to the root of the project. The structure of this folder will look like this:
    /|-.structure
     | | -DEBIAN
     | | | -conffiles
     | | | -control
     | | | -postinst
     | | | -postrm
     | | | -preinst
     | | | -prerm
     | | | -templates
     | | -etc
     | | -var
     | | | -log
     | | | -www
     | -package.xml
     | -package.properties
    

    In fact, the .structure catalog is our future package. The DEBIAN subdirectory contains service files, which will be discussed below. All other directories completely repeat the directory hierarchy of the Debian Linux file system. The package.xml and package.properties files contain scripts and settings for creating packages using the Apache Ant utility . But first things first.

    Debian Directory


    The DEBIAN directory contains project settings files and pre / post install / uninstall scripts.

    The conffiles file contains a list of configuration files that should not be overwritten during installation: In our case, the project settings file will be indicated here. The control file contains general information about the package:
    /etc/my-app/parameters.ini




    Package: my-app
    Version: {{{VERSION}}}
    Section: user
    Priority: optional
    Architecture: all
    Installed-Size: 0
    Maintainer: Mikhail Krestjaninoff
    Depends: nginx, php5-common (>= 5.2), php5-cli
    Description: My application

    Separate attention in this file deserves points Version and Depends. We specifically indicate the constant {{{VERSION}}} as the package version, since in the future when assembling the package we will replace it with the current value. In the list of dependencies, we indicated only nginx and php, however, if your project uses any additional packages (for example php modules), you can explicitly list them, thereby reducing the risks of incorrect operation of the project when posting to the battle server.

    The preinst file contains a preinstallation script: In our case, no preliminary steps are required; therefore, the file is empty. The postinst file contains a post-installation script. In this case, the script will set permissions, configure the config using the debconf utility
    #!/bin/sh



    and create directories for temporary files:
    #!/bin/sh
    if [ configure = "$1" ]; then
        # Set permissions
        chown -R www-data:www-data /etc/my-app/
        chmod -R 0664 /etc/my-app/
        chown -R www-data:www-data /var/www/my-app/
        chmod -R 0664 /var/www/my-app/
        chown -R www-data:www-data /var/log/my-app/
        chmod -R 0664 /var/log/my-app/
        # Set up configuration file
        . /usr/share/debconf/confmodule
        db_input critical db/dsn || true
        db_go
        db_fset db/dsn seen false || true
        db_get db/dsn || true
        DSN=$RET
        DSN=`echo "$DSN" | sed 's/\//\\\\\//g'`;
        sed -i s/{{DSN}}/$DSN/ /etc/my-app/parameters.ini
        # Create directories for temporary files
        CACHE_DIR="/var/www/my-app/templates/cache"
        COMPILED_DIR="/var/www/my-app/templates/compiled"
        if [ ! -d $CACHE_DIR ]
        then
            mkdir -p $CACHE_DIR
            chown -R www-data:www-data $CACHE_DIR
            chmod -R 0664 $CACHE_DIR
        fi
        if [ ! -d $COMPILED_DIR ]
        then
            mkdir -p $COMPILED_DIR
            chown -R www-data:www-data $COMPILED_DIR
            chmod -R 0664 $COMPILED_DIR
        fi
    fi
    

    If necessary, scripts for creating a project database can also be added to this file. With updating the database, the task is somewhat more complicated. However, you can try to partially allow it by storing 2 sql files in the project: with a full set of commands for reproducing the structure / data (initial installation) and changes from the previous release (for updating).

    The prerm file contains a preinstallation script. In this case, the script will delete directories for temporary files:
    #!/bin/sh
    if [ remove == "$1" -o purge == "$1" ];
    then
        # Remove directories for temporary files
        CACHE_DIR="/var/www/my-app/templates/cache"
        if [ -e $CACHE_DIR ]; then
            rm -rf $CACHE_DIR
        fi
        COMPILED_DIR="/var/www/my-app/templates/compiled"
        if [ -e $COMPILED_DIR ]; then
            rm -rf $COMPILED_DIR
        fi
    fi
    


    The templates file contains field templates for the debconf utility :
    Template: db/dsn
    Type: string
    Default: postgres://user@passwd:localhost/my-app
    Description: Database Source Name. Example: postgres://user@passwd:localhost/my-app
    

    You can read more about the contents of the DEBIAN directory on opennet or in the official documentation .

    Package build scripts


    Now, in order to create a full-fledged package based on our project, it remains for us to fill out the file structure of the package (file system with the root in the .structure directory with data). To do this, you will have to create a small set of scripts that copy the necessary data from the project file system to the package file system. I used Apache Ant for this purpose, as a result of which I got the package.xml and package.properties files .

    The package.properties file contains the settings for building the package:
    package.name=my-app
    package.version=1.0.0
    

    The main build script is contained in the package.xml file:



      
      
      
      
      

      
      
        
        
      


      
      
        
        
      


      
      

        
          
            
            
        

        


        
        
          
            
            
          

        


        
        
          
            
            
          

        


      
        
          
            
            
          

        


        
        
          
            
            
            
            
          

        


      


      
      

        
        
          
        


        
        
          
        


        
        
          
        


        
        
          
        


      




    * This source code was highlighted with Source Code Highlighter.

    Package assembly


    And so, the creation of the .package directory is complete. Now we can commit it to SVN along with the rest of the project. When we need to build a package (for example, give a release / label for testing or putting it into battle), it will be enough to go to the .package directory and execute the command ant -f package.xml buildthat will create a new deb package for us in the .package / target directory , ready to use !

    Also popular now: