#!/usr/bin/python # # makeupdates - Generate an updates.img containing changes since the last # tag, but only changes that do not need to be compiled. If # you need an updated _isys.so or a new loader, you should # still compile things as usual. # # Copyright (C) 2009 Red Hat, Inc. # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU Lesser General Public License as published # by the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public License # along with this program. If not, see . # # Author: David Cantrell import getopt import os import shutil import subprocess import sys def getArchiveTag(configure, spec): tag = "" f = open(configure) lines = f.readlines() f.close() for line in lines: if line.startswith('AC_INIT('): fields = line.split('[') tag += fields[1].split(']')[0] + '-' + fields[2].split(']')[0] break else: continue f = open(spec) lines = f.readlines() f.close() for line in lines: if line.startswith('Release:'): tag += '-' + line.split()[1].split('%')[0] else: continue return tag def getArchiveTagOffset(configure, spec, offset): tag = getArchiveTag(configure, spec) if not tag.count("-") >= 2: return tag ldash = tag.rfind("-") bldash = tag[:ldash].rfind("-") ver = tag[bldash+1:ldash] if not ver.count(".") >= 1: return tag ver = ver[:ver.rfind(".")] if not len(ver) > 0: return tag globstr = "refs/tags/" + tag[:bldash+1] + ver + ".*" proc = subprocess.Popen(['git', 'for-each-ref', '--sort=taggerdate', '--format=%(tag)', globstr], stdout=subprocess.PIPE, stderr=subprocess.PIPE).communicate() lines = proc[0].strip("\n").split('\n') lines.reverse() try: return lines[offset] except IndexError: return tag def doGitDiff(tag, args=[]): proc = subprocess.Popen(['git', 'diff', '--name-status', tag] + args, stdout=subprocess.PIPE, stderr=subprocess.PIPE).communicate() lines = proc[0].split('\n') return lines def copyUpdatedFiles(tag, updates, cwd): def pruneFile(src, names): lst = [] for name in names: if name.startswith('Makefile') or name.endswith('.pyc'): lst.append(name) return lst subdirs = [] lines = doGitDiff(tag) for line in lines: fields = line.split() if len(fields) < 2: continue status = fields[0] file = fields[1] if status == "D": continue if file.endswith('.spec.in') or (file.find('Makefile') != -1) or \ file.endswith('.c') or file.endswith('.h') or \ file.endswith('.sh') or file == 'configure.ac': continue if file.find('/') != -1: fields = file.split('/') subdir = fields[0] if subdir == 'installclasses' or subdir == 'storage' or \ subdir == 'booty': subupdates = os.path.realpath(updates + '/' + subdir) if os.path.isdir(subupdates): shutil.rmtree(subupdates) if not subdir in subdirs: sys.stdout.write("Including %s/\n" % (subdir,)) subdirs.append(subdir) shutil.copytree(os.path.realpath(cwd + '/' + subdir), subupdates, ignore=pruneFile) elif subdir == 'loader' or subdir == 'po' or \ subdir =='scripts' or subdir == 'command-stubs' or \ subdir == 'tests' or subdir == 'bootdisk' or \ subdir == 'docs' or subdir == 'fonts' or \ subdir == 'utils' or subdir == 'gptsync' or \ subdir == 'liveinst': continue else: sys.stdout.write("Including %s\n" % (file,)) shutil.copy2(file, updates) else: sys.stdout.write("Including %s\n" % (file,)) shutil.copy2(file, updates) def isysChanged(tag): lines = doGitDiff(tag, ['isys']) for line in lines: fields = line.split() if len(fields) < 2: continue status = fields[0] file = fields[1] if status == "D": continue if file.startswith('Makefile') or file.endswith('.h') or \ file.endswith('.c'): return True return False def copyUpdatedIsys(updates, cwd): os.chdir(cwd) if not os.path.isfile('Makefile'): if not os.path.isfile('configure'): os.system('./autogen.sh') os.system('./configure') os.system('make') isysmodule = os.path.realpath(cwd + '/isys/.libs/_isys.so') if os.path.isfile(isysmodule): shutil.copy2(isysmodule, updates) def createUpdatesImage(cwd, updates): os.chdir(updates) os.system("find . | cpio -c -o | gzip -9cv > %s/updates.img" % (cwd,)) sys.stdout.write("updates.img ready\n") def usage(cmd): sys.stdout.write("Usage: %s [OPTION]...\n" % (cmd,)) sys.stdout.write("Options:\n") sys.stdout.write(" -k, --keep Do not delete updates subdirectory.\n") sys.stdout.write(" -c, --compile Compile code if there are isys changes.\n") sys.stdout.write(" -h, --help Display this help and exit.\n") sys.stdout.write(" -t, --tag Make image from TAG to HEAD.\n") sys.stdout.write(" -o, --offset Make image from (latest_tag - OFFSET) to HEAD.\n") def main(argv): prog = os.path.basename(sys.argv[0]) cwd = os.getcwd() configure = os.path.realpath(cwd + '/configure.ac') spec = os.path.realpath(cwd + '/anaconda.spec.in') updates = cwd + '/updates' keep, compile, help, unknown = False, False, False, False tag = None opts = [] offset = 0 try: opts, args = getopt.getopt(sys.argv[1:], 't:o:kc?', ['tag=', 'offset=', 'keep', 'compile', 'help']) except getopt.GetoptError: help = True for o, a in opts: if o in ('-k', '--keep'): keep = True elif o in ('-c', '--compile'): compile = True elif o in ('-?', '--help'): help = True elif o in ('-t', '--tag'): tag = a elif o in ('-o', '--offset'): offset = int(a) else: unknown = True if help: usage(prog) sys.exit(0) elif unknown: sys.stderr.write("%s: extra operand `%s'" % (prog, sys.argv[1],)) sys.stderr.write("Try `%s --help' for more information." % (prog,)) sys.exit(1) if not os.path.isfile(configure) and not os.path.isfile(spec): sys.stderr.write("You must be at the top level of the anaconda source tree.\n") sys.exit(1) if not tag: if offset < 1: tag = getArchiveTag(configure, spec) else: tag = getArchiveTagOffset(configure, spec, offset) sys.stdout.write("Using tag: %s\n" % tag) if not os.path.isdir(updates): os.makedirs(updates) copyUpdatedFiles(tag, updates, cwd) if compile: if isysChanged(tag): copyUpdatedIsys(updates, cwd) createUpdatesImage(cwd, updates) if not keep: shutil.rmtree(updates) if __name__ == "__main__": main(sys.argv)