Index: head/Tools/scripts/checkcats.py =================================================================== --- head/Tools/scripts/checkcats.py (revision 486556) +++ head/Tools/scripts/checkcats.py (revision 486557) @@ -1,42 +1,42 @@ #!/usr/bin/env python # # checkcats.py - verify that master categories in all ports are correct and # report any problems. # # ---------------------------------------------------------------------------- # "THE BEER-WARE LICENSE" (Revision 42, (c) Poul-Henning Kamp): # Maxim Sobolev wrote this file. As long as you retain # this notice you can do whatever you want with this stuff. If we meet some # day, and you think this stuff is worth it, you can buy me a beer in return. # # Maxim Sobolev # ---------------------------------------------------------------------------- # # $FreeBSD$ # -# MAINTAINER= sobomax@FreeBSD.org <- any unapproved commits to this file are +# MAINTAINER= portmgr@FreeBSD.org <- any unapproved commits to this file are # highly discouraged!!! # import glob, os.path import patchtool from patchtool import True, False PORTSDIR = '/usr/ports' if __name__ == '__main__': portdirs = glob.glob(os.path.join(PORTSDIR, '*/*')) for dirname in portdirs: if not os.path.isfile(os.path.join(dirname, 'Makefile')): continue categories = patchtool.querymakevar('CATEGORIES', dirname) try: mastercat = categories.split()[0] except IndexError: print '%s: categories list is empty' % dirname continue mastercat_real = os.path.basename(os.path.dirname(dirname)) if mastercat != mastercat_real: print '%s: specified master category `%s\' doesn\'t match real one `%s\'' \ % (dirname, mastercat, mastercat_real) Index: head/Tools/scripts/checknewver.sh =================================================================== --- head/Tools/scripts/checknewver.sh (revision 486556) +++ head/Tools/scripts/checknewver.sh (revision 486557) @@ -1,108 +1,108 @@ #!/bin/sh # # checknewver # Check for availability of the newest distfiles # # ---------------------------------------------------------------------------- # "THE BEER-WARE LICENSE" (Revision 42, (c) Poul-Henning Kamp): # Maxim Sobolev wrote this file. As long as you retain # this notice you can do whatever you want with this stuff. If we meet some # day, and you think this stuff is worth it, you can buy me a beer in return. # # Maxim Sobolev # ---------------------------------------------------------------------------- # # $FreeBSD$ # -# MAINTAINER= sobomax@FreeBSD.org +# MAINTAINER= ports@FreeBSD.org display_warn () { if [ x"${SILENT}" != x"yes" ]; then echo "WARN: ${@}" >&2 fi } display_err () { if [ x"${SILENT}" != x"yes" ]; then echo "ERROR: ${@}" >&2 fi exit 1 } display_msg () { if [ x"${SILENT}" != x"yes" ]; then echo "${@}" >&2 fi } while getopts "s" COMMAND_LINE_ARGUMENT ; do case "${COMMAND_LINE_ARGUMENT}" in s) SILENT=yes ;; esac done if [ x`which ftpls` = x"" ]; then display_err "Couldn't find ftpls program, which is part of" \ "ports/ftp/ftpcopy port. Please make sure that it is installed" \ "and try again." fi if [ ! -e Makefile ]; then display_err "Couldn't find Makefile here." fi PORTNAME=`make -V PORTNAME 2>/dev/null` PORTVERSION=`make -V PORTVERSION 2>/dev/null` DISTFILES=`make -V DISTFILES 2>/dev/null` if [ x"${PORTNAME}" = x"" -o x"${PORTVERSION}" = x"" -o x"${DISTFILES}" = x"" ]; then display_err "Either PORTNAME, PORTVERSION or DISTFILES is undefined in Makefile." fi MASTER_SITES=`env MASTER_SITE_BACKUP=\"\" make master-sites-all 2>/dev/null | xargs -n1 echo | grep ^ftp://` if [ x"${MASTER_SITES}" = x"" ]; then display_err "Either MASTER_SITES is undefined in Makefile or it doesn't contain any ftp sites." fi display_msg "Checking for updated version of ${PORTNAME}..." PV_PATR=`echo ${PORTVERSION} | sed 's=\.=\\\\.=g'` for DISTNAME in ${DISTFILES}; do DF_PATR=`echo ${DISTNAME} | sed "s=${PV_PATR}=.*=" | \ sed 's=\.=\\\\.=g ; s=\\\.\*=.*='` DF_CHECK=`echo ${DISTNAME} | sed 's=\.=\\\\.=g'` if [ x"${DF_PATR}" = x"${DF_CHECK}" ]; then display_warn "Couldn't construct searching pattern - ${DISTNAME} ignored." else DF_PATRNS="${DF_PATRNS} ${DF_PATR}" F_DISTFILES="${F_DISTFILES} ${DISTNAME}" fi done if [ x"${F_DISTFILES}" = x"" ]; then display_warn "Nothing to check - exiting." exit 0 fi DISTFILES="${F_DISTFILES}" for MASTER_SITE in ${MASTER_SITES}; do display_msg "...checking ${MASTER_SITE}" FTPLIST=`ftpls ${MASTER_SITE} 2>/dev/null | grep -v ^dir | awk '{print $6}'` for DISTNAME in ${DISTFILES}; do DF_PATR=`echo ${DISTNAME} | sed "s=${PV_PATR}=.*=" | \ sed 's=\.=\\\\.=g ; s=\\\.\*=.*='` for i in `echo ${FTPLIST} | xargs -n1 echo | grep "${DF_PATR}$"` ; do if [ "${i}" ">" "${DISTNAME}" ]; then NEW="${NEW} ${MASTER_SITE}${i}" fi done done done if [ x"${NEW}" != x"" ]; then display_msg "" display_msg "Hmm, is seems that there is a newer version(s) at:" echo "${NEW}" | xargs -n1 echo display_msg "" fi Index: head/Tools/scripts/distclean.sh =================================================================== --- head/Tools/scripts/distclean.sh (revision 486556) +++ head/Tools/scripts/distclean.sh (revision 486557) @@ -1,85 +1,83 @@ #!/bin/sh # # distclean # Compare distfiles in /usr/ports/distfiles # with currently instaled ports collection # and removes outdated files # # ---------------------------------------------------------------------------- # "THE BEER-WARE LICENSE" (Revision 42, (c) Poul-Henning Kamp): # Maxim Sobolev wrote this file. As long as you retain # this notice you can do whatever you want with this stuff. If we meet some # day, and you think this stuff is worth it, you can buy me a beer in return. # # Maxim Sobolev # ---------------------------------------------------------------------------- # # $FreeBSD: /tmp/pcvs/ports/Tools/scripts/distclean.sh,v 1.18 2010-11-18 11:28:05 pav Exp $ # -# MAINTAINER= sobomax@FreeBSD.org +# MAINTAINER= ports@FreeBSD.org PATH=/sbin:/bin:/usr/bin cleanup() { rm -f $FN_RESULTS_SCRIPT $FN_PORTS $FN_DISTFILES echo "Terminated." exit 1 } - -echo "Distfiles clean utility by Maxim Sobolev ." PORTSDIR=${PORTSDIR:-/usr/ports} if [ ! -d ${PORTSDIR} ]; then echo "Ports directory ${PORTSDIR} does not exist." exit 1 fi DISTDIR=`(make -V DISTDIR -f ${PORTSDIR}/Mk/bsd.port.mk) 2>/dev/null` DISTDIR=${DISTDIR:-/usr/ports/distfiles} echo "Assumes that your ports are in ${PORTSDIR} and distfiles in ${DISTDIR}." echo "" if [ x"$1" = x"-f" ]; then RM_FLAG="-f" else RM_FLAG="-i" echo "Use \"`basename $0` -f\" to remove the files without prompting for confirmation." echo "" fi umask 077 FN_PORTS=`mktemp -t dclean` || exit 1 FN_DISTFILES=`mktemp -t dclean` || exit 1 FN_RESULTS_SCRIPT=`mktemp -t dclean` || exit 1 trap cleanup 1 2 3 4 5 6 7 8 10 11 12 13 14 15 16 21 22 23 24 25 26 27 28 \ 30 31 echo -n "Building ports sha256 index..." find ${PORTSDIR}/ \ \( -name "distinfo" -or -name "distinfo.i386" -or -name "distinfo.alpha" \) \ -type f -mindepth 3 -maxdepth 3 | \ xargs cat | grep '^SHA256 ('| sort -u > $FN_PORTS echo "Done." P_SHA256_COUNT=`wc -l $FN_PORTS | sed "s| $FN_PORTS|| ; s| ||g"` echo "Found $P_SHA256_COUNT sha256 entries in your ports directory." echo -n "Building distfiles sha256 index..." find ${DISTDIR}/ -type f | xargs sha256 | sed 's|'${DISTDIR}'/||' | sort > $FN_DISTFILES echo "Done." D_SHA256_COUNT=`wc -l $FN_DISTFILES | sed "s| $FN_DISTFILES|| ; s| ||g"` echo "Found $D_SHA256_COUNT distfile(s) in your distfiles directory." echo -n "Comparing results..." diff -d $FN_DISTFILES $FN_PORTS | grep "^<" | sed 's|.*(|rm '$RM_FLAG' '${DISTDIR}'/| ; s|).*||' > $FN_RESULTS_SCRIPT echo "Done." R_SHA256_COUNT=`wc -l $FN_RESULTS_SCRIPT | sed "s| $FN_RESULTS_SCRIPT|| ; s| ||g"` echo "$R_SHA256_COUNT distfile(s) doesn't have corresponding sha256 entries in ports directory." /bin/sh $FN_RESULTS_SCRIPT find ${DISTDIR}/ -type d -empty -delete echo -n "Finishing..." rm -f $FN_RESULTS_SCRIPT $FN_PORTS $FN_DISTFILES echo "Done." Index: head/Tools/scripts/gnomedepends.py =================================================================== --- head/Tools/scripts/gnomedepends.py (revision 486556) +++ head/Tools/scripts/gnomedepends.py (revision 486557) @@ -1,128 +1,128 @@ #!/usr/bin/env python # # gnomedepends # Analyse pkg/PLIST and give an advice as to which GNOME # ports should be listes in {RUN,LIB}_DEPENDS for this port # # ---------------------------------------------------------------------------- # "THE BEER-WARE LICENSE" (Revision 42, (c) Poul-Henning Kamp): # Maxim Sobolev wrote this file. As long as you retain # this notice you can do whatever you want with this stuff. If we meet some # day, and you think this stuff is worth it, you can buy me a beer in return. # # Maxim Sobolev # ---------------------------------------------------------------------------- # # $FreeBSD$ # -# MAINTAINER= sobomax@FreeBSD.org +# MAINTAINER= gnome@FreeBSD.org # # TODO: # - analyse actual {RUN,LIB}_DEPENDS and give an advice about what should be # added; # - analyse results and remove redundant dependencies (for example if gnomecore # has gnomecontrolcenter listed as dependency, and it is found that the port # requires both gnomecontrolcenter and gnomecore do not list # gnomecontrolcenter then); # - parse ports/INDEX directly. # import os, os.path, sys, string, re def getcmdout(cmdline): results = [] pipe = os.popen(cmdline) buffer = pipe.readlines() for result in buffer: result = string.strip(result) if len(result) > 0: results.append(result) pipe.close() return results def readfile(filename): file = open(filename) result = file.readlines() file.close() return result def filter(lines, regobj): results = [] for line in lines: match = regobj.match(line) if match != None: result = string.strip(match.group(1)) try: tmp = results.index(result) except ValueError: results.append(result) return results gnomeports = getcmdout('cd /usr/ports && make search key=gnome | grep ^Path:') newgnomeports = [] for i in gnomeports: newgnomeports.append(string.split(i)[1]) gnomeports = newgnomeports newgnomeports = [] regobj = re.compile('^@dirrm (?P\S+).*$') for portdir in gnomeports: try: lines = readfile(os.path.join(portdir, 'pkg-plist')) lines = list(filter(lines, regobj)) if len(lines) > 0: newgnomeports.append([portdir, lines]) except IOError: pass gnomeports = newgnomeports newgnomeports = [] try: currplist = readfile('pkg-plist') except IOError as errmsg: print(errmsg) sys.exit(1) regobj = re.compile('^(?!@)(?P\S+)/.*') currdirs = list(filter(currplist, regobj)) regobj = re.compile('^@dirrm (?P\S+).*$') currdirs.extend(list(filter(currplist, regobj))) currportdir = os.getcwd() newcurrdirs = [] for dir in currdirs: incremental = '' for component in string.split(dir, '/'): if incremental != '': incremental = incremental + '/' incremental = incremental + component try: tmp = newcurrdirs.index(incremental) except ValueError: newcurrdirs.append(incremental) currdirs = newcurrdirs depends = [] for gnomeport in gnomeports: if (currportdir == gnomeport[0]): continue matches = [] for gnomedir in gnomeport[1]: for dir in currdirs: if (gnomedir == dir): matches.append(dir) if len(matches) > 0: depends.append([gnomeport[0], matches]) if len(depends) == 0: sys.stdout.writelines(['No dependencies found (maybe it is not a GNOME port).\n']) sys.exit(0) sys.stdout.writelines(['According to the contents of pkg-plist the port depends on the following GNOME\n', 'port(s):\n\n']) for depend in depends: sys.stdout.writelines([depend[0], ', for directories:\n']) for dir in depend[1]: sys.stdout.writelines(['\t', dir, '\n']) sys.stdout.writelines(['\n']) Index: head/Tools/scripts/patchtool.py =================================================================== --- head/Tools/scripts/patchtool.py (revision 486556) +++ head/Tools/scripts/patchtool.py (revision 486557) @@ -1,685 +1,685 @@ #!/usr/bin/env python # ex:ts=4 #-*- mode: Fundamental; tab-width: 4; -*- # # patchtool.py - a tool to automate common operation with patchfiles in the # FreeBSD Ports Collection. # # ---------------------------------------------------------------------------- # "THE BEER-WARE LICENSE" (Revision 42, (c) Poul-Henning Kamp): # Maxim Sobolev wrote this file. As long as you retain # this notice you can do whatever you want with this stuff. If we meet some # day, and you think this stuff is worth it, you can buy me a beer in return. # # Maxim Sobolev # ---------------------------------------------------------------------------- # # $FreeBSD$ # -# MAINTAINER= sobomax@FreeBSD.org <- any unapproved commits to this file are +# MAINTAINER= ports@FreeBSD.org <- any unapproved commits to this file are # highly discouraged!!! # import os, os.path, subprocess, sys, getopt, glob, errno, types # Some global variables used as constants True = 1 False = 0 # Tweakable global variables. User is able to override any of these by setting # appropriate environment variable prefixed by `PT_', eg: # $ export PT_CVS_ID="FooOS" # $ export PT_DIFF_CMD="/usr/local/bin/mydiff" # will force script to use "FooOS" as a CVS_ID instead of "FreeBSD" and # "/usr/local/bin/mydiff" as a command to generate diffs. class Vars: CVS_ID = 'FreeBSD' DIFF_ARGS = '-du' DIFF_SUFX = '.orig' PATCH_PREFIX = 'patch-' PATCH_IGN_SUFX = ('.orig', '.rej') RCSDIFF_SUFX = ',v' CD_CMD = 'cd' DIFF_CMD = '/usr/bin/diff' MAKE_CMD = '/usr/bin/make' PRINTF_CMD = '/usr/bin/printf' RCSDIFF_CMD = '/usr/bin/rcsdiff' DEFAULT_MAKEFILE = 'Makefile' DEV_NULL = '/dev/null' ETC_MAKE_CONF = '/etc/make.conf' SLASH_REPL_SYMBOL = '_' # The symbol to replace '/' when auto-generating # patchnames # # Check if the supplied patch refers to a port's directory. # def isportdir(path, soft = False): REQ_FILES = ('Makefile', 'pkg-descr', 'distinfo') if not os.path.isdir(path) and soft != True: raise IOError(errno.ENOENT, path) # Not reached # try: content = os.listdir(path) except OSError: return False for file in REQ_FILES: if file not in content: return False return True # # Traverse directory tree up from the path pointed by argument and return if # root directory of a port is found. # def locateportdir(path, wrkdirprefix= '', strict = False): # Flag to relax error checking in isportdir() function. It required when # WRKDIRPREFIX is defined. softisport = False path = os.path.abspath(path) if wrkdirprefix != '': wrkdirprefix= os.path.abspath(wrkdirprefix) commonprefix = os.path.commonprefix((path, wrkdirprefix)) if commonprefix != wrkdirprefix: return '' path = path[len(wrkdirprefix):] softisport = True while path != '/': if isportdir(path, softisport) == True: return path path = os.path.abspath(os.path.join(path, '..')) if strict == True: raise LocatePDirError(path) # Not reached # else: return '' # # Get value of a make(1) variable called varname. Optionally maintain a cache # for resolved varname:makepath pairs to speed-up operation if the same variable # from the exactly same file is requested repeatedly (invocation of make(1) is # very expensive operation...) # def querymakevar(varname, path = 'Makefile', strict = False, cache = {}): path = os.path.abspath(path) if cache.has_key((varname, path)) == 1: return cache[(varname, path)] origpath = path if os.path.isdir(path): path = os.path.join(path, Vars.DEFAULT_MAKEFILE) if not os.path.isfile(path): raise IOError(errno.ENOENT, path) # Not reached # dir = os.path.dirname(path) CMDLINE = '%s %s && %s -f %s -V %s' % (Vars.CD_CMD, dir, Vars.MAKE_CMD, \ path, varname) devnull = open('/dev/null', 'a') pipe = subprocess.Popen(CMDLINE, shell = True, stdin = subprocess.PIPE, \ stdout = subprocess.PIPE, stderr = devnull, close_fds = True) retval = '' for line in pipe.stdout.readlines(): retval = retval + line.strip() + ' ' retval = retval[:-1] if strict == True and retval.strip() == '': raise MakeVarError(path, varname) # Not reached # cache[(varname, origpath)] = retval return retval # # Get a path of `path' relatively to wrksrc. For example: # path: /foo/bar # wrksrc: /foo/bar/baz/somefile.c # getrelpath: baz/somefile.c # Most of the code here is to handle cases when ../ operation is required to # reach wrksrc from path, for example: # path: /foo/bar # wrksrc: /foo/baz/somefile.c # getrelpath: ../baz/somefile.c # def getrelpath(path, wrksrc): path = os.path.abspath(path) wrksrc = os.path.abspath(wrksrc) + '/' commonpart = os.path.commonprefix((path, wrksrc)) while commonpart[-1:] != '/': commonpart = commonpart[:-1] path = path[len(commonpart):] wrksrc = wrksrc[len(commonpart):] adjust = '' while os.path.normpath(os.path.join(wrksrc, adjust)) != '.': adjust = os.path.join(adjust, '..') relpath = os.path.join(adjust, path) return relpath # # Generate a diff between saved and current versions of the file pointed by the # wrksrc+path. Apply heuristics to locate saved version of the file in question # and if it fails assume that file is new, so /dev/null is to be used as # original file. Optionally save generated patch into `outfile' instead of # dumping it to stdout. Generated patches automatically being tagged with # "FreeBSD" cvs id. # def gendiff(path, wrksrc, outfile = ''): fullpath = os.path.join(wrksrc, path) if not os.path.isfile(fullpath): raise IOError(errno.ENOENT, fullpath) # Not reached # cmdline = '' if os.path.isfile(fullpath + Vars.DIFF_SUFX): # Normal diff path_orig = path + Vars.DIFF_SUFX cmdline = '%s %s %s %s' % (Vars.DIFF_CMD, Vars.DIFF_ARGS, path_orig, path) elif os.path.isfile(fullpath + Vars.RCSDIFF_SUFX): # RCS diff path_orig = path cmdline = '%s %s %s' % (Vars.RCSDIFF_CMD, Vars.DIFF_ARGS, path) else: # New file path_orig = Vars.DEV_NULL cmdline = '%s %s %s %s' % (Vars.DIFF_CMD, Vars.DIFF_ARGS, path_orig, path) savedir = os.getcwd() os.chdir(wrksrc) devnull = open('/dev/null', 'a') pipe = subprocess.Popen(cmdline, shell = True, stdin = subprocess.PIPE, \ stdout = subprocess.PIPE, stderr = devnull, close_fds = True) outbuf = pipe.stdout.readlines() exitval = pipe.wait() if exitval == 0: # No differences were found retval = False retmsg = 'no differences found between original and current ' \ 'version of "%s"' % fullpath elif exitval == 1: # Some differences were found if (outfile != ''): outbuf[0] = '--- %s\n' % path_orig outbuf[1] = '+++ %s\n' % path open(outfile, 'w').writelines(outbuf) else: sys.stdout.writelines(outbuf) retval = True retmsg = '' else: # Error occurred raise ECmdError('"%s"' % cmdline, \ 'external command returned non-zero error code') # Not reached # os.chdir(savedir) return (retval, retmsg) # # Automatically generate a name for a patch based on its path relative to # wrksrc. Use simple scheme to ensure 1-to-1 mapping between path and # patchname - replace all '_' with '__' and all '/' with '_'. # def makepatchname(path, patchdir = ''): SRS = Vars.SLASH_REPL_SYMBOL retval = Vars.PATCH_PREFIX + \ path.replace(SRS, SRS + SRS).replace('/', SRS) retval = os.path.join(patchdir, retval) return retval # # Write a specified message to stderr. # def write_msg(message): if type(message) == types.StringType: message = message, sys.stderr.writelines(message) # # Print specified message to stdout and ask user [y/N]?. Optionally allow # specify default answer, i.e. return value if user typed only # def query_yn(message, default = False): while True: if default == True: yn = 'Y/n' elif default == False: yn = 'y/N' else: yn = 'Y/N' reply = raw_input('%s [%s]: ' % (message, yn)) if reply == 'y' or reply == 'Y': return True elif reply == 'n' or reply == 'N': return False elif reply == '' and default in (True, False): return default print 'Wrong answer "%s", please try again' % reply return default # # Print optional message and usage information and exit with specified exit # code. # def usage(code, msg = ''): myname = os.path.basename(sys.argv[0]) write_msg((str(msg), """ Usage: %s [-afi] file ... %s -u [-i] [patchfile|patchdir ...] """ % (myname, myname))) sys.exit(code) # # Simple custom exception # class MyError(Exception): msg = 'error' def __init__(self, file, msg=''): self.file = file if msg != '': self.msg = msg def __str__(self): return '%s: %s' % (self.file, self.msg) # # Error parsing patchfile # class PatchError(MyError): msg = 'corrupt patchfile, or not patchfile at all' # # Error executing external command # class ECmdError(MyError): pass # # Error getting value of makefile variable # class MakeVarError(MyError): def __init__(self, file, makevar, msg=''): self.file = file if msg != '': self.msg = msg else: self.msg = 'can\'t get %s value' % makevar # # Error locating portdir # class LocatePDirError(MyError): msg = 'can\'t locate portdir' class Patch: fullpath = '' minus3file = '' plus3file = '' wrksrc = '' patchmtime = 0 targetmtime = 0 def __init__(self, path, wrksrc): MINUS3_DELIM = '--- ' PLUS3_DELIM = '+++ ' path = os.path.abspath(path) if not os.path.isfile(path): raise IOError(errno.ENOENT, path) # Not reached # self.fullpath = path filedes = open(path) for line in filedes.readlines(): if self.minus3file == '': if line[:len(MINUS3_DELIM)] == MINUS3_DELIM: lineparts = line.split() try: self.minus3file = lineparts[1] except IndexError: raise PatchError(path) # Not reached # continue elif line[:len(PLUS3_DELIM)] == PLUS3_DELIM: lineparts = line.split() try: self.plus3file = lineparts[1] except IndexError: raise PatchError(path) # Not reached # break filedes.close() if self.minus3file == '' or self.plus3file == '': raise PatchError(path) # Not reached # self.wrksrc = os.path.abspath(wrksrc) self.patchmtime = os.path.getmtime(self.fullpath) plus3file = os.path.join(self.wrksrc, self.plus3file) if os.path.isfile(plus3file): self.targetmtime = os.path.getmtime(plus3file) else: self.targetmtime = 0 def update(self, patch_cookiemtime = 0, ignoremtime = False): targetfile = os.path.join(self.wrksrc, self.plus3file) if not os.path.isfile(targetfile): raise IOError(errno.ENOENT, targetfile) # Not reached # patchdir = os.path.dirname(self.fullpath) if not os.path.isdir(patchdir): os.mkdir(patchdir) if ignoremtime == True or self.patchmtime == 0 or \ self.targetmtime == 0 or \ (self.patchmtime < self.targetmtime and \ patch_cookiemtime < self.targetmtime): retval = gendiff(self.plus3file, self.wrksrc, self.fullpath) if retval[0] == True: self.patchmtime = os.path.getmtime(self.fullpath) else: retval = (False, 'patch is already up to date') return retval class NewPatch(Patch): def __init__(self, patchdir, wrksrc, relpath): self.fullpath = makepatchname(relpath, os.path.abspath(patchdir)) self.wrksrc = os.path.abspath(wrksrc) self.plus3file = relpath self.minus3file = relpath self.patchmtime = 0 plus3file = os.path.join(self.wrksrc, self.plus3file) if os.path.isfile(plus3file): self.targetmtime = os.path.getmtime(plus3file) else: self.targetmtime = 0 class PatchesCollection: patches = {} def __init__(self): self.patches = {} pass def adddir(self, patchdir, wrksrc): if not os.path.isdir(patchdir): raise IOError(errno.ENOENT, patchdir) # Not reached # for filename in glob.glob(os.path.join(patchdir, Vars.PATCH_PREFIX + '*')): for sufx in Vars.PATCH_IGN_SUFX: if filename[-len(sufx):] == sufx: write_msg('WARNING: patchfile "%s" ignored\n' % filename) break else: self.addpatchfile(filename, wrksrc) def addpatchfile(self, path, wrksrc): path = os.path.abspath(path) if not self.patches.has_key(path): self.addpatchobj(Patch(path, wrksrc)) def addpatchobj(self, patchobj): self.patches[patchobj.fullpath] = patchobj def lookupbyname(self, path): path = os.path.abspath(path) if self.patches.has_key(path): return self.patches[path] return None def lookupbytarget(self, wrksrc, relpath): wrksrc = os.path.abspath(wrksrc) for patch in self.patches.values(): if wrksrc == patch.wrksrc and relpath == patch.plus3file: return patch return None def getpatchobjs(self): return self.patches.values() # # Resolve all symbolic links in the given path to a file # def truepath(path): if not os.path.isfile(path): raise IOError(errno.ENOENT, path) result = '' while len(path) > 0: path, lastcomp = os.path.split(path) if len(lastcomp) == 0: lastcomp = path path = '' result = os.path.join(lastcomp, result) if len(path) == 0: break if os.path.islink(path): linkto = os.path.normpath(os.readlink(path)) if linkto[0] != '/': path = os.path.join(path, linkto) else: path = linkto return result[:-1] def main(): try: opts, args = getopt.getopt(sys.argv[1:], 'afui') except getopt.GetoptError, msg: usage(2, msg) automatic = False force = False mode = generate ignoremtime = False for o, a in opts: if o == '-a': automatic = True elif o == '-f': force = True elif o == '-u': mode = update elif o == '-i': ignoremtime = True else: usage(2) # Allow user to override internal constants for varname in dir(Vars): if varname[:2] == '__' and varname[-2:] == '__': continue try: value = os.environ['PT_' + varname] setattr(Vars, varname, value) except KeyError: pass mode(args, automatic, force, ignoremtime) sys.exit(0) # # Display a diff or generate patchfile for the files pointed out by args. # def generate(args, automatic, force, ignoremtime): if len(args) == 0: usage(2, "ERROR: no input files specified") patches = PatchesCollection() for filepath in args: for suf in Vars.RCSDIFF_SUFX, Vars.DIFF_SUFX: if filepath.endswith(suf): filepath = filepath[:-len(suf)] break if not os.path.isfile(filepath): raise IOError(errno.ENOENT, filepath) # Not reached # filepath = truepath(filepath) wrkdirprefix = querymakevar('WRKDIRPREFIX', Vars.ETC_MAKE_CONF, False) portdir = locateportdir(os.path.dirname(filepath), wrkdirprefix, True) wrksrc = querymakevar('WRKSRC', portdir, True) relpath = getrelpath(filepath, wrksrc) if automatic: patchdir = querymakevar('PATCHDIR', portdir, True) if os.path.isdir(patchdir): patches.adddir(patchdir, wrksrc) extra_patches = querymakevar('EXTRA_PATCHES', portdir, False) for extra_patch in extra_patches.split(): if os.path.isfile(extra_patch): patches.addpatchfile(extra_patch, wrksrc) patchobj = patches.lookupbytarget(wrksrc, relpath) if patchobj == None: patchobj = NewPatch(patchdir, wrksrc, relpath) patches.addpatchobj(patchobj) if not force and os.path.exists(patchobj.fullpath) and \ os.path.getsize(patchobj.fullpath) > 0: try: retval = query_yn('Target patchfile "%s" already ' \ 'exists, do you want to replace it?' % \ os.path.basename(patchobj.fullpath)) except KeyboardInterrupt: sys.exit('\nAction aborted') # Not reached # if retval == False: continue write_msg('Generating patchfile: %s...' % \ os.path.basename(patchobj.fullpath)) try: retval = None retval = patchobj.update(ignoremtime = ignoremtime) finally: # Following tricky magic intended to let us append \n even if # we are going to die due to unhandled exception if retval == None: write_msg('OUCH!\n') if retval[0] == False: write_msg('skipped (%s)\n' % retval[1]) else: write_msg('ok\n') else: # automatic != True retval = gendiff(relpath, wrksrc) if retval[0] == False: write_msg('WARNING: %s\n' % retval[1]) # # Atomatically update all patches pointed by args (may be individual # patchfiles, patchdirs or any directories in a portdirs). If directory argument # is encountered, all patches that belong to the port are updated. If no # arguments are supplied - current directory is assumed. # # The procedure honours last modification times of the patchfile, file from # which diff to be generated and `EXTRACT_COOKIE' file (usually # ${WRKDIR}/.extract_cookie) to update only those patches that are really need # to be updated. # def update(args, automatic, force, ignoremtime): if len(args) == 0: args = './', for path in args: if not os.path.exists(path): raise IOError(errno.ENOENT, path) # Not reached # patches = PatchesCollection() if os.path.isdir(path): for wrkdirprefix in (querymakevar('WRKDIRPREFIX', \ Vars.ETC_MAKE_CONF, False), ''): portdir = locateportdir(path, wrkdirprefix, False) if portdir != '': break if portdir == '': raise LocatePDirError(os.path.abspath(path)) # Not reached # wrksrc = querymakevar('WRKSRC', portdir, True) patchdir = querymakevar('PATCHDIR', portdir, True) if os.path.isdir(patchdir): patches.adddir(patchdir, wrksrc) else: continue elif os.path.isfile(path): portdir = locateportdir(os.path.dirname(path), '' , True) wrksrc = querymakevar('WRKSRC', portdir, True) patches.addpatchfile(path, wrksrc) patch_cookie = querymakevar('PATCH_COOKIE', portdir, True) if os.path.isfile(patch_cookie): patch_cookiemtime = os.path.getmtime(patch_cookie) else: patch_cookiemtime = 0 for patchobj in patches.getpatchobjs(): write_msg('Updating patchfile: %s...' % \ os.path.basename(patchobj.fullpath)) try: retval = None retval = patchobj.update(patch_cookiemtime, \ ignoremtime) finally: if retval == None: write_msg('OUCH!\n') if retval[0] == False: write_msg('skipped (%s)\n' % retval[1]) else: write_msg('ok\n') if __name__ == '__main__': try: main() except (PatchError, ECmdError, MakeVarError, LocatePDirError), msg: sys.exit('ERROR: ' + str(msg)) except IOError, (code, msg): sys.exit('ERROR: %s: %s' % (str(msg), os.strerror(code)))