X-Git-Url: https://git.carlh.net/gitweb/?a=blobdiff_plain;f=cdist;h=c583990bb3e5cbdc5f2f2ae76139a22ab04cf95c;hb=923642336b80e616a828f4dbe3bf2ad565af3b39;hp=b9f3bbcd910925e68956d03a8761c873aa0cd103;hpb=1586e065ac6b7c0f7ab2d58d7a9f681d95baae61;p=cdist.git diff --git a/cdist b/cdist index b9f3bbc..c583990 100755 --- a/cdist +++ b/cdist @@ -30,11 +30,17 @@ import inspect TEMPORARY_DIRECTORY = '/tmp' +class Globals: + quiet = False + command = None + +globals = Globals() + class Error(Exception): def __init__(self, value): self.value = value def __str__(self): - return '\x1b[31m%s\x1b[0m' % repr(self.value) + return self.value def __repr__(self): return str(self) @@ -43,9 +49,9 @@ class Error(Exception): # class Option(object): - def __init__(self, key): + def __init__(self, key, default=None): self.key = key - self.value = None + self.value = default def offer(self, key, value): if key == self.key: @@ -69,11 +75,12 @@ class Config: Option('osx_build_host'), Option('osx_environment_prefix'), Option('osx_sdk_prefix'), - Option('osx_sdk') ] + Option('osx_sdk'), + Option('parallel', 4) ] try: f = open('%s/.config/cdist' % os.path.expanduser('~'), 'r') - while 1: + while True: l = f.readline() if l == '': break @@ -102,16 +109,25 @@ config = Config() # def log(m): - if not args.quiet: + if not globals.quiet: print '\x1b[33m* %s\x1b[0m' % m +def scp_escape(n): + s = n.split(':') + assert(len(s) == 1 or len(s) == 2) + if len(s) == 2: + s[1] = '"\'%s\'"' % s[1] + return '%s:%s' % (s[0], s[1]) + else: + return n + def copytree(a, b): log('copy %s -> %s' % (a, b)) - shutil.copytree(a, b) + os.system('scp -r %s %s' % (scp_escape(a), scp_escape(b))) def copyfile(a, b): log('copy %s -> %s' % (a, b)) - shutil.copyfile(a, b) + os.system('scp %s %s' % (scp_escape(a), scp_escape(b))) def rmdir(a): log('remove %s' % a) @@ -135,7 +151,7 @@ def command_and_read(c): def read_wscript_variable(directory, variable): f = open('%s/wscript' % directory, 'r') - while 1: + while True: l = f.readline() if l == '': break @@ -203,9 +219,9 @@ class Version: class Target(object): # @param directory directory to work in; if None we will use a temporary directory # Temporary directories will be removed after use; specified directories will not - def __init__(self, platform, parallel, directory=None): + def __init__(self, platform, directory=None): self.platform = platform - self.parallel = parallel + self.parallel = int(config.get('parallel')) if directory is None: self.directory = tempfile.mkdtemp('', 'tmp', TEMPORARY_DIRECTORY) @@ -214,8 +230,6 @@ class Target(object): self.directory = directory self.rmdir = False - print 'Working in %s' % self.directory - # Environment variables that we will use when we call cscripts self.variables = {} self.debug = False @@ -295,7 +309,7 @@ class Target(object): class WindowsTarget(Target): def __init__(self, bits, directory=None): - super(WindowsTarget, self).__init__('windows', 2, directory) + super(WindowsTarget, self).__init__('windows', directory) self.bits = bits self.windows_prefix = '%s/%d' % (config.get('windows_environment_prefix'), self.bits) @@ -324,6 +338,7 @@ class WindowsTarget(Target): cxx += ' -I%s/include' % p link += ' -L%s/lib' % p self.set('CXXFLAGS', '"%s"' % cxx) + self.set('CPPFLAGS', '') self.set('LINKFLAGS', '"%s"' % link) def command(self, c): @@ -336,7 +351,7 @@ class WindowsTarget(Target): class LinuxTarget(Target): def __init__(self, distro, version, bits, directory=None): - super(LinuxTarget, self).__init__('linux', 2, directory) + super(LinuxTarget, self).__init__('linux', directory) self.distro = distro self.version = version self.bits = bits @@ -346,6 +361,7 @@ class LinuxTarget(Target): self.chroot_prefix = '%s/%s' % (config.get('linux_chroot_prefix'), self.chroot) self.set('CXXFLAGS', '-I%s/include' % self.directory) + self.set('CPPFLAGS', '') self.set('LINKFLAGS', '-L%s/lib' % self.directory) self.set('PKG_CONFIG_PATH', '%s/lib/pkgconfig:/usr/local/lib/pkgconfig' % self.directory) self.set('PATH', '%s:/usr/local/bin' % (os.environ['PATH'])) @@ -359,7 +375,7 @@ class LinuxTarget(Target): class OSXTarget(Target): def __init__(self, directory=None): - super(OSXTarget, self).__init__('osx', 4, directory) + super(OSXTarget, self).__init__('osx', directory) def command(self, c): command('%s %s' % (self.variables_string(False), c)) @@ -380,6 +396,7 @@ class OSXSingleTarget(OSXTarget): # Environment variables self.set('CFLAGS', '"-I%s/include -I%s/include %s"' % (self.directory, enviro, flags)) + self.set('CPPFLAGS', '') self.set('CXXFLAGS', '"-I%s/include -I%s/include %s"' % (self.directory, enviro, flags)) self.set('LDFLAGS', '"-L%s/lib -L%s/lib %s"' % (self.directory, enviro, flags)) self.set('LINKFLAGS', '"-L%s/lib -L%s/lib %s"' % (self.directory, enviro, flags)) @@ -395,8 +412,8 @@ class OSXUniversalTarget(OSXTarget): def __init__(self, directory=None): super(OSXUniversalTarget, self).__init__(directory) self.parts = [] - self.parts.append(OSXSingleTarget(32, directory)) - self.parts.append(OSXSingleTarget(64, directory)) + self.parts.append(OSXSingleTarget(32, os.path.join(self.directory, '32'))) + self.parts.append(OSXSingleTarget(64, os.path.join(self.directory, '64'))) def package(self, project): for p in self.parts: @@ -413,8 +430,7 @@ class OSXUniversalTarget(OSXTarget): class SourceTarget(Target): def __init__(self): - super(SourceTarget, self).__init__('source', 2) - self.directory = tempfile.mkdtemp() + super(SourceTarget, self).__init__('source') def command(self, c): log('host -> %s' % c) @@ -451,7 +467,7 @@ def target_factory(s, debug, work): elif s.startswith('osx-'): target = OSXSingleTarget(int(s.split('-')[1]), work) elif s == 'osx': - if args.command == 'build': + if globals.command == 'build': target = OSXSingleTarget(64, work) else: target = OSXUniversalTarget(work) @@ -481,7 +497,7 @@ class Project(object): def checkout(self, target): flags = '' redirect = '' - if args.quiet: + if globals.quiet: flags = '-q' redirect = '>/dev/null' command('git clone %s %s/%s.git %s/src/%s' % (flags, config.get('git_prefix'), self.name, target.directory, self.name)) @@ -508,7 +524,7 @@ class Project(object): def set_version_in_wscript(version): f = open('wscript', 'rw') o = open('wscript.tmp', 'w') - while 1: + while True: l = f.readline() if l == '': break @@ -551,219 +567,273 @@ def devel_to_git(project, filename): filename = filename.replace('devel', '-%s' % project.git_commit) return filename + # # Command-line parser # -parser = argparse.ArgumentParser() -parser.add_argument('command') -parser.add_argument('-p', '--project', help='project name') -parser.add_argument('-d', '--directory', help='directory within project repo', default='.') -parser.add_argument('--minor', help='minor version number bump', action='store_true') -parser.add_argument('--micro', help='micro version number bump', action='store_true') -parser.add_argument('-c', '--checkout', help='string to pass to git for checkout') -parser.add_argument('-o', '--output', help='output directory', default='.') -parser.add_argument('-q', '--quiet', help='be quiet', action='store_true') -parser.add_argument('-t', '--target', help='target') -parser.add_argument('-k', '--keep', help='keep working tree', action='store_true') -parser.add_argument('--debug', help='build with debugging symbols where possible', action='store_true') -parser.add_argument('-w', '--work', help='override default work directory') -args = parser.parse_args() - -args.output = os.path.abspath(args.output) -if args.work is not None: - args.work = os.path.abspath(args.work) - -if args.project is None and args.command != 'shell': - raise Error('you must specify -p or --project') - -project = Project(args.project, args.directory, args.checkout) - -if args.command == 'build': - if args.target is None: - raise Error('you must specify -t or --target') - - target = target_factory(args.target, args.debug, args.work) - project.checkout(target) - target.build_dependencies(project) - target.build(project) - if not args.keep: - target.cleanup() - -elif args.command == 'package': - if args.target is None: - raise Error('you must specify -t or --target') +def main(): + + commands = { + "build": "build project", + "package": "package and build project", + "release": "release a project using its next version number (changing wscript and tagging)", + "pot": "build the project's .pot files", + "changelog": "generate a simple HTML changelog", + "manual": "build the project's manual", + "doxygen": "build the project's Doxygen documentation", + "latest": "print out the latest version", + "test": "run the project's unit tests", + "shell": "build the project then start a shell in its chroot", + "revision": "print the head git revision number" + } + + one_of = "Command is one of:\n" + summary = "" + for k, v in commands.iteritems(): + one_of += "\t%s\t%s\n" % (k, v) + summary += k + " " + + parser = argparse.ArgumentParser() + parser.add_argument('command', help=summary) + parser.add_argument('-p', '--project', help='project name') + parser.add_argument('-d', '--directory', help='directory within project repo', default='.') + parser.add_argument('--minor', help='minor version number bump', action='store_true') + parser.add_argument('--micro', help='micro version number bump', action='store_true') + parser.add_argument('--major', help='major version to return with latest', type=int) + parser.add_argument('-c', '--checkout', help='string to pass to git for checkout') + parser.add_argument('-o', '--output', help='output directory', default='.') + parser.add_argument('-q', '--quiet', help='be quiet', action='store_true') + parser.add_argument('-t', '--target', help='target') + parser.add_argument('-k', '--keep', help='keep working tree', action='store_true') + parser.add_argument('--debug', help='build with debugging symbols where possible', action='store_true') + parser.add_argument('-w', '--work', help='override default work directory') + args = parser.parse_args() + + if args.output.find(':') == -1: + # This isn't of the form host:path so make it absolute + args.output = os.path.abspath(args.output) + '/' + + # Now, args.output is 'host:' or 'path/' + + if args.work is not None: + args.work = os.path.abspath(args.work) + + if args.project is None and args.command != 'shell': + raise Error('you must specify -p or --project') - target = target_factory(args.target, args.debug, args.work) + globals.quiet = args.quiet + globals.command = args.command - packages = target.package(project) - if hasattr(packages, 'strip') or (not hasattr(packages, '__getitem__') and not hasattr(packages, '__iter__')): - packages = [packages] + project = Project(args.project, args.directory, args.checkout) - if target.platform == 'linux': - out = '%s/%s-%s-%d' % (args.output, target.distro, target.version, target.bits) - try: - os.makedirs(out) - except: - pass - for p in packages: - copyfile(p, '%s/%s' % (out, os.path.basename(devel_to_git(project, p)))) - else: - for p in packages: - copyfile(p, '%s/%s' % (args.output, os.path.basename(devel_to_git(project, p)))) + if not globals.command in commands: + e = 'command must be one of:\n' + one_of + raise Error('command must be one of:\n%s' % one_of) - if not args.keep: - target.cleanup() + if globals.command == 'build': + if args.target is None: + raise Error('you must specify -t or --target') + + target = target_factory(args.target, args.debug, args.work) + project.checkout(target) + target.build_dependencies(project) + target.build(project) + if not args.keep: + target.cleanup() -elif args.command == 'release': - if args.minor is False and args.micro is False: - raise Error('you must specify --minor or --micro') + elif globals.command == 'package': + if args.target is None: + raise Error('you must specify -t or --target') - target = SourceTarget() - project.checkout(target) + target = target_factory(args.target, args.debug, args.work) - version = project.version - version.to_release() - if args.minor: - version.bump_minor() - else: - version.bump_micro() + packages = target.package(project) + if hasattr(packages, 'strip') or (not hasattr(packages, '__getitem__') and not hasattr(packages, '__iter__')): + packages = [packages] + + if target.platform == 'linux': + out = '%s%s-%s-%d' % (args.output, target.distro, target.version, target.bits) + try: + os.makedirs(out) + except: + pass + for p in packages: + copyfile(p, '%s/%s' % (out, os.path.basename(devel_to_git(project, p)))) + else: + for p in packages: + copyfile(p, '%s%s' % (args.output, os.path.basename(devel_to_git(project, p)))) - set_version_in_wscript(version) - append_version_to_changelog(version) - append_version_to_debian_changelog(version) + if not args.keep: + target.cleanup() - command('git commit -a -m "Bump version"') - command('git tag -m "v%s" v%s' % (version, version)) + elif globals.command == 'release': + if args.minor is False and args.micro is False: + raise Error('you must specify --minor or --micro') - version.to_devel() - set_version_in_wscript(version) - command('git commit -a -m "Bump version"') - command('git push') - command('git push --tags') + target = SourceTarget() + project.checkout(target) - target.cleanup() + version = project.version + version.to_release() + if args.minor: + version.bump_minor() + else: + version.bump_micro() -elif args.command == 'pot': - target = SourceTarget() - project.checkout(target) + set_version_in_wscript(version) + append_version_to_changelog(version) + append_version_to_debian_changelog(version) - pots = project.cscript['make_pot'](target) - for p in pots: - copyfile(p, '%s/%s' % (args.output, os.path.basename(p))) + command('git commit -a -m "Bump version"') + command('git tag -m "v%s" v%s' % (version, version)) - target.cleanup() + version.to_devel() + set_version_in_wscript(version) + command('git commit -a -m "Bump version"') + command('git push') + command('git push --tags') -elif args.command == 'changelog': - target = SourceTarget() - project.checkout(target) + target.cleanup() - text = open('ChangeLog', 'r') - html = open('%s/changelog.html' % args.output, 'w') - versions = 8 - - last = None - changes = [] - - while 1: - l = text.readline() - if l == '': - break - - if len(l) > 0 and l[0] == "\t": - s = l.split() - if len(s) == 4 and s[1] == "Version" and s[3] == "released.": - v = Version(s[2]) - if v.micro == 0: - if last is not None and len(changes) > 0: - print >>html,"

Changes between version %s and %s

" % (s[2], last) - print >>html,"" - last = s[2] - changes = [] - versions -= 1 - if versions < 0: - break - else: - c = l.strip() - if len(c) > 0: - if c[0] == '*': - changes.append(c[2:]) - else: - changes[-1] += " " + c - - target.cleanup() - -elif args.command == 'manual': - target = SourceTarget() - project.checkout(target) - - outs = project.cscript['make_manual'](target) - for o in outs: - if os.path.isfile(o): - copyfile(o, '%s/%s' % (args.output, os.path.basename(o))) - else: - copytree(o, '%s/%s' % (args.output, os.path.basename(o))) + elif globals.command == 'pot': + target = SourceTarget() + project.checkout(target) - target.cleanup() + pots = project.cscript['make_pot'](target) + for p in pots: + copyfile(p, '%s%s' % (args.output, os.path.basename(p))) -elif args.command == 'doxygen': - target = SourceTarget() - project.checkout(target) + target.cleanup() - dirs = project.cscript['make_doxygen'](target) - if hasattr(dirs, 'strip') or (not hasattr(dirs, '__getitem__') and not hasattr(dirs, '__iter__')): - dirs = [dirs] + elif globals.command == 'changelog': + target = SourceTarget() + project.checkout(target) + + text = open('ChangeLog', 'r') + html = tempfile.NamedTemporaryFile() + versions = 8 + + last = None + changes = [] + + while True: + l = text.readline() + if l == '': + break + + if len(l) > 0 and l[0] == "\t": + s = l.split() + if len(s) == 4 and s[1] == "Version" and s[3] == "released.": + v = Version(s[2]) + if v.micro == 0: + if last is not None and len(changes) > 0: + print >>html,"

Changes between version %s and %s

" % (s[2], last) + print >>html,"" + last = s[2] + changes = [] + versions -= 1 + if versions < 0: + break + else: + c = l.strip() + if len(c) > 0: + if c[0] == '*': + changes.append(c[2:]) + else: + changes[-1] += " " + c + + copyfile(html.file, '%schangelog.html' % args.output) + html.close() + target.cleanup() - for d in dirs: - copytree(d, '%s/%s' % (args.output, 'doc')) + elif globals.command == 'manual': + target = SourceTarget() + project.checkout(target) - target.cleanup() + outs = project.cscript['make_manual'](target) + for o in outs: + if os.path.isfile(o): + copyfile(o, '%s%s' % (args.output, os.path.basename(o))) + else: + copytree(o, '%s%s' % (args.output, os.path.basename(o))) -elif args.command == 'latest': - target = SourceTarget() - project.checkout(target) + target.cleanup() - f = command_and_read('git log --tags --simplify-by-decoration --pretty="%d"') - t = f.readline() - m = re.compile(".*\((.*)\).*").match(t) - latest = None - if m: - tags = m.group(1).split(', ') - for t in tags: - s = t.split() - if len(s) > 1: - t = s[1] - if len(t) > 0 and t[0] == 'v': - latest = t[1:] + elif globals.command == 'doxygen': + target = SourceTarget() + project.checkout(target) - print latest - target.cleanup() + dirs = project.cscript['make_doxygen'](target) + if hasattr(dirs, 'strip') or (not hasattr(dirs, '__getitem__') and not hasattr(dirs, '__iter__')): + dirs = [dirs] -elif args.command == 'test': - if args.target is None: - raise Error('you must specify -t or --target') + for d in dirs: + copytree(d, '%s%s' % (args.output, 'doc')) + + target.cleanup() + + elif globals.command == 'latest': + target = SourceTarget() + project.checkout(target) + + f = command_and_read('git log --tags --simplify-by-decoration --pretty="%d"') + latest = None + while latest is None: + t = f.readline() + m = re.compile(".*\((.*)\).*").match(t) + if m: + tags = m.group(1).split(', ') + for t in tags: + s = t.split() + if len(s) > 1: + t = s[1] + if len(t) > 0 and t[0] == 'v': + v = Version(t[1:]) + if args.major is None or v.major == args.major: + latest = v + + print latest + target.cleanup() + + elif globals.command == 'test': + if args.target is None: + raise Error('you must specify -t or --target') + + target = None + try: + target = target_factory(args.target, args.debug, args.work) + target.test(project) + except Error as e: + if target is not None: + target.cleanup() + raise - target = None - try: - target = target_factory(args.target, args.debug, args.work) - target.test(project) - except Error as e: if target is not None: target.cleanup() - raise - - if target is not None: - target.cleanup() -elif args.command == 'shell': - if args.target is None: - raise Error('you must specify -t or --target') + elif globals.command == 'shell': + if args.target is None: + raise Error('you must specify -t or --target') - target = target_factory(args.target, args.debug, args.work) - target.command('bash') + target = target_factory(args.target, args.debug, args.work) + target.command('bash') + + elif globals.command == 'revision': + + target = SourceTarget() + project.checkout(target) + print command_and_read('git rev-parse HEAD').readline().strip()[:7] + target.cleanup() + + else: + raise Error('invalid command %s' % globals.command) -else: - raise Error('invalid command %s' % args.command) +try: + main() +except Error as e: + print >>sys.stderr,'cdist: %s' % str(e) + sys.exit(1)