This is the mail archive of the ecos-patches@sources.redhat.com mailing list for the eCos project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Powerfull python script to generate packages/templates/targets


Hi,

I have written a program to generate ecos .epk packages. This is the synopsis:

./ecospkggen.py --help
usage:
    ecospkggen.py [options] -V VERSION PACKAGES
 Will result in PACKAGES being built separately, all having version VERSION.

    ecospkggen.py [options] -t TARGET -V VERSION PACKAGES
 Will result in a single package containing TARGET and all PACKAGES.

    ecospkggen.py [options] -t TARGET -T TEMPLATE -V VERSION PACKAGES
 Will result in a single package containing TARGET, TEMPLATE and all PACKAGES.

 All PACKAGES listed on the command line will be taken from 'current' and 
override versions given in TARGET or TEMPLATE.
 All packages listed in the TARGET and the TEMPLATE file will be included in 
the archive.


options:
  --version             show program's version number and exit
  -h, --help            show this help message and exit
  -RPATH, --repository=PATH
                        The path to the eCos repository
  -VVERSION, --version_number=VERSION
                        The version number of the generated packages
  -q, --quiet           don't print any messages to stdout
  -v, --verbose         make lots of noise
  -r, --recursive       Process packages recursively [default]
  -S, --single          Do not process packages recursively
  -LLICENCE_FILE, --licence=LICENCE_FILE
                        Specify the licence to add to the package.
  -tTARGET_NAME, --target=TARGET_NAME
                        Specify a target. This will result in a single package
                        which contains the target, its dependencies and all
                        specified packages.
  -TTEMPLATE_NAME, --template=TEMPLATE_NAME
                      Specify a template. This will result in a single package
                        which contains the template, its dependencies and all
                        specified packages.

It requires Python 2.3 for the argument parsing. I'd appreciate any test 
results from other people so I can improve its robustness. For example, only 
the first alias is used from the package description (which is fine for 99% 
of the packages).

If all goes well, you are able to specify the alias or the CYGPKG_... name on 
the commandline for PACKAGES

TODO : 
* replace the occurence of 'current' in the template .ect file with the actual 
version number.

Peter

PS: you can also have it from  
http://people.mech.kuleuven.ac.be/~psoetens/ecos/ecospkggen.py
-- 
------------------------------------------------------------------------
Peter Soetens                                      http://www.orocos.org
Katholieke Universiteit Leuven
Division Production Engineering,                      tel. +32 16 322773
Machine Design and Automation                         fax. +32 16 322987
Celestijnenlaan 300B                   peter.soetens@mech.kuleuven.ac.be
B-3001 Leuven Belgium                 http://www.mech.kuleuven.ac.be/pma
------------------------------------------------------------------------
#!/usr/bin/python
#
# A script to generate an .epk file from an existing package directory
# ecospkggen.py (c) 2003 Peter Soetens
#
# ***************************************************************************
# *                                                                         *
# *   This program is free software; you can redistribute it and/or modify  *
# *   it under the terms of the GNU General Public License as published by  *
# *   the Free Software Foundation; either version 2 of the License, or     *
# *   (at your option) any later version.                                   *
# *                                                                         *
# ***************************************************************************/
"""
File : ecospkggen.py
"""


import os
import re
import sys
import string

from optparse import OptionParser

class Generator:
    "Contains all user given info for generating the package(s)"

    def __init__(self, db):
        self.db = db
        self.packages = []
        self.bin_exts = ['gif','jpg','png', 'dia'] # Add your own binary files extensions here
        if verbose:
            self.opt_flag = ' -v '
        else:
            self.opt_flag = ''

    def store_packages(self, given):
        self.packages = []
        for i in given:
            if self.db.alias_dict.has_key(i):
                self.packages.append(self.db.alias_dict[i])
            else:
                self.packages.append(i)
    

    # Create an entire configuration package
    def create_config(self, target, template, all_packages, version, recursive):
        self.store_packages(all_packages)
        self.version  = version
        
        self.init_workdir()
        self.copy_tgt(target)
        self.copy_tmp(template)
        for i in self.packages:
            self.copy_pkg(i,"current", version, recursive)
        self.finish_workdir( target+"-"+template )

    ##
    # Create one target and all given packages
    ##
    def create_tgt(self, target, all_packages, version, recursive) :
        self.store_packages(all_packages)
        self.version  = version
        
        self.init_workdir()

        self.copy_tgt(target)
        for i in self.packages :
            self.copy_pkg(i,"current", version, recursive)
            
        self.finish_workdir( target )

    ##
    # Create one template and all given packages
    ##
    def create_tmp(self, template, all_packages, version, recursive) :
        self.store_packages(all_packages)
        self.version  = version
        
        self.init_workdir()

        self.copy_tmp(template)
        for i in self.packages :
            self.copy_pkg(i,"current", version, recursive)
            
        self.finish_workdir( template )

    ##
    # Creates a package from all packages located at/within root_package.
    # The 'current ' version number is renamed to <version>
    #
    # @param root_package The package to be distributed
    # @param version      The common new version number
    # @param recursive    Recursive processing
    ##
    def create_pkg(self, root_package, version, recursive) :
        self.store_packages( [root_package ])
        self.version  = version
        
        self.init_workdir()
        self.copy_pkg(root_package, "current", version, recursive)
        self.finish_workdir(root_package)

    def copy_tgt(self, target) :
        if ( not quiet ):
            print "Producing target "+ target
        
        for t in self.db.targets:
            if target == t.name or target == t.alias :
                t.print_output(self.pkgadd)
                # copy/add each leaf-package of this target
                for p in t.packages :
                    if p not in self.packages :
                        self.copy_pkg( p, "current", self.version, False ) #only copy if not listed on command line

    # This function copies the template itself *and* all packages associated with the
    # template
    def copy_tmp(self, template ):
        if ( not quiet ):
            print "Producing template "+ template

        # copy/rename template file
        os.makedirs(self.workdir+"/templates/"+template);
        os.system("cp "+self.opt_flag+" "+self.db.repos+"/templates/"+template+"/current.ect " + self.workdir +"/templates/"+template+"/"+self.version+".ect")

        self.template = Template(self.db.repos+"/templates/"+template+"/current.ect") 
        
        # copy/add each leaf-package with version number
        # command-line specified packages override the ones in the template
        for i,j in self.template.packages:
            #print "Trying "+i+" version "+j
            if i not in self.packages :
                if j == "current":
                    pkg_vers = self.version
                else:
                    pkg_vers = j
                self.copy_pkg(i, j, pkg_vers, False) #only copy if not listed on command line
                #print "ok"

    def copy_pkg(self, root_package, rep_version, pkg_version, recursive) :
        if ( not quiet ):
            print "Creating package "+ root_package+ " version "+pkg_version
        # copy/add each leaf-package
        for i in self.db.packages:
            if ( recursive and ( root_package in i.name or root_package in i.alias) ) or root_package == i.name or root_package == i.alias :
                i.print_output(self.pkgadd)
                targetdir = self.workdir + "/" + i.dir +"/"+ pkg_version
                os.makedirs(targetdir)
                os.system("cp -a " + self.db.repos + "/" + i.dir +"/"+rep_version+"/* "+ targetdir  )

    def init_workdir(self):
        self.workdir = "/tmp/ecospkggen." + str(os.getpid())
        os.mkdir(self.workdir)
        if licence != "":
            os.system("cp "+self.opt_flag+licence+" "+self.workdir+"/pkgadd.txt")
        # create new pkgadd.db file
        self.pkgadd = open( self.workdir+"/pkgadd.db",'w')

    def finish_workdir(self, base_name):
        self.pkgadd.close()
        # make the final distribution and remove/rename some files
        os.system("chmod -R +w " + self.workdir )
        # remove backup files etc
        os.system("find "+self.workdir+" -name \"*~\" -o  -name .svn -a -type d -o -name CVS -a -type d | xargs rm "+self.opt_flag+"-rf")
        for ext in self.bin_exts:
            os.system("find "+self.workdir+" -type f -name '*."+ ext + "' -exec mv {} {}.bin ';'")
        os.system("tar "+self.opt_flag+"-cz -f "+ self.db.repos + "/" +base_name+"-"+self.version+".epk -C " + self.workdir +" "+ string.join(os.listdir(self.workdir)) )
        os.system("rm "+self.opt_flag+"-rf "+self.workdir )


class EcosDB :
    "Our own db of found packages"

    def __init__(self, path= ".", file = "ecos.db") :
        self.rawtext = open( path +"/"+ file, 'r').read()
        self.repos   = path
        self.pkg_name_pat = re.compile(r"\s*package\s+(.+?)\s*{(.*?{.*?}.*?)}",re.S)
        self.tgt_name_pat = re.compile(r"\s*target\s+(.+?)\s*{(.*?{.*?}.*?{.*?}.*?)}",re.S)
        self.packages = [] # maybe use a dictionary instead of list
        self.targets  = [] # all targets in the db file
        self.alias_dict = {} # when an alias is given, we retrieve the packagename here.

    def parseDB(self):
        res = self.pkg_name_pat.findall(self.rawtext)
        for i in range(0,len(res)):
            tmppkg = Package( res[i][0], res[i][1] )
            self.packages.append(tmppkg)

        # build alias dictionary
        for i in self.packages:
            self.alias_dict[i.alias] = i.name

        res = self.tgt_name_pat.findall(self.rawtext)
        for i in range(0,len(res)):
            tmptgt = Target( res[i][0], res[i][1] )
            self.targets.append(tmptgt)

class Template:
    "A template defining packages and versions"
    def __init__(self, file):
        tf = open(file, 'r')
        tmp_pkg_pat = re.compile(r"package\s+(\w+)\s+(\w+)\s*;")
        self.raw_contents = tf.read()
        tf.close()
        self.packages = tmp_pkg_pat.findall(self.raw_contents) ## find all NAME, version pairs
        #print self.packages

    # Check if a given package is listed
    def have_pkg(self,name):
        for p in self.packages:
            if p[0].name == name:
                return True
        return False
            

class Target :
    "A target to be added to the pkgadd.db file"
    def __init__(self, _name, _contents) :
        self.name = _name
        self.raw_contents = _contents
        self.packages = []

        tgt_pkg_pat = re.compile(r"packages\s*{\s*(.*?)\s*}", re.S)
        tgt_alias_pat= re.compile(r"alias\s+{\s\"(.+?)\"\s+(.+?)\s*}")

        res = tgt_pkg_pat.search(_contents)
        self.packages = string.split( res.group(1), '\n')
        
        res = tgt_alias_pat.search(_contents)
        self.description = res.group(0)
        self.alias       = res.group(1)

    def print_output(self, _out=sys.stdout):
        _out.write("target " + self.name + " {")
        _out.write(self.raw_contents)
        _out.write("}\n")

    # Returns a list of all required packages for this target
    def get_packages():
        return self.packages

    # Check if a given package is listed
    def have_pkg(self,name):
        for p in self.packages:
            if p == name :
                return True
        return False
            

class Package :
    "The contents of an ecos package"
    def __init__(self, _name, _contents) :
        self.name = _name
        self.raw_contents = _contents

        # search patterns
        pkg_dir_pat  = re.compile(r"directory\s*(\S+)")
        pkg_alias_pat= re.compile(r"alias\s+{\s\"(.+?)\"\s+(.+?)\s*}")
        pkg_script_pat= re.compile(r"script\s+(\S+)\n")

        # extract info
        self.dir = pkg_dir_pat.search(_contents).group(1)
        self.description, self.alias = pkg_alias_pat.search(_contents).groups()
        self.alias = string.split(self.alias)[0] # XXX take only one alias into account
        self.script = pkg_script_pat.search(_contents).group(1)
    
    def print_output(self, _out=sys.stdout):
        _out.write("package " + self.name + " {")
        _out.write(self.raw_contents)
        _out.write("}\n")

# Main Script start

myusage = "\n    %prog [options] -V VERSION PACKAGES\n" \
          " Will result in PACKAGES being built separately, all having version VERSION.\n\n" \
          "    %prog [options] -t TARGET -V VERSION PACKAGES\n"\
          " Will result in a single package containing TARGET and all PACKAGES.\n\n" \
          "    %prog [options] -t TARGET -T TEMPLATE -V VERSION PACKAGES\n"\
          " Will result in a single package containing TARGET, TEMPLATE and all PACKAGES.\n" \
          "\n All PACKAGES listed on the command line will be taken from 'current' and override versions given in TARGET or TEMPLATE.\n" \
          " All packages listed in the TARGET and the TEMPLATE file will be included in the archive.\n"


parser = OptionParser( usage=myusage, version = "%prog 0.1")
parser.add_option("-R", "--repository", dest="path", default=".",
                  help="The path to the eCos repository [default='./']", metavar="PATH")
parser.add_option("-V", "--version_number", dest="version",
                  help="The version number of the generated packages", metavar="VERSION")
parser.add_option("-q", "--quiet",
                  action="store_true", dest="quiet", default=False,
                  help="don't print any messages to stdout")
parser.add_option("-v", "--verbose",
                  action="store_true", dest="verbose", 
                  help="make lots of noise")
parser.add_option("-r", "--recursive",
                  action="store_true", dest="recursive", default=True,
                  help="Process packages recursively [default]")
parser.add_option("-S", "--single",
                  action="store_false", dest="recursive",
                  help="Do not process packages recursively")
parser.add_option("-L", "--licence",
                  action="store", dest="licence", metavar="LICENCE_FILE", default="",
                  help="Specify the licence to add to the package.")
parser.add_option("-t", "--target",
                  action="store", dest="targetname", metavar="TARGET_NAME", default="",
                  help="Specify a target. This will result in a single package which " \
                  "contains the target, its dependencies and all specified packages. ")
parser.add_option("-T", "--template",
                  action="store", dest="templatename", metavar="TEMPLATE_NAME", default="",
                  help="Specify a template. This will result in a single package which " \
                  "contains the template, its dependencies and all specified packages. ")

# interpret given options
(options, args) = parser.parse_args()

version = options.version
recursive = options.recursive
verbose = options.verbose
quiet   = options.quiet
licence = options.licence
targetname = options.targetname
templatename = options.templatename


if len(args) == 0 and len(targetname) == 0 and len(templatename) ==0:
    parser.error ("Please specify the package name to generate ('alias' or XXXPKG_FULL_NAME)\n"\
                  " and/or a target and/or a template")

# start application
mydb = EcosDB( options.path )

mydb.parseDB()

mygen = Generator(mydb)

# in case no target specified, build separate packages
if len(targetname) == 0  and len(templatename) == 0:
    packages = args
    for i in packages :
        mygen.create_pkg(i, version, recursive)
    sys.exit()

if len(templatename) !=0 and len(targetname) != 0 :
    mygen.create_config(targetname, templatename, args, version, recursive)
else:
    if len(templatename) != 0:
        mygen.create_tmp(templatename, args, version, recursive)
        sys.exit()
    if len(targetname) != 0:
        mygen.create_tgt(targetname, args, version, recursive)
        sys.exit()

               
    

        
        
        
    


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]