createrepo/__init__.py createrepo/utils.py createrepo/yumbased.py genpkgmetadata.py
[email protected] (Seth Vidal)
| Newsgroups | gmane.linux.rpm.metadata |
|---|---|
| Message-ID | <[email protected]> |
createrepo/__init__.py | 169 +++++++++++++++++++++++++++++++++++++++++-------- createrepo/utils.py | 6 - createrepo/yumbased.py | 15 ++-- genpkgmetadata.py | 147 ++++-------------------------------------- 4 files changed, 170 insertions(+), 167 deletions(-) New commits: commit 77d30d7581dea9adfa5966088eddcf48efacb5c5 Author: Seth Vidal <[email protected]> Date: Wed Jan 16 12:12:44 2008 -0500 clean up api to simplify all of the code calling it probably severely break --split for the moment, though diff --git a/createrepo/__init__.py b/createrepo/__init__.py index 0421e1e..210d6fe 100644 --- a/createrepo/__init__.py +++ b/createrepo/__init__.py @@ -37,7 +37,7 @@ except ImportError: pass -from utils import _gzipOpen, bzipFile +from utils import _gzipOpen, bzipFile, checkAndMakeDir __version__ = '0.9.1' @@ -98,10 +98,7 @@ class SimpleMDCallBack(object): sys.stdout.write("\r%d/%d - %s" % (current, total, item)) sys.stdout.flush() -#FIXME = make it so you pass in a dir to doPkgMetadata() and it -# parses out basedir and directory for relative dir from there -# it creates the .repodata directory in the output location, etc - + class MetaDataGenerator: def __init__(self, config_obj=None, callback=None): self.conf = config_obj @@ -116,17 +113,69 @@ class MetaDataGenerator: self.ts = rpmUtils.transaction.initReadOnlyTransaction() self.pkgcount = 0 self.files = [] + + if not self.conf.directory and not self.conf.directories: + raise MDError, "No directory given on which to run." + + # this does the dir setup we need done + self._parse_directory(self.conf.directory) + self._test_setup_dirs() - def _setup_and_check_repo_dir(self, direc): + def _parse_directory(self, direc): if os.path.isabs(direc): self.conf.basedir = os.path.dirname(direc) - self.conf.directory = os.path.basename(direc) + self.conf.relative_dir = os.path.basename(direc) else: self.conf.basedir = os.path.realpath(self.conf.basedir) + self.conf.relative_dir = direc + + self.package_dir = os.path.join(self.conf.basedir, self.conf.relative_dir) + + if not self.conf.outputdir: + self.conf.outputdir = os.path.join(self.conf.basedir, self.conf.relative_dir) + + + def _test_setup_dirs(self): + testdir = os.path.realpath(os.path.join(self.conf.basedir, self.conf.relative_dir)) + # start the sanity/stupidity checks + if not os.path.exists(testdir): + raise MDError, _('Directory %s must exist') % self.conf.directory + + if not os.path.isdir(testdir): + raise MDError, _('%s must be a directory') % self.conf.directory + + if not os.access(self.conf.outputdir, os.W_OK): + raise MDError, _('Directory %s must be writable.') % self.conf.outputdir + +# SPLIT STUFF? +# if self.conf.split: +# oldbase = self.conf.basedir +# self.conf.basedir = os.path.join(self.conf.basedir, self.conf.directory) - if not self.conf.opts.outputdir: - self.conf.outputdir = os.path.join(self.conf.basedir, direc) + temp_output = os.path.join(self.conf.outputdir, self.conf.tempdir) + if not checkAndMakeDir(temp_output): + raise MDError, _('Cannot create/verify %s') % temp_output + temp_final = os.path.join(self.conf.outputdir, self.conf.finaldir) + if not checkAndMakeDir(temp_final): + raise MDError, _('Cannot create/verify %s') % temp_final + + if os.path.exists(os.path.join(self.conf.outputdir, self.conf.olddir)): + raise MDError, _('Old data directory exists, please remove: %s') % self.conf.olddir + + # make sure we can write to where we want to write to: + # and pickup the mdtimestamps while we're at it + for direc in ['tempdir', 'finaldir']: + for f in ['primaryfile', 'filelistsfile', 'otherfile', 'repomdfile']: + filepath = os.path.join(self.conf.outputdir, direc, f) + if os.path.exists(filepath): + if not os.access(filepath, os.W_OK): + raise MDError, _('error in must be able to write to metadata files:\n -> %s') % filepath + + if conf.checkts: + timestamp = os.path.getctime(filepath) + if timestamp > self.conf.mdtimestamp: + self.conf.mdtimestamp = timestamp def _os_path_walk(self, top, func, arg): """Directory tree walk with callback function. @@ -143,7 +192,7 @@ class MetaDataGenerator: if os.path.isdir(name): self._os_path_walk(name, func, arg) # module - def getFileList(self, basepath, directory, ext): + def getFileList(self, directory, ext): """Return all files in path matching ext, store them in filelist, recurse dirs. Returns a list object""" @@ -161,7 +210,7 @@ class MetaDataGenerator: filelist.append(os.path.join(relativepath,fn)) filelist = [] - startdir = os.path.join(basepath, directory) + '/' + startdir = directory + '/' self._os_path_walk(startdir, extension_visitor, filelist) return filelist @@ -198,11 +247,9 @@ class MetaDataGenerator: files.remove(file) return files - def doPkgMetadata(self, directory=None): + def doPkgMetadata(self): """all the heavy lifting for the package metadata""" - if not directory: - directory = self.conf.directory - + # rpms we're going to be dealing with if self.conf.update: #build the paths @@ -211,7 +258,7 @@ class MetaDataGenerator: otherfile = os.path.join(self.conf.outputdir, self.conf.finaldir, self.conf.otherfile) opts = { 'verbose' : self.conf.verbose, - 'pkgdir' : os.path.normpath(os.path.join(self.conf.basedir, directory)) + 'pkgdir' : os.path.normpath(self.package_dir) } if self.conf.skip_stat: opts['do_stat'] = False @@ -222,12 +269,12 @@ class MetaDataGenerator: if self.conf.pkglist: packages = self.conf.pkglist else: - packages = self.getFileList(self.conf.basedir, directory, '.rpm') + packages = self.getFileList(self.package_dir, '.rpm') packages = self.trimRpms(packages) self.pkgcount = len(packages) self.openMetadataDocs() - self.writeMetadataDocs(packages, directory) + self.writeMetadataDocs(packages) self.closeMetadataDocs() # module @@ -264,19 +311,23 @@ class MetaDataGenerator: return fo - def read_in_package(self, directory, rpmfile): - # directory is stupid - just make it part of the class - rpmfile = '%s/%s/%s' % (self.conf.basedir, directory, rpmfile) + def read_in_package(self, rpmfile): + """rpmfile == relative path to file from self.packge_dir""" + + rpmfile = '%s/%s' % (self.package_dir, rpmfile) try: po = yumbased.CreateRepoPackage(self.ts, rpmfile) except Errors.MiscError, e: raise MDError, "Unable to open package: %s" % e return po - def writeMetadataDocs(self, pkglist, directory, current=0): - # FIXME - # directory is unused, kill it, pkglist should come from self - # I don't see why current needs to be this way at all + def writeMetadataDocs(self, pkglist=[], directory=None, current=0): + + if not pkglist: + pkglist = self.conf.pkglist + if not directory: + directory=self.conf.directory + for pkg in pkglist: current+=1 recycled = False @@ -294,7 +345,7 @@ class MetaDataGenerator: if not recycled: #scan rpm files try: - po = self.read_in_package(directory, pkg) + po = self.read_in_package(pkg) except MDError, e: # need to say something here self.callback.errorlog("\nError %s: %s\n" % (pkg, e)) @@ -486,6 +537,72 @@ class MetaDataGenerator: del repodoc + + def doFinalMove(self): + """move the just-created repodata from .repodata to repodata + also make sure to preserve any files we didn't mess with in the + metadata dir""" + + output_final_dir = os.path.join(self.conf.outputdir, self.conf.finaldir) + output_old_dir = os.path.join(self.conf.outputdir, self.conf.olddir) + + if os.path.exists(output_final_dir): + try: + os.rename(output_final_dir, output_old_dir) + except: + raise MDError, _('Error moving final %s to old dir %s' % (output_final_dir, + output_old_dir)) + + output_temp_dir = os.path.join(self.conf.outputdir, self.conf.tempdir) + + try: + os.rename(output_temp_dir, output_final_dir) + except: + # put the old stuff back + os.rename(output_old_dir, output_final_dir) + raise MDError, _('Error moving final metadata into place') + + for f in ['primaryfile', 'filelistsfile', 'otherfile', 'repomdfile', 'groupfile']: + if getattr(self.conf, f): + fn = os.path.basename(getattr(self.conf, f)) + else: + continue + oldfile = os.path.join(output_old_dir, fn) + + if os.path.exists(oldfile): + try: + os.remove(oldfile) + except OSError, e: + raise MDError, _('Could not remove old metadata file: %s: %s') % (oldfile, e) + + # Move everything else back from olddir (eg. repoview files) + for f in os.listdir(output_old_dir): + oldfile = os.path.join(output_old_dir, f) + finalfile = os.path.join(output_final_dir, f) + if os.path.exists(finalfile): + # Hmph? Just leave it alone, then. + try: + if os.path.isdir(oldfile): + shutil.rmtree(oldfile) + else: + os.remove(oldfile) + except OSError, e: + raise MDError, _('Could not remove old metadata file: %s: %s') % (oldfile, e) + else: + try: + os.rename(oldfile, finalfile) + except OSError, e: + msg = _('Could not restore old non-metadata file: %s -> %s') % (oldfile, finalfile) + msg += _('Error was %s') % e + raise MDError, msg + + try: + os.rmdir(output_old_dir) + except OSError, e: + self.errorlog(_('Could not remove old metadata dir: %s') % self.conf.olddir) + self.errorlog(_('Error was %s') % e) + self.errorlog(_('Please clean up this directory manually.')) + class SplitMetaDataGenerator(MetaDataGenerator): def __init__(self, config_obj=None, callback=None): diff --git a/createrepo/utils.py b/createrepo/utils.py index 51e56cd..13d1d67 100644 --- a/createrepo/utils.py +++ b/createrepo/utils.py @@ -104,11 +104,11 @@ def checkAndMakeDir(dir): """ if os.path.exists(dir): if not os.path.isdir(dir): - errorprint(_('%s is not a dir') % dir) + #errorprint(_('%s is not a dir') % dir) result = False else: if not os.access(dir, os.W_OK): - errorprint(_('%s is not writable') % dir) + #errorprint(_('%s is not writable') % dir) result = False else: result = True @@ -116,7 +116,7 @@ def checkAndMakeDir(dir): try: os.mkdir(dir) except OSError, e: - errorprint(_('Error creating dir %s: %s') % (dir, e)) + #errorprint(_('Error creating dir %s: %s') % (dir, e)) result = False else: result = True diff --git a/createrepo/yumbased.py b/createrepo/yumbased.py index 88fcb0c..e705f6e 100644 --- a/createrepo/yumbased.py +++ b/createrepo/yumbased.py @@ -64,6 +64,7 @@ class CreateRepoPackage(YumLocalPackage): def _xml(self, item): item = utils.utf8String(item) + item = item.rstrip() return xml.sax.saxutils.escape(item) def _do_checksum(self): @@ -154,7 +155,7 @@ class CreateRepoPackage(YumLocalPackage): <packager>%s</packager> <url>%s</url> <time file="%s" build="%s"/> - <size package="%s" installed="%s" archive="%s"/>""" % (self.name, + <size package="%s" installed="%s" archive="%s"/>\n""" % (self.name, self.arch, self.epoch, self.ver, self.rel, self.checksum, self._xml(self.summary), self._xml(self.description), packager, url, self.filetime, self.buildtime, self.packagesize, self.size, @@ -162,9 +163,9 @@ class CreateRepoPackage(YumLocalPackage): if baseurl: - msg += """<location xml:base="%s" href="%s"/>""" % (self._xml(baseurl), relpath) + msg += """<location xml:base="%s" href="%s"/>\n""" % (self._xml(baseurl), relpath) else: - msg += """<location href="%s"/>""" % relpath + msg += """<location href="%s"/>\n""" % relpath return msg @@ -173,22 +174,22 @@ class CreateRepoPackage(YumLocalPackage): if self.license: msg += """ <rpm:license>%s</rpm:license>\n""" % self._xml(self.license) else: - msg += """ <rpm:license/>""" + msg += """ <rpm:license/>\n""" if self.vendor: msg += """ <rpm:vendor>%s</rpm:vendor>\n""" % self._xml(self.vendor) else: - msg += """ <rpm:vendor/>""" + msg += """ <rpm:vendor/>\n""" if self.group: msg += """ <rpm:group>%s</rpm:group>\n""" % self._xml(self.group) else: - msg += """ <rpm:group/>""" + msg += """ <rpm:group/>\n""" if self.buildhost: msg += """ <rpm:buildhost>%s</rpm:buildhost>\n""" % self._xml(self.buildhost) else: - msg += """ <rpm:buildhost/>""" + msg += """ <rpm:buildhost/>\n""" if self.sourcerpm: msg += """ <rpm:sourcerpm>%s</rpm:sourcerpm>\n""" % self._xml(self.sourcerpm) diff --git a/genpkgmetadata.py b/genpkgmetadata.py index 38cd151..0449258 100755 --- a/genpkgmetadata.py +++ b/genpkgmetadata.py @@ -106,16 +106,10 @@ def parseArgs(args, conf): setattr(conf, opt.dest, getattr(opts, opt.dest)) directory = directories[0] - directory = os.path.normpath(directory) - if conf.split: - pass - elif os.path.isabs(directory): - conf.basedir = os.path.dirname(directory) - directory = os.path.basename(directory) - else: - conf.basedir = os.path.realpath(conf.basedir) + conf.directory = directory + conf.directories = directories - + # FIXME - I think this is unnecessary if not opts.outputdir: conf.outputdir = os.path.join(conf.basedir, directory) if conf.groupfile: @@ -124,10 +118,12 @@ def parseArgs(args, conf): a = os.path.join(conf.basedir, directory, conf.groupfile) elif not os.path.isabs(a): a = os.path.join(conf.basedir, directory, conf.groupfile) + # FIXME, move this test most likely inside the class if not os.path.exists(a): errorprint(_('Error: groupfile %s cannot be found.' % a)) usage() conf.groupfile = a + # FIXME - move this one inside the class, too if conf.cachedir: conf.cache = True a = conf.cachedir @@ -148,12 +144,6 @@ def parseArgs(args, conf): conf.pkglist = lst - #setup some defaults - - # Fixup first directory - directories[0] = directory - conf.directory = directory - conf.directories = directories return conf @@ -172,130 +162,25 @@ class MDCallBack(object): def main(args): conf = createrepo.MetaDataConfig() conf = parseArgs(args, conf) - # FIXME - some of these should be moved into the module and out of the cli routines - testdir = os.path.realpath(os.path.join(conf.basedir, conf.directory)) - # start the sanity/stupidity checks - if not os.path.exists(testdir): - errorprint(_('Directory %s must exist') % (conf.directory,)) - sys.exit(1) - if not os.path.isdir(testdir): - errorprint(_('%s - must be a directory') - % (conf.directory,)) - sys.exit(1) - - if not os.access(conf.outputdir, os.W_OK): - errorprint(_('Directory %s must be writable.') % (conf.outputdir,)) - sys.exit(1) - - if conf.split: - oldbase = conf.basedir - conf.basedir = os.path.join(conf.basedir, conf.directory) - if not checkAndMakeDir(os.path.join(conf.outputdir, conf.tempdir)): - sys.exit(1) - - if not checkAndMakeDir(os.path.join(conf.outputdir, conf.finaldir)): - sys.exit(1) - - if os.path.exists(os.path.join(conf.outputdir, conf.olddir)): - errorprint(_('Old data directory exists, please remove: %s') % conf.olddir) - sys.exit(1) - - # make sure we can write to where we want to write to: - for direc in ['tempdir', 'finaldir']: - for f in ['primaryfile', 'filelistsfile', 'otherfile', 'repomdfile']: - filepath = os.path.join(conf.outputdir, direc, f) - if os.path.exists(filepath): - if not os.access(filepath, os.W_OK): - errorprint(_('error in must be able to write to metadata files:\n -> %s') % filepath) - usage() - if conf.checkts: - timestamp = os.path.getctime(filepath) - if timestamp > conf.mdtimestamp: - conf.mdtimestamp = timestamp - - if conf.split: - conf.basedir = oldbase - mdgen = createrepo.SplitMetaDataGenerator(config_obj=conf, callback=MDCallBack()) - else: - mdgen = createrepo.MetaDataGenerator(config_obj=conf, callback=MDCallBack()) - if mdgen.checkTimeStamps(): - if mdgen.conf.verbose: - print _('repo is up to date') - sys.exit(0) try: + if conf.split: + mdgen = createrepo.SplitMetaDataGenerator(config_obj=conf, callback=MDCallBack()) + else: + mdgen = createrepo.MetaDataGenerator(config_obj=conf, callback=MDCallBack()) + if mdgen.checkTimeStamps(): + if mdgen.conf.verbose: + print _('repo is up to date') + sys.exit(0) + mdgen.doPkgMetadata() mdgen.doRepoMetadata() + mdgen.doFinalMove() + except MDError, e: errorprint(_('%s') % e) sys.exit(1) - output_final_dir = os.path.join(mdgen.conf.outputdir, mdgen.conf.finaldir) - output_old_dir = os.path.join(mdgen.conf.outputdir, mdgen.conf.olddir) - - if os.path.exists(output_final_dir): - try: - os.rename(output_final_dir, output_old_dir) - except: - errorprint(_('Error moving final %s to old dir %s' % (output_final_dir, - output_old_dir))) - sys.exit(1) - - output_temp_dir =os.path.join(mdgen.conf.outputdir, mdgen.conf.tempdir) - - try: - os.rename(output_temp_dir, output_final_dir) - except: - errorprint(_('Error moving final metadata into place')) - # put the old stuff back - os.rename(output_old_dir, output_final_dir) - sys.exit(1) - - for f in ['primaryfile', 'filelistsfile', 'otherfile', 'repomdfile', 'groupfile']: - if getattr(mdgen.conf, f): - fn = os.path.basename(getattr(mdgen.conf, f)) - else: - continue - oldfile = os.path.join(output_old_dir, fn) - - if os.path.exists(oldfile): - try: - os.remove(oldfile) - except OSError, e: - errorprint(_('Could not remove old metadata file: %s') % oldfile) - errorprint(_('Error was %s') % e) - sys.exit(1) - - # Move everything else back from olddir (eg. repoview files) - for f in os.listdir(output_old_dir): - oldfile = os.path.join(output_old_dir, f) - finalfile = os.path.join(output_final_dir, f) - if os.path.exists(finalfile): - # Hmph? Just leave it alone, then. - try: - if os.path.isdir(oldfile): - shutil.rmtree(oldfile) - else: - os.remove(oldfile) - except OSError, e: - errorprint(_('Could not remove old non-metadata file: %s') % oldfile) - errorprint(_('Error was %s') % e) - sys.exit(1) - else: - try: - os.rename(oldfile, finalfile) - except OSError, e: - errorprint(_('Could not restore old non-metadata file: %s -> %s') % (oldfile, finalfile)) - errorprint(_('Error was %s') % e) - sys.exit(1) - - - try: - os.rmdir(output_old_dir) - except OSError, e: - errorprint(_('Could not remove old metadata dir: %s') % mdgen.conf.olddir) - errorprint(_('Error was %s') % e) - errorprint(_('Please clean up this directory manually.')) if __name__ == "__main__": if len(sys.argv) > 1: