#!/usr/bin/env python # # shipper -- a tool for shipping software import sys, os, readline, re, commands, time, glob, optparse, stat # # State variables # destinations = [] # List of remote directories to update channels = ['ibiblio', 'redhat', 'freshmeat'] whoami = None # Who am I? (Used for FTP logins) date = None # User has not yet set a date package = None # Nor a package name homepage = None # Nor a home page arch = None # The machine architecture keywords = None # Keywords for LSMs freshmeat_name = None # Name of the project ob Freshmeat changelog = None # Project changelog lastchange = None # Last entry in changelog summary = None # One-line summary of the package description = None # Nor a description indextemplate = """ Resource page for %(package)s %(version)s

Resource page for %(package)s %(version)s

%(description)s


%(resourcetable)s

Last modified %(date)s.

""" mailtemplate = """Subject: Announcing release %(version)s of %(package)s Release %(version)s of %(package)s is now available at: %(homepage)s Here are the most recent changes: %(lastchange)s -- shipper, acting for %(whoami)s """ # It's unpleasant that we have to include these here, but # the freshmeat release focus has to be validated even if the # user is offline and the XML-RPC service not accessible. freshmeat_focus_types = ( "N/A", "Initial freshmeat announcement", "Documentation", "Code cleanup", "Minor feature enhancements", "Major feature enhancements", "Minor bugfixes", "Major bugfixes", "Minor security fixes", "Major security fixes", ) def croak(msg): sys.stderr.write("shipper: " + msg + "\n") sys.exit(1) # # Shipping methods # def do_or_die(cmd): "Wither execute a command or fail noisily" if options.verbose: print "***", cmd if os.system(cmd): croak("command '%s' failed!" % cmd) def upload_or_die(cmd): if options.noupload: print cmd else: do_or_die(cmd) def upload(destination, files): # Upload a file via ftp or sftp, handles print "# Uploading to %s" % destination files = filter(os.path.exists, files) if destination.startswith("ftp://"): destination = destination[6:].split("/") host = destination.pop(0) directory = "/".join(destination) commands = ["lftp", "open -u anonymous," + whoami + " " + host + "\n"] if directory: commands.append("cd " + directory + "\n") commands.append("mput " + " ".join(files) + "\n") commands.append("close\n") if options.noupload: print "".join(commands) else: pfp = os.popen(commands.pop(0), "w") pfp.writelines(commands) pfp.close() elif destination.find("::") > -1: upload_or_die("rsync " + " ".join(files) + " " + destination) elif destination.find(":") > -1: (host, directory) = destination.split(":") for file in files: # This is a really ugly way to deal with the problem # of write-protected files in the remote directory. # Unfortunately, sftp(1) is rather brain-dead -- no # way to ignore failure on a remove, and refuses to # do renames with an obscure error message. remote = os.path.join(directory, package, file) upload_or_die("scp " + file + " " + host + ":" + remote+".new;") upload_or_die("ssh %s 'mv -f %s.new %s'" % (host, remote, remote)) else: sys.stderr.write("Don't know what to do with destination %s!") def freshmeat_ship(manifest): "Ship a specified update to freshmeat." if options.verbose: print "Announcing to freshmeat..." upload_or_die("freshmeat-submit <" + manifest[0]) # # Metadata extraction # def grep(pattern, file): "Mine for a specified pattern in a file." fp = open(file) try: while True: line = fp.readline() if not line: return None m = re.search(pattern, line) if m: return m.group(1) finally: fp.close() return None class Specfile: def __init__(self, filename): self.filename = filename self.type = None
#!/bin/sh
#
#  Build RPMs from the source in the current directory.  This script sets
#  up an RPM "_topdir" and builds the RPMs under there, then copies the
#  binary and source RPMs to the current directory.
#
#  Written by Sean Reifschneider <jafo-rpms@tummy.com>, 2003

TARBALL=$1		#  tarball to build from

#  set up temporary directory
TMPDIR=`pwd`/rpm-build.$$
[ ! -z "$TMPDIR" -a "$TMPDIR" != / ] && rm -rf "$TMPDIR"
mkdir -p "$TMPDIR"/BUILD
mkdir -p "$TMPDIR"/RPMS
mkdir -p "$TMPDIR"/SOURCES
mkdir -p "$TMPDIR"/SPECS
mkdir -p "$TMPDIR"/SRPMS

#  set up rpmmacros file
MACROFILE="$TMPDIR"/rpmmacros
RCFILE="$TMPDIR"/rpmrc
sed "s|~/.rpmmacros|$MACROFILE|" /usr/lib/rpm/rpmrc >"$RCFILE"
echo "%_topdir $TMPDIR" >"$MACROFILE"
echo "%_topdir $TMPDIR" >"$MACROFILE"

ARCH=--target=$(uname -m)

#  build RPMs
rpmbuild --rcfile "$RCFILE" $ARCH -ta $TARBALL \
|| rpm --rcfile "$RCFILE" $ARCH -ta $TARBALL
status=$?

if [ $status = '0' ]
then
    # move RPMs to this directory
    mv "$TMPDIR"/RPMS/*/*.rpm .
    mv "$TMPDIR"/SRPMS/*.rpm .
fi

#  clean up build directory
[ ! -z "$TMPDIR" -a "$TMPDIR" != / ] && rm -rf "$TMPDIR"

exit $status
delete_at_end.append("index.html") # Next the CHANGES file. Build this only if (a) there is no ChangeLog, # and (b) there is a specfile %changelog. if not os.path.exists("ChangeLog") and \ (options.force or not os.path.exists("CHANGES")) and changelog: print "# Building CHANGES..." ofp = open("CHANGES", "w") ofp.write(" Changelog for " + package + "\n\n") ofp.write(changelog) ofp.close() delete_at_end.append("CHANGES") # The freshmeat announcement if 'freshmeat' in channels \ and options.force or not os.path.exists("ANNOUNCE.FRESHMEAT"): print "# Building ANNOUNCE.FRESHMEAT..." if not homepage: print "# Can't announce to freshmeat without a primary website!" elif not lastchange: print "# Can't announce to freshmeat without a changes field!" else: while True: focus = raw_input("# freshmeat.net release focus (? for list): ") if focus == '?': i = 0 for f in freshmeat_focus_types: print "%d: %s" % (i, f) i += 1 elif focus in "0123456789": print "# OK:", freshmeat_focus_types[int(focus)] break elif focus.lower() in map(lambda x: x.lower(), freshmeat_focus_types): break else: croak("not a valid freshmeat.net release focus!") ofp = open("ANNOUNCE.FRESHMEAT", "w") ofp.write("Project: %s\n"%(freshmeat_name or package)) ofp.write("Version: %s\n"% version) ofp.write("Release-Focus: %s\n" % focus) ofp.write("Home-Page-URL: %s\n" % homepage) if os.path.exists(tarball): ofp.write("Gzipped-Tar-URL: %s\n" % os.path.join(homepage,tarball)) if os.path.exists(zip): ofp.write("Zipped-Tar-URL: %s\n" % os.path.join(homepage, zip)) if os.path.exists("CHANGES"): ofp.write("Changelog-URL: %s\n" % os.path.join(homepage, "CHANGES")) if os.path.exists(binrpm): ofp.write("RPM-URL: %s\n" % os.path.join(homepage, binrpm)) # freshmeat.net doesn't like bulleted entries. freshmeatlog = lastchange[2:].replace("\n ", "\n") ofp.write("\n" + freshmeatlog) ofp.close() delete_at_end.append("ANNOUNCE.FRESHMEAT") # Finally, email notification if filter(lambda x: x.startswith("mailto:"), destinations) \ and (options.force or not os.path.exists("ANNOUNCE.EMAIL")): print "# Building ANNOUNCE.EMAIL..." ofp = open("ANNOUNCE.EMAIL", "w") ofp.write(mailtemplate % globals()) ofp.close() delete_at_end.append("ANNOUNCE.FRESHMEAT") # # Now actually ship # # Shipping methods, locations, and deliverables for public channels. hardwired = { 'freshmeat' : (lambda: freshmeat_ship(("ANNOUNCE.FRESHMEAT",))), 'ibiblio' : (lambda: upload("ftp://ibiblio.org/incoming/linux", (tarball, binrpm, srcrpm, lsm))), 'redhat' : (lambda: upload("ftp://incoming.redhat.com/libc6", (tarball, binrpm, srcrpm))), } # First ship to private channels. Order is important here, we # need to hit the user's primary website first so everything # will be in place when announcements are generated. for destination in destinations: if destination.startswith("ftp:"): upload(destination, (tarball, binrpm, srcrpm,)) elif destination.startswith("mailto:"): print "# Mailing to %s" % destination command = "sendmail -i -oem -f %s %s