#!/usr/bin/python # -*- coding: utf-8 -*- import sys import os import os.path import fnmatch import shutil import zipfile import stat import getopt from os.path import dirname import shutil from os import system import ConfigParser import StringIO import re import urllib2 DEBUG = False VERBOSE = False def message(msg): if VERBOSE: print msg def msgerror(msg): print "ERROR: ", msg def msgwarn(msg): print "WARNING: ", msg def debug(msg): if DEBUG: print "DEBUG: ", msg def acquire_file(name): files = list() folder = os.getcwd() while folder not in ( None, "", "/"): pathname = os.path.join(folder,name) if os.path.exists(pathname): files.append(pathname) folder = os.path.dirname(folder) return files def get_gvspkg_bin_folder(): files = list() files.append(os.path.join(os.environ['HOME'],".gvspkg.bin")) files.extend( acquire_file(".gvspkg.bin") ) files.extend( acquire_file("gvspkg.bin") ) debug( "gvspkg.bin = %s" % files[-1]) return files[-1] RWALL = stat.S_IWOTH | stat.S_IROTH | stat.S_IWUSR | stat.S_IRUSR | stat.S_IWGRP | stat.S_IRGRP VERSION = os.path.basename(os.getcwd()) GVSPKG_ROOT = get_gvspkg_bin_folder() def getVersion(): return VERSION def getPackagesRoot(): return GVSPKG_ROOT def getPool(): return getPackagesRoot() + "/pool" def getWeb(): return getPackagesRoot() + "/web" def getDist(): return getPackagesRoot() + "/dists/" +getVersion() def findfiles(root,filename): result=list() for wroot, dirs, files in os.walk(root): for f in files : if fnmatch.fnmatch(f,filename): result.append(wroot+"/"+f) result.sort() return result def mychmod(filename, perms): try: os.chmod(filename,perms) except Exception, ex: msgwarn("Can't change permissions of file '%s', error %s" % (filename, str(ex))) class Command: def __init__(self, args): self.args = args self.defaultoptions = None def load_options(self,filename): debug("loading option from %s" % filename) if not os.path.isfile(filename): debug("filename %s not found" % filename) return f=file(filename,"r") for line in f.readlines(): line = line.strip() if line=="" or line.startswith("#"): continue if line[-1] == "\n": line = line[:-1] n = line.find("=") if n<0 : continue cmd = line[:n] args = line[n+1:].strip() if args != "": self.defaultoptions[cmd] = self.defaultoptions.get(cmd,[]) + args.split(" ") debug("add options: %s=%r" % (cmd, args.split(" "))) f.close() def load_default_options(self): if self.defaultoptions != None: return self.defaultoptions = dict() options = list(); rootoptions = os.path.join(GVSPKG_ROOT,"options") if os.path.isfile(rootoptions): options.append(rootoptions) else: options.append("~/.gvspkg.bin/options") options.extend(acquire_file(".gvspkg.options")) options.extend(acquire_file("gvspkg.options")) for optionfile in options: self.load_options(optionfile) def getArgs(self,name): self.load_default_options() l = list() cmd = self.defaultoptions.get(name,None) if cmd != None: l.extend(cmd) l.extend(self.args[1:]) return l class PackageInfo(str): def __init__(self, filename): self._ini = None self.filename = filename[:-7] self.type = filename[-6:] s = os.path.basename(self.filename) s = s.split("-") #print "## PackageInfo ", repr(s) self.gvsig = s[0] + "-" + s[1] self.gvsig_version = s[2] self.code = s[3] try: if s[5] == 'SNAPSHOT': self.version = s[4] + "-" + s[5] self.build = s[6] self.status = s[7] self.os = s[8] self.arch = s[9] else: self.version = s[4] self.build = s[5] self.status = s[6] self.os = s[7] self.arch = s[8] except Exception: self.build = "0" self.status = "unknow" self.os = "all" self.arch = "all" try: self.build = int(self.build) except: pass def getCode(self): return self.code def getKey(self): return self.code+"-"+self.os+"-"+self.arch def getFullName(self): return os.path.basename(self.filename) def getFullVersion(self): return "%s-%06d" %(self.version,self.build) def getFilename(self): return self.filename + "." + self.type def hasPki(self): return os.path.isfile( self.getPkiFilename() ) def getPkiFilename(self): return self.filename + ".gvspki" def hasPkg(self): return os.path.isfile( self.getPkgFilename() ) def getPkgFilename(self): return self.filename + ".gvspkg" def getIniOption(self, name, default=None): section = "general" ini = self.getIni() if ini.has_option(section, name): x = ini.get(section, name) x = x.replace("\\:", ":") return x return default def getDescription(self): return self.getIniOption("description") def getName(self): return self.getIniOption("name") def getOwner(self): ini = self.getIni() if ini.has_option("general","owner"): return ini.get("general","owner") return None def getUrl(self): ini = self.getIni() if ini.has_option("general","download-url"): return ini.get("general","download-url") return None def getSourceUrl(self): ini = self.getIni() if ini.has_option("general","source-url"): return ini.get("general","source-url") return None def getDependencies(self): ini = self.getIni() if ini.has_option("general","dependencies"): return ini.get("general","dependencies") return None def getType(self): ini = self.getIni() if ini.has_option("general","type"): return ini.get("general","type") return None def getOfficial(self): ini = self.getIni() if ini.has_option("general","official"): return ini.get("general","official") return None def getIni(self): if self._ini != None: return self._ini index_path = self.getPkiFilename() outputfolder="/tmp/gvspkg.%s" % os.getpid() os.mkdir(outputfolder) os.system('unzip -q %s -d %s' % (index_path,outputfolder)) files = findfiles(outputfolder, "package.info") if len(files) != 1: msgerror("Can't locate package.info in pool '%s'." % (index_name)) return None package_info = files[0] self._ini = ConfigParser.ConfigParser() f = file(package_info,"r") ss = f.read() self._ini.readfp(StringIO.StringIO("[general]\n"+ss)) f.close() shutil.rmtree(outputfolder) return self._ini def __str__(self): return self.filename def __repr__(self): return "filename=%r:gvsig=%r:gvsig_version=%r:code=%r:version=%r:build=%r:status=%r" % ( self.filename, self.gvsig, self.gvsig_version, self.code, self.version, self.build, self.status ) class IndexList(list): def load(self, fname): message( "Loading index list from '%s'." % fname) f=file(fname,"r") lines=f.readlines() f.close() for line in lines: if line[-1] == "\n": line = line[:-1] info = PackageInfo(line) self.append(info) def save(self,fname): message( "Saving index list from '%s'." % fname) f=file(fname,"w") for index in self: f.write("%s\n" % index.getFilename()) f.close() mychmod(fname,RWALL) def build(self, pool, version): message( "Creating index list for version '%s' from '%s'" % (version, pool) ) packages=dict() for root, dirs, files in os.walk(pool): for f in files : fullpath = root+"/"+f info = PackageInfo(fullpath) if info.gvsig == "gvSIG-desktop" and info.gvsig_version == version : if packages.get(info.getKey()) == None: debug( "build: add " + repr(info)) packages[info.getKey()]=info else: oldinfo = packages[info.getKey()] debug("build: %s %s %s" % ( info.getKey(), oldinfo.getFullVersion(),info.getFullVersion())) if oldinfo.getFullVersion() "%s" package list'''% getVersion() # Title html += ''' ''' html += '''

%s package list

'''%(getVersion(),getVersion()) # sort allpackages for item in sorted(allpackages, key=getCode): html += '''\n \n'''%( "../../../web/" + item.getFullName() + ".html?height=400&width=600", item.getName(), item.version, item.os, item.getOfficial(), item.getType(), item.getOwner() ) html += """ \n
Package name Version O.S. Official Type Owner
%s %s %s %s %s %s
""" # generate index.html try: f=file(getDist()+"/web/index.html","w") f.write(html) f.close() except Exception, ex: raise ex def mkpkihtml(basepath, info): html=''' %s \n'''%(info.getIniOption("name"), getVersion()) html += ' \n'%info.getIniOption("name") html += ' \n \n \n \n \n \n'%("Name", info.getIniOption("name")) html += ' \n'%("Code", info.code) html += ' \n'%("Version", info.version) html += ' \n'%("State", info.getIniOption("state")) html += ' \n'%("Build", info.build) html += ' \n'%("Owner", info.getOwner()) #url = info.getUrl() url = info.getIniOption("download-url") if url != None: html += ' \n'%(url) else: html += ' \n' sourceUrl = info.getSourceUrl() if sourceUrl != None: html += ' \n'%(sourceUrl) else: html += " \n" html += ' \n'%("Dependencies", info.getDependencies().replace("\:",":")) html += ' \n'%("Type", info.getType()) html += ' \n'%("Official", info.getOfficial()) description = info.getDescription().replace("\\n", "
") description = description.replace("\:",":") html += ' \n'%("Description", description) html += """ \n
%s %s
%s %s
%s %s
%s %s
%s %s
%s %s
DownloadsBinaries
DownloadsBinaries
Sources
Sources
%s %s
%s %s
%s %s
%s %s
\n""" html += """ \n""" try: f = file(getWeb() + "/" + info.getFullName() + ".html","w") f.write(html) f.close() except Exception, ex: raise ex def show(args): cmd = Command(args) try: opts, args = getopt.getopt(cmd.getArgs("show"), "S", [ "verify"]) except getopt.GetoptError, err: # print help information and exit: print str(err) # will print something like "option -a not recognized" help(args) sys.exit(2) verify = False for opt, arg in opts: if opt in ("-V", "--verify"): verify = True else: assert False, "unhandled option %r" % opt index_name=args[0] message( "Show package.info from '%s'" % index_name) files = findfiles(getPool(), index_name) if len(files) != 1: msgerror("Can't locate package '%s' in pool '%s'." % (index_name, getPool())) return index_path = files[0] outputfolder="/tmp/gvspkg.%s" % os.getpid() os.mkdir(outputfolder) os.system('unzip -q %s -d %s' % (index_path,outputfolder)) files = findfiles(outputfolder, "package.info") if len(files) != 1: msgerror("Can't locate package.info in pool '%s'." % (index_name)) return package_info = files[0] f = file(package_info,"r") s = f.read() f.close() print s if verify: verify_sign(package_info) shutil.rmtree(outputfolder) def editall(args): cmd = Command(args) try: opts, args = getopt.getopt(cmd.getArgs("editall"), "Scx:I:r:", ["clear-list", "exclude=", "excludepki=", "excludepkg=", "include=", "replace=", "sign"]) except getopt.GetoptError, err: # print help information and exit: print str(err) # will print something like "option -a not recognized" help(args) sys.exit(2) index_only = False clear_list=False includes=list() excludes_pki=list() replaces = list() excludes_pkg=list() sign = False interactive = True for opt, arg in opts: if opt in ("-c", "--clear-list"): clear_list = True elif opt in ("-x", "--exclude"): excludes_pki.append(arg) excludes_pkg.append(arg) elif opt in ( "--excludepki"): excludes_pki.append(arg) elif opt in ( "--excludepkg"): excludes_pkg.append(arg) elif opt in ( "--include", "-I"): includes.append(PackageInfo(arg)) elif opt in ("-r", "--replace"): interactive = False replaces.append(arg) elif opt in ("-S", "--sign"): sign = True else: assert False, "unhandled option %r" % opt indexes = IndexList() packages_txt = getDist() +"/packages.txt" if os.path.exists(packages_txt) and not clear_list: indexes.load(packages_txt) else: indexes.build(getPool(), getVersion()) indexes.save(packages_txt) for pkg in includes: indexes.append(pkg) allpackages = list() for info in indexes: if not ( info.code in excludes_pki or info.getFullName() in excludes_pki ): try: if info.hasPki() : print info.getPkiFilename() if interactive : edit_pkginfo_of_package(info.getPkiFilename(), edit_ui) elif len(replaces) < 1: edit_pkginfo_of_package(info.getPkiFilename(), edit_replace, replaces) if sign: edit_pkginfo_of_package(info.getPkiFilename(), edit_sign) except Exception, ex: msgerror("Can't add index '%s', error %s" % (info, str(ex))) def edit(args): cmd = Command(args) try: opts, args = getopt.getopt(cmd.getArgs("edit"), "Sr:", [ "replace=", "onlysign", "sign" ]) except getopt.GetoptError, err: # print help information and exit: print str(err) # will print something like "option -a not recognized" help(args) sys.exit(2) replaces = list() interactive = True sign = False for opt, arg in opts: if opt in ("-r", "--replace"): interactive = False replaces.append(arg) elif opt in ("--onlysign"): interactive = False sign = True elif opt in ("-S", "--sign"): sign = True else: assert False, "unhandled option %r" % opt index_name=args[0] message( "Show package.info from '%s'" % index_name) files = findfiles(getPool(), index_name) if len(files) != 1: msgerror("Can't locate package '%s' in pool '%s'." % (index_name, getPool())) return index_path = files[0] if interactive: edit_pkginfo_of_package(index_path, edit_ui) elif len(replaces) < 1: edit_pkginfo_of_package(index_path, edit_replace, replaces) if sign: edit_pkginfo_of_package(index_path, edit_sign) def edit_ui(filename, args): os.system('vi "%s"' % filename) def edit_replace(filename, args): replaces = args[0] f = open(filename) s = f.read() f.close() for replace in replaces: x = replace.split(replace[0]) if len(x)==4: s=re.sub(x[1],x[2],s) f = open(filename,"w") f.write(s) f.close() def edit_sign(filename, args): os.system('java -cp "%s/commons-codec-1.6.jar:%s/org.gvsig.installer.lib.impl-1.0.1-SNAPSHOT.jar" org.gvsig.installer.lib.impl.utils.SignUtil sign %s' % ( get_gvspkg_bin_folder(), get_gvspkg_bin_folder(), filename) ) def verify_sign(filename): os.system('java -cp "%s/commons-codec-1.6.jar:%s/org.gvsig.installer.lib.impl-1.0.1-SNAPSHOT.jar" org.gvsig.installer.lib.impl.utils.SignUtil verify %s' % ( get_gvspkg_bin_folder(), get_gvspkg_bin_folder(), filename) ) def edit_pkginfo_of_package(pkg_path, operation, *args): outputfolder="/tmp/gvspkg.%s" % os.getpid() os.mkdir(outputfolder) os.system('unzip -q %s -d %s' % (pkg_path,outputfolder)) files = findfiles(outputfolder, "package.info") if len(files) != 1: msgerror("Can't locate package.info in pool '%s'." % (pkg_path)) return package_info = files[0] code = package_info.split("/")[-2] operation(package_info, args) # zip -Dr kk.zip org.gvsig.wfs temp_index_name = "/tmp/packages.gvspki.%s" % os.getpid() temp_index = zipfile.ZipFile(temp_index_name,"w",zipfile.ZIP_STORED) temp_index.write(package_info, "%s/package.info" % (code)) temp_index.close() shutil.rmtree(outputfolder) os.remove(pkg_path) shutil.move(temp_index_name,pkg_path) def install(args): cmd = Command(args) try: opts, args = getopt.getopt(cmd.getArgs("install"), "f", [ "force" ]) except getopt.GetoptError, err: # print help information and exit: print str(err) # will print something like "option -a not recognized" help(args) sys.exit(2) force = False for opt, arg in opts: if opt in ("-f", "--force"): force = True else: assert False, "unhandled option %r" % opt url_pki = args[0] message( "Download package index '%s'" % url_pki) temppath_pki= os.path.join("/tmp",os.path.basename(url_pki)) downloadFile(url_pki,temppath_pki) pkg = PackageInfo(temppath_pki) url_pkg = pkg.getUrl().replace("\\","") message( "Download package '%s'" % url_pkg) temppath_pkg= os.path.join("/tmp",os.path.basename(url_pkg)) downloadFile(url_pkg,temppath_pkg) folder = os.path.join(getPool(),pkg.getCode()) if not os.path.isdir(folder) : os.makedirs(folder) pathname_pki = os.path.join(folder,os.path.basename(url_pki)) if not force and os.path.isfile(pathname_pki) : msgerror("Ya existe en el pool el fichero gvspki indicado.") return 1 pathname_pkg = os.path.join(folder,os.path.basename(url_pkg)) if not force and os.path.isfile(pathname_pki) : msgerror("Ya existe en el pool el fichero gvspkg indicado.") return 1 message( "installing package '%s'" % os.path.basename(pathname_pki)) shutil.copyfile(temppath_pki, pathname_pki) message( "installing package '%s'" % os.path.basename(pathname_pkg)) shutil.copyfile(temppath_pkg, pathname_pkg) def downloadFile(url,path): fsrc = urllib2.urlopen(url) fdst = file(path,"wb") shutil.copyfileobj(fsrc,fdst) fdst.close() fsrc.close() def help(args): print """ usage: gvspkg [OPTIONS] COMMANDS OPTIONS: -h|--help Muestra esta ayuda -v|--verbose Activa el modo verbose -d|--debug Activa el modo debug. Se muestran mensajes que pueden ser utilies de cara a depuracion. --version version Fija la version con la que van a trabajar los comandos indicados. -r|--package-root package-root Fija la carpeta en la que va a buscar el raiz del sistema de paquetes con el que trabajar COMMANDS: mkinstall [OPTIONS] install-file packages-file OPTIONS: -L | --jrelin=path -W | --jrewin=path -l | --addjrelin -w | --addjrewin -N | --distribution-name=name Nombre usado como sufijo del nuevo binario a generar. Por defecto si no se indica valdra "custom". lsi [OPTIONS] Lista los indices disponibles de la version OPTIONS: -l | --long-format Muestra para cada paquete la informacion del package.info mks [OPTIONS] Crea el fichero packages.gvspki con los indices de la version y packages.gvspkg con los paquetes. OPTIONS: -c | --clear-list Elimina la lista de paquetes a utilizar recreandola a partir de los paquetes del pool tomando el ultimo build de cada paquete. --excludepkg pkgcode No incluye el paquete indicado en el fichero gvspkg a generar --excludepki pkgcode No incluye el paquete indicado en el fichero gvspki a generar --exclude pkgcode No incluye el paquete indicado en los ficheros gvspkg y gvspki a generar -s | --include-default-selection Incluye el fichero "defaultPackages", que se debe encontrar en el directorio corriente, con los nombres de paquetes a seleccionar por defecto. -i | --index-only No crea el fichero gvspks, solo crea el gvspki -I full-path-to-package | --include full-path-to-package Añade el paquete indicado a la lista de paquetes aunque no coincida para la version de gvSIG con la que se esta trabajando. mkhtml [OPTIONS] ???? OPTIONS: -c | --clear-list Elimina la lista de paquetes a utilizar recreandola a partir de los paquetes del pool tomando el ultimo build de cada paquete. --excludepkg pkgcode No incluye el paquete indicado en el fichero gvspkg a generar --excludepki pkgcode No incluye el paquete indicado en el fichero gvspki a generar --exclude pkgcode No incluye el paquete indicado en los ficheros gvspkg y gvspki a generar show OPTIONS package-index Muestra el package.info del indice indicado como parametro. OPTIONS --verify | -V Comprueba la forma del packete. edit [OPTIONS] package-index Edita el package.info del indice indicado como parametro. OPTIONS: --replace=@search@replace@ Reemplaza en el package.info de cada paquete la cadena "search" por "replace" todas las veces que aparezca. "@" puede ser cualquier caracter que no aparezca en "search" y "replace". Esta opcion puede indicarse tatas veces como reemplazos se deseen efectuar. --onlysign firma el package.info sin editarlo de forma interactiva (no invoca al editor antes de firmarlo). --sign | -S Firma el package.info tras terminar la edicion (bach o interactiva) editall [OPTIONS] Edita todos los package.info OPTIONS: -c | --clear-list Elimina la lista de paquetes a utilizar recreandola a partir de los paquetes del pool tomando el ultimo build de cada paquete. --excludepkg pkgcode No incluye el paquete indicado en el fichero gvspkg a generar --excludepki pkgcode No incluye el paquete indicado en el fichero gvspki a generar --exclude pkgcode No incluye el paquete indicado en los ficheros gvspkg y gvspki a generar --replace=@search@replace@ Reemplaza en el package.info de cada paquete la cadena "search" por "replace" todas las veces que aparezca. "@" puede ser cualquier caracter que no aparezca en "search" y "replace". Esta opcion puede indicarse tatas veces como reemplazos se deseen efectuar. --sign | -S Firma todos los paquetes que sean oficiales install [OPTIONS] url-to-pki descarga de la url indicada un fichero gvspki e instala este junto con su correspondiente pkg en el pool local. OPTIONS: -f | --force fuerza la sobreescritura de los ficheros en caso de que estos ya existan. Si en la carpeta corriente encuentra un fichero gvspkg.options cargara los flags indicados ahi como flags por defecto para cada comando. El formato del fichero es: main=OPCION-POR-DEFECTO mks=OPCOPNES-POR-DEFECTO Donde main indica las opciones por defecto generales, independientes del comando a ejecutar. "mks" indica las opciones por defecto a usar en el comando "mks", y asi sucesivamente, indicando el nombre del comando seguido de un "=" y las opciones por defecto para ese comando. Por defecto la version la obtiene del nombre de la carpeta corriente (%s). Las opciones indicadas en el fichero gvspkg.options tienen prioridad sobre este valor. El directorio root de la estructura de packetes lo buscara en el sitio indicado por la variable de entorno GVPKG_ROOT, y si esta no esta establecida usara "%s". Las opciones indicadas en el fichero gvspkg.options tienen prioridad sobre este valor. """ % (VERSION, GVSPKG_ROOT) def main(): global VERSION global VERBOSE global GVSPKG_ROOT cmd = Command(sys.argv) try: opts, args = getopt.getopt(cmd.getArgs("main"), "dhvr:", ["debug", "verbose", "version=", "package-root=","help"]) except getopt.GetoptError, err: # print help information and exit: print str(err) # will print something like "option -a not recognized" help(None) sys.exit(2) for opt, arg in opts: if opt in ("-h", "--help"): help(args) sys.exit() elif opt in ("-d", "--debug"): DEBUG = True elif opt in ("-v", "--verbose"): VERBOSE = True elif opt in ("--version"): VERSION = arg elif opt in ("-r", "--package-root"): GVSPKG_ROOT = arg else: assert False, "unhandled option" # message("VERSION=%s" % VERSION) message("GVSPKG_ROOT=%s" % GVSPKG_ROOT) command = "help" if len(args)>0: command=args[0] if command=="lsi" : lsi(args) elif command == "mks": mks(args) elif command == "edit": edit(args) elif command == "editall": editall(args) elif command == "show": show(args) elif command == "mkhtml": mkhtml(args) elif command == "mkinstall": mkinstall(args) elif command == "install": install(args) else: help(args) main()