Re: Frustrated trying to build beecrypt & rpm on a Debian system whereI'm not root

"Paul Johnson" <[email protected]>
Newsgroups gmane.linux.redhat.rpm.general
Message-ID <[email protected]>
On Nov 25, 2007 4:41 PM, Mike Meyer <[email protected]> wrote:
> On Sun, 25 Nov 2007 15:21:25 -0600 "Paul Johnson" <[email protected]> wrote:
>

> Can you make sure that createrepo is using the Python you think it
> should? That's the only explanation I can think of for the error you
> quoted earlier.

YES! That's it.  createrepo is just this:

#!/bin/sh
exec /usr/share/createrepo/genpkgmetadata.py "$@"

But the programs called by createrepo had the /usr/bin/python hard
coded in, so it was accessing 2.3's executable but it was trying to
use libs for 2.4.

After fixing that, now I'm back full circle to the original problem.
I build & install the rpm python modues under
$HOME/packages/lib/python2.4, but even though I add that directory to
$PYTHONPATH, then the run of create repo  fails because it cannot find
the module "rpm".




>
> Where can I find a copy of creatrepo (assuming it's python)?
>

I got the createrepo stuff from an RPM in Scientific Linux 5

createrepo-0.4.4-2.fc6.noarch

from the SRPM file in their server is just the one from fedora core 6,
ftp://linux.fnal.gov/linux/scientific/50/SRPMS/vendor/createrepo-0.4.4-2.fc6.src.rpm

But you can get the newer one here.

http://mirror.cogentco.com/pub/linux/fedora/linux/releases/8/Everything/source/SRPMS/createrepo-0.4.10-1.fc8.src.rpm

In case you just want a quick glance at one of their programs, I'm
attaching an original, unchanged version of genpkgmetadata.py for your
convenience.

pj

> --
> Mike Meyer <[email protected]>              http://www.mired.org/consulting.html
> Independent Network/Unix/Perforce consultant, email for more information.
>

-- 
Paul E. Johnson
Professor, Political Science
1541 Lilac Lane, Room 504
University of Kansas

_______________________________________________
Rpm-list mailing list
[email protected]
https://www.redhat.com/mailman/listinfo/rpm-list
genpkgmetadata.py (application/octet-stream, 23.3 KB)
#!/usr/bin/python -t
# primary functions and glue for generating the repository metadata
#

# 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.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU Library General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
# Copyright 2004 Duke University

# $Id: genpkgmetadata.py,v 1.51 2006/02/21 23:30:26 pnasrat Exp $


import os
import sys
import getopt
import rpm
import libxml2
import string
import fnmatch
import urlgrabber

import dumpMetadata
from dumpMetadata import _gzipOpen
__version__ = '0.4.3'

def errorprint(stuff):
    print >> sys.stderr, stuff

def _(args):
    """Stub function for translation"""
    return args

def usage(retval=1):
    print _("""
    createrepo [options] directory-of-packages

    Options:
     -u, --baseurl <url> = optional base url location for all files
     -o, --outputdir <dir> = optional directory to output to
     -x, --exclude = files globs to exclude, can be specified multiple times
     -q, --quiet = run quietly
     -g, --groupfile <filename> to point to for group information (precreated)
                    (<filename> relative to directory-of-packages)
     -v, --verbose = run verbosely
     -c, --cachedir <dir> = specify which dir to use for the checksum cache
     -U, --update-info-location <url> = acquire package update metadata
     -h, --help = show this help
     -V, --version = output version
     -p, --pretty = output xml files in pretty format.
    """)

    sys.exit(retval)

class MetaDataGenerator:
    def __init__(self, cmds):
        self.cmds = cmds
        self.ts = rpm.TransactionSet()
        self.pkgcount = 0
        self.files = []

    def getFileList(self, basepath, path, ext, filelist):
        """Return all files in path matching ext, store them in filelist,
        recurse dirs. Returns a list object"""

        extlen = len(ext)
        totalpath = os.path.normpath(os.path.join(basepath, path))
        try:
            dir_list = os.listdir(totalpath)
        except OSError, e:
            errorprint(_('Error accessing directory %s, %s') % (totalpath, e))
            sys.exit(1)

        for d in dir_list:
            if os.path.isdir(totalpath + '/' + d):
                filelist = self.getFileList(basepath, os.path.join(path, d), ext, filelist)
            else:
                if string.lower(d[-extlen:]) == '%s' % (ext):
                    if totalpath.find(basepath) == 0:
                        relativepath = totalpath.replace(basepath, "", 1)
                        relativepath = relativepath.lstrip("/")
                        filelist.append(os.path.join(relativepath, d))
                    else:
                        raise "basepath '%s' not found in path '%s'" % (basepath, totalpath)

        return filelist


    def trimRpms(self, files):
        badrpms = []
        for file in files:
            for glob in self.cmds['excludes']:
                if fnmatch.fnmatch(file, glob):
                    # print 'excluded: %s' % file
                    if file not in badrpms:
                        badrpms.append(file)
        for file in badrpms:
            if file in files:
                files.remove(file)
        return files

    def doPkgMetadata(self, directory):
        """all the heavy lifting for the package metadata"""

        # rpms we're going to be dealing with
        files = self.getFileList(self.cmds['basedir'], directory, '.rpm', [])
        files = self.trimRpms(files)
        self.pkgcount = len(files)
        self.openMetadataDocs()
        self.writeMetadataDocs(files)
        self.closeMetadataDocs()


    def openMetadataDocs(self):
        self._setupBase()
        self._setupFilelists()
        self._setupOther()

    def _setupBase(self):
        # setup the base metadata doc
        self.basedoc = libxml2.newDoc("1.0")
        self.baseroot =  self.basedoc.newChild(None, "metadata", None)
        basens = self.baseroot.newNs('http://linux.duke.edu/metadata/common', None)
        self.formatns = self.baseroot.newNs('http://linux.duke.edu/metadata/rpm', 'rpm')
        self.baseroot.setNs(basens)
        basefilepath = os.path.join(self.cmds['outputdir'], self.cmds['tempdir'], self.cmds['primaryfile'])
        self.basefile = _gzipOpen(basefilepath, 'w')
        self.basefile.write('<?xml version="1.0" encoding="UTF-8"?>\n')
        self.basefile.write('<metadata xmlns="http://linux.duke.edu/metadata/common" xmlns:rpm="http://linux.duke.edu/metadata/rpm" packages="%s">\n' %
                       self.pkgcount)

    def _setupFilelists(self):
        # setup the file list doc
        self.filesdoc = libxml2.newDoc("1.0")
        self.filesroot = self.filesdoc.newChild(None, "filelists", None)
        filesns = self.filesroot.newNs('http://linux.duke.edu/metadata/filelists', None)
        self.filesroot.setNs(filesns)
        filelistpath = os.path.join(self.cmds['outputdir'], self.cmds['tempdir'], self.cmds['filelistsfile'])
        self.flfile = _gzipOpen(filelistpath, 'w')
        self.flfile.write('<?xml version="1.0" encoding="UTF-8"?>\n')
        self.flfile.write('<filelists xmlns="http://linux.duke.edu/metadata/filelists" packages="%s">\n' %
                       self.pkgcount)

    def _setupOther(self):
        # setup the other doc
        self.otherdoc = libxml2.newDoc("1.0")
        self.otherroot = self.otherdoc.newChild(None, "otherdata", None)
        otherns = self.otherroot.newNs('http://linux.duke.edu/metadata/other', None)
        self.otherroot.setNs(otherns)
        otherfilepath = os.path.join(self.cmds['outputdir'], self.cmds['tempdir'], self.cmds['otherfile'])
        self.otherfile = _gzipOpen(otherfilepath, 'w')
        self.otherfile.write('<?xml version="1.0" encoding="UTF-8"?>\n')
        self.otherfile.write('<otherdata xmlns="http://linux.duke.edu/metadata/other" packages="%s">\n' %
                       self.pkgcount)

    def writeMetadataDocs(self, files, current=0):
        for file in files:
            current+=1
            try:
                mdobj = dumpMetadata.RpmMetaData(self.ts, self.cmds['basedir'], file, self.cmds)
                if not self.cmds['quiet']:
                    if self.cmds['verbose']:
                        print '%d/%d - %s' % (current, len(files), file)
                    else:
                        sys.stdout.write('\r' + ' ' * 80)
                        sys.stdout.write("\r%d/%d - %s" % (current, self.pkgcount, file))
                        sys.stdout.flush()
            except dumpMetadata.MDError, e:
                errorprint('\n%s - %s' % (e, file))
                continue
            else:
                try:
                    node = dumpMetadata.generateXML(self.basedoc, self.baseroot, self.formatns, mdobj, self.cmds['sumtype'])
                except dumpMetadata.MDError, e:
                    errorprint(_('\nAn error occurred creating primary metadata: %s') % e)
                    continue
                else:
                    try:
                        # Fetch the update metadata for this package
                        if self.cmds['update-info-location']:
                            metadata = urlgrabber.urlopen(
                                    self.cmds['update-info-location'] +
                                    '?pkg=%s' % file)
                            filename = file.replace('.rpm', '.xml')
                            metadata.filename = os.path.join(
                                    self.cmds['basedir'], self.cmds['tempdir'],
                                    self.cmds['update-info-dir'], filename)
                            metadata._do_grab()
                            metadata.close()

                            # Get the update ID from the metadata
                            md = libxml2.parseFile(metadata.filename)
                            update_root = md.children
                            update = node.newChild(None, 'update', None)
                            update.newProp('id', update_root.prop('id'))
                            update.newProp('location', os.path.join(
                                    self.cmds['update-info-dir'], filename))
                            del md, metadata
                    except Exception, e:
                        pass
                    output = node.serialize('UTF-8', self.cmds['pretty'])
                    self.basefile.write(output)
                    self.basefile.write('\n')
                    node.unlinkNode()
                    node.freeNode()
                    del node

                try:
                    node = dumpMetadata.fileListXML(self.filesdoc, self.filesroot, mdobj)
                except dumpMetadata.MDError, e:
                    errorprint(_('\nAn error occurred creating filelists: %s') % e)
                    continue
                else:
                    output = node.serialize('UTF-8', self.cmds['pretty'])
                    self.flfile.write(output)
                    self.flfile.write('\n')
                    node.unlinkNode()
                    node.freeNode()
                    del node

                try:
                    node = dumpMetadata.otherXML(self.otherdoc, self.otherroot, mdobj)
                except dumpMetadata.MDError, e:
                    errorprint(_('\nAn error occurred: %s') % e)
                    continue
                else:
                    output = node.serialize('UTF-8', self.cmds['pretty'])
                    self.otherfile.write(output)
                    self.otherfile.write('\n')
                    node.unlinkNode()
                    node.freeNode()
                    del node
        return current


    def closeMetadataDocs(self):
        if not self.cmds['quiet']:
            print ''

        # save them up to the tmp locations:
        if not self.cmds['quiet']:
            print _('Saving Primary metadata')
        self.basefile.write('\n</metadata>')
        self.basefile.close()
        self.basedoc.freeDoc()

        if not self.cmds['quiet']:
            print _('Saving file lists metadata')
        self.flfile.write('\n</filelists>')
        self.flfile.close()
        self.filesdoc.freeDoc()

        if not self.cmds['quiet']:
            print _('Saving other metadata')
        self.otherfile.write('\n</otherdata>')
        self.otherfile.close()
        self.otherdoc.freeDoc()

    def doRepoMetadata(self):
        """wrapper to generate the repomd.xml file that stores the info on the other files"""
        repodoc = libxml2.newDoc("1.0")
        reporoot = repodoc.newChild(None, "repomd", None)
        repons = reporoot.newNs('http://linux.duke.edu/metadata/repo', None)
        reporoot.setNs(repons)
        repofilepath = os.path.join(self.cmds['outputdir'], self.cmds['tempdir'], self.cmds['repomdfile'])

        try:
            dumpMetadata.repoXML(reporoot, self.cmds)
        except dumpMetadata.MDError, e:
            errorprint(_('Error generating repo xml file: %s') % e)
            sys.exit(1)

        try:
            repodoc.saveFormatFileEnc(repofilepath, 'UTF-8', 1)
        except:
            errorprint(_('Error saving temp file for rep xml: %s') % repofilepath)
            sys.exit(1)

        del repodoc

class SplitMetaDataGenerator(MetaDataGenerator):

    def __init__(self, cmds):
        MetaDataGenerator.__init__(self, cmds)
        self.initialdir = self.cmds['basedir']

    def _getFragmentUrl(self, url, fragment):
        import urlparse
        urlparse.uses_fragment.append('media')
        if not url:
            return url
        (scheme, netloc, path, query, fragid) = urlparse.urlsplit(url)
        return urlparse.urlunsplit((scheme, netloc, path, query, str(fragment)))

    def doPkgMetadata(self, directories):
        """all the heavy lifting for the package metadata"""
        import types
        if type(directories) == types.StringType:
            MetaDataGenerator.doPkgMetadata(self, directories)
            return
        filematrix = {}
        for mydir in directories:
            filematrix[mydir] = self.getFileList(os.path.join(self.initialdir, mydir), '.', '.rpm', [])
            self.trimRpms(filematrix[mydir])
            self.pkgcount += len(filematrix[mydir])

        mediano = 1
        current = 0
        self.cmds['baseurl'] = self._getFragmentUrl(self.cmds['baseurl'], mediano)
        self.cmds['basedir'] = os.path.join(self.initialdir, directories[0])
        self.openMetadataDocs()
        for mydir in directories:
            self.cmds['basedir'] = os.path.join(self.initialdir, mydir)
            self.cmds['baseurl'] = self._getFragmentUrl(self.cmds['baseurl'], mediano)
            current = self.writeMetadataDocs(filematrix[mydir], current)
            mediano += 1
        self.cmds['basedir'] = os.path.join(self.initialdir, directories[0])
        self.cmds['baseurl'] = self._getFragmentUrl(self.cmds['baseurl'], 1)
        self.closeMetadataDocs()


def checkAndMakeDir(dir):
    """
     check out the dir and make it, if possible, return 1 if done, else return 0
    """
    if os.path.exists(dir):
        if not os.path.isdir(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)
                result = False
            else:
                result = True
    else:
        try:
            os.mkdir(dir)
        except OSError, e:
            errorprint(_('Error creating dir %s: %s') % (dir, e))
            result = False
        else:
            result = True
    return result

def parseArgs(args):
    """
       Parse the command line args return a commands dict and directory.
       Sanity check all the things being passed in.
    """
    cmds = {}
    cmds['quiet'] = 0
    cmds['verbose'] = 0
    cmds['excludes'] = []
    cmds['baseurl'] = None
    cmds['groupfile'] = None
    cmds['sumtype'] = 'sha'
    cmds['pretty'] = 0
#    cmds['updategroupsonly'] = 0
    cmds['cachedir'] = None
    cmds['basedir'] = os.getcwd()
    cmds['cache'] = False
    cmds['split'] = False
    cmds['outputdir'] = ""
    cmds['file-pattern-match'] = ['.*bin\/.*', '^\/etc\/.*', '^\/usr\/lib\/sendmail$']
    cmds['dir-pattern-match'] = ['.*bin\/.*', '^\/etc\/.*']

    try:
        gopts, argsleft = getopt.getopt(args, 'phqVvg:s:x:u:c:U:o:', ['help', 'exclude=',
                                                                  'quiet', 'verbose', 'cachedir=', 'basedir=',
                                                                  'baseurl=', 'groupfile=', 'checksum=',
                                                                  'version', 'pretty', 'split', 'outputdir=',
                                                                  'update-info-location='])
    except getopt.error, e:
        errorprint(_('Options Error: %s.') % e)
        usage()

    try:
        for arg,a in gopts:
            if arg in ['-h','--help']:
                usage(retval=0)
            elif arg in ['-V', '--version']:
                print '%s' % __version__
                sys.exit(0)
            elif arg == '--split':
                cmds['split'] = True
    except ValueError, e:
        errorprint(_('Options Error: %s') % e)
        usage()


    # make sure our dir makes sense before we continue
    if len(argsleft) > 1 and not cmds['split']:
        errorprint(_('Error: Only one directory allowed per run.'))
        usage()
    elif len(argsleft) == 0:
        errorprint(_('Error: Must specify a directory to index.'))
        usage()
    else:
        directories = argsleft

    try:
        for arg,a in gopts:
            if arg in ['-v', '--verbose']:
                cmds['verbose'] = 1
            elif arg in ["-q", '--quiet']:
                cmds['quiet'] = 1
            elif arg in ['-u', '--baseurl']:
                if cmds['baseurl'] is not None:
                    errorprint(_('Error: Only one baseurl allowed.'))
                    usage()
                else:
                    cmds['baseurl'] = a
            elif arg in ['-g', '--groupfile']:
                if cmds['groupfile'] is not None:
                    errorprint(_('Error: Only one groupfile allowed.'))
                    usage()
                else:
                    cmds['groupfile'] = a
            elif arg in ['-x', '--exclude']:
                cmds['excludes'].append(a)
            elif arg in ['-p', '--pretty']:
                cmds['pretty'] = 1
#            elif arg in ['--update-groups-only']:
#                cmds['updategroupsonly'] = 1
            elif arg in ['-s', '--checksum']:
                errorprint(_('This option is deprecated'))
            elif arg in ['-c', '--cachedir']:
                cmds['cache'] = True
                cmds['cachedir'] = a
            elif arg in ['-U', '--update-info-location']:
                cmds['update-info-location'] = a
            elif arg == '--basedir':
                cmds['basedir'] = a
            elif arg in ['-o','--outputdir']:
                cmds['outputdir'] = a
                    
    except ValueError, e:
        errorprint(_('Options Error: %s') % e)
        usage()

    directory = directories[0]
# Fix paths
    directory = os.path.normpath(directory)
    if cmds['split']:
        pass
    elif os.path.isabs(directory):
        cmds['basedir'] = directory
        directory = '.'
    else:
        cmds['basedir'] = os.path.realpath(os.path.join(cmds['basedir'], directory))
        directory = '.'
    if not cmds['outputdir']:
        cmds['outputdir'] = cmds['basedir']
    if cmds['groupfile']:
        a = cmds['groupfile']
        if cmds['split']:
            a = os.path.join(cmds['basedir'], directory, cmds['groupfile'])
        elif not os.path.isabs(a):
            a = os.path.join(cmds['basedir'], cmds['groupfile'])
        if not os.path.exists(a):
            errorprint(_('Error: groupfile %s cannot be found.' % a))
            usage()
        cmds['groupfile'] = a
    if cmds['cachedir']:
        a = cmds ['cachedir']
        if not os.path.isabs(a):
            a = os.path.join(cmds['basedir'] ,a)
        if not checkAndMakeDir(a):
            errorprint(_('Error: cannot open/write to cache dir %s' % a))
            usage()
        cmds['cachedir'] = a

    #setup some defaults
    cmds['primaryfile'] = 'primary.xml.gz'
    cmds['filelistsfile'] = 'filelists.xml.gz'
    cmds['otherfile'] = 'other.xml.gz'
    cmds['repomdfile'] = 'repomd.xml'
    cmds['tempdir'] = '.repodata'
    cmds['finaldir'] = 'repodata'
    cmds['olddir'] = '.olddata'
    cmds['update-info-dir'] = 'update-info'

    # Fixup first directory
    directories[0] = directory
    return cmds, directories

def main(args):
    cmds, directories = parseArgs(args)
    directory = directories[0]
    # start the sanity/stupidity checks
    if not os.path.exists(os.path.join(cmds['basedir'], directory)):
        errorprint(_('Directory must exist'))
        sys.exit(1)

    if not os.path.isdir(os.path.join(cmds['basedir'], directory)):
        errorprint(_('Directory of packages must be a directory.'))
        sys.exit(1)

    if not os.access(cmds['outputdir'], os.W_OK):
        errorprint(_('Directory must be writable.'))
        sys.exit(1)

    if cmds['split']:
        oldbase = cmds['basedir']
        cmds['basedir'] = os.path.join(cmds['basedir'], directory)
    if not checkAndMakeDir(os.path.join(cmds['outputdir'], cmds['tempdir'])):
        sys.exit(1)

    if not checkAndMakeDir(os.path.join(cmds['outputdir'], cmds['finaldir'])):
        sys.exit(1)

    if os.path.exists(os.path.join(cmds['outputdir'], cmds['olddir'])):
        errorprint(_('Old data directory exists, please remove: %s') % cmds['olddir'])
        sys.exit(1)

    if cmds.has_key('update-info-location'):
        if not checkAndMakeDir(os.path.join(cmds['basedir'],
                               cmds['tempdir'], cmds['update-info-dir'])):
            errorprint(_('Error: cannot open/write to update info dir %s' % a))
            usage()

    # make sure we can write to where we want to write to:
    for direc in ['tempdir', 'finaldir']:
        for file in ['primaryfile', 'filelistsfile', 'otherfile', 'repomdfile']:
            filepath = os.path.join(cmds['outputdir'], cmds[direc], cmds[file])
            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 cmds['split']:
        cmds['basedir'] = oldbase
        mdgen = SplitMetaDataGenerator(cmds)
        mdgen.doPkgMetadata(directories)
    else:
        mdgen = MetaDataGenerator(cmds)
        mdgen.doPkgMetadata(directory)
    mdgen.doRepoMetadata()

    if os.path.exists(os.path.join(cmds['outputdir'], cmds['finaldir'])):
        try:
            os.rename(os.path.join(cmds['outputdir'], cmds['finaldir']),
                      os.path.join(cmds['outputdir'], cmds['olddir']))
        except:
            errorprint(_('Error moving final %s to old dir %s' % (os.path.join(cmds['outputdir'], cmds['finaldir']),
                                                                  os.path.join(cmds['outputdir'], cmds['olddir']))))
            sys.exit(1)

    try:
        os.rename(os.path.join(cmds['outputdir'], cmds['tempdir']),
                  os.path.join(cmds['outputdir'], cmds['finaldir']))
    except:
        errorprint(_('Error moving final metadata into place'))
        # put the old stuff back
        os.rename(os.path.join(cmds['outputdir'], cmds['olddir']),
                  os.path.join(cmds['outputdir'], cmds['finaldir']))
        sys.exit(1)

    for file in ['primaryfile', 'filelistsfile', 'otherfile', 'repomdfile', 'groupfile']:
        if cmds[file]:
            fn = os.path.basename(cmds[file])
        else:
            continue
        oldfile = os.path.join(cmds['outputdir'], cmds['olddir'], 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)

    # Clean up any update metadata
    mdpath = os.path.join(cmds['basedir'], cmds['olddir'], cmds['update-info-dir'])
    if os.path.isdir(mdpath):
        for file in os.listdir(mdpath):
            os.remove(os.path.join(mdpath, file))
        os.rmdir(mdpath)


#XXX: fix to remove tree as we mung basedir
    try:
        os.rmdir(os.path.join(cmds['outputdir'], cmds['olddir']))
    except OSError, e:
        errorprint(_('Could not remove old metadata dir: %s') % cmds['olddir'])
        errorprint(_('Error was %s') % e)
        errorprint(_('Please clean up this directory manually.'))

if __name__ == "__main__":
    if len(sys.argv) > 1:
        if sys.argv[1] == 'profile':
            import hotshot
            p = hotshot.Profile(os.path.expanduser("~/createrepo.prof"))
            p.run('main(sys.argv[2:])')
            p.close()
        else:
            main(sys.argv[1:])
    else:
        main(sys.argv[1:])
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.