diff --git a/backportpackage b/backportpackage index e87af9f..3ec373a 100755 --- a/backportpackage +++ b/backportpackage @@ -15,7 +15,6 @@ # # ################################################################## -import logging import optparse import os import shutil @@ -26,14 +25,17 @@ import tempfile from debian.deb822 import Dsc import launchpadlib.launchpad +from ubuntutools.logger import Logger + devnull = open('/dev/null', 'r+') lp = None -def error(msg, *args, **kwargs): - logging.error(msg, *args, **kwargs) +def error(msg): + Logger.error(msg) sys.exit(1) def check_call(cmd, *args, **kwargs): + Logger.command(cmd) ret = subprocess.call(cmd, *args, **kwargs) if ret != 0: error('%s returned %d' % (cmd, ret)) @@ -197,7 +199,6 @@ def do_backport(workdir, package, dscfile, release, opts): def main(args): global lp - logging.basicConfig(level=logging.INFO) os.environ['DEB_VENDOR'] = 'Ubuntu' opts, (package,) = parse(args[1:]) diff --git a/sponsor-patch b/sponsor-patch index 0f6ca7c..bdda4b4 100755 --- a/sponsor-patch +++ b/sponsor-patch @@ -29,6 +29,7 @@ import debian.debian_support import launchpadlib.launchpad import ubuntutools.update_maintainer +from ubuntutools.logger import Logger USER_ABORT = 2 @@ -57,7 +58,7 @@ class BugTask(object): dsc_file = None for url in source_files: filename = urllib.unquote(os.path.basename(url)) - Print.info("Downloading %s..." % (filename)) + Logger.info("Downloading %s..." % (filename)) urllib.urlretrieve(url, filename) if url.endswith(".dsc"): dsc_file = filename @@ -171,7 +172,7 @@ class Pbuilder(Builder): cmd = ["sudo", "-E", "DIST=" + dist, "pbuilder", "--build", "--distribution", dist, "--architecture", self.architecture, "--buildresult", result_directory, dsc_file] - Print.command(cmd) + Logger.command(cmd) return subprocess.call(cmd) @@ -181,13 +182,13 @@ class Sbuild(Builder): def build(self, dsc_file, dist, result_directory): workdir = os.getcwd() - Print.command(["cd", result_directory]) + Logger.command(["cd", result_directory]) os.chdir(result_directory) cmd = ["sbuild", "--arch-all", "--dist=" + dist, "--arch=" + self.architecture, dsc_file] - Print.command(cmd) + Logger.command(cmd) result = subprocess.call(cmd) - Print.command(["cd", workdir]) + Logger.command(["cd", workdir]) os.chdir(workdir) return result @@ -220,41 +221,6 @@ class Patch(object): self.changed_files)) > 0 -class Print(object): - script_name = os.path.basename(sys.argv[0]) - verbose = False - - @classmethod - def command(cls, cmd): - if cls.verbose: - for i in xrange(len(cmd)): - if cmd[i].find(" ") >= 0: - cmd[i] = '"' + cmd[i] + '"' - print "%s: I: %s" % (script_name, " ".join(cmd)) - - @classmethod - def debug(cls, message): - if cls.verbose: - print "%s: D: %s" % (script_name, message) - - @classmethod - def error(cls, message): - print >> sys.stderr, "%s: Error: %s" % (script_name, message) - - @classmethod - def info(cls, message): - if cls.verbose: - print "%s: I: %s" % (script_name, message) - - @classmethod - def normal(cls, message): - print "%s: %s" % (script_name, message) - - @classmethod - def set_verbosity(cls, verbose): - cls.verbose = verbose - - def get_source_package_name(bug_task): package = None if bug_task.bug_target_name != "ubuntu": @@ -334,7 +300,7 @@ def yes_edit_no_question(question, default): def edit_source(): # Spawn shell to allow modifications cmd = [get_user_shell()] - Print.command(cmd) + Logger.command(cmd) print """An interactive shell was launched in file://%s Edit your files. When you are done, exit the shell. If you wish to abort the @@ -342,7 +308,7 @@ process, exit the shell such that it returns an exit code other than zero. """ % (os.getcwd()), returncode = subprocess.call(cmd) if returncode != 0: - Print.error("Shell exited with exit value %i." % (returncode)) + Logger.error("Shell exited with exit value %i." % (returncode)) sys.exit(1) def get_fixed_lauchpad_bugs(changes_file): @@ -380,10 +346,10 @@ def get_patch_or_branch(bug): linked_branches = map(lambda b: b.branch, bug.linked_branches) if len(attached_patches) == 0 and len(linked_branches) == 0: if len(bug.attachments) == 0: - Print.error("No attachment and no linked branch found on bug #%i." \ + Logger.error("No attachment and no linked branch found on bug #%i." \ % (bug.id)) else: - Print.error(("No attached patch and no linked branch found. Go " \ + Logger.error(("No attached patch and no linked branch found. Go " \ "to https://launchpad.net/bugs/%i and mark an " \ "attachment as patch.") % (bug.id)) sys.exit(1) @@ -393,13 +359,13 @@ def get_patch_or_branch(bug): branch = linked_branches[0].bzr_identity else: if len(attached_patches) == 0: - Print.normal("https://launchpad.net/bugs/%i has %i branches " \ + Logger.normal("https://launchpad.net/bugs/%i has %i branches " \ "linked:" % (bug.id, len(linked_branches))) elif len(linked_branches) == 0: - Print.normal("https://launchpad.net/bugs/%i has %i patches" \ + Logger.normal("https://launchpad.net/bugs/%i has %i patches" \ " attached:" % (bug.id, len(attached_patches))) else: - Print.normal("https://launchpad.net/bugs/%i has %i branch(es)" \ + Logger.normal("https://launchpad.net/bugs/%i has %i branch(es)" \ " linked and %i patch(es) attached:" % \ (bug.id, len(linked_branches), len(attached_patches))) i = 0 @@ -421,11 +387,11 @@ def download_patch(patch): patch_filename = re.sub(" ", "_", patch.title) if not reduce(lambda r, x: r or patch.title.endswith(x), (".debdiff", ".diff", ".patch"), False): - Print.info("Patch %s does not have a proper file extension." % \ + Logger.info("Patch %s does not have a proper file extension." % \ (patch.title)) patch_filename += ".patch" - Print.info("Downloading %s." % (patch_filename)) + Logger.info("Downloading %s." % (patch_filename)) patch_file = open(patch_filename, "w") patch_file.write(patch.data.open().read()) patch_file.close() @@ -436,18 +402,18 @@ def download_branch(branch): if os.path.isdir(dir_name): shutil.rmtree(dir_name) cmd = ["bzr", "branch", branch] - Print.command(cmd) + Logger.command(cmd) if subprocess.call(cmd) != 0: - Print.error("Failed to download branch %s." % (branch)) + Logger.error("Failed to download branch %s." % (branch)) sys.exit(1) return dir_name def merge_branch(branch): edit = False cmd = ["bzr", "merge", branch] - Print.command(cmd) + Logger.command(cmd) if subprocess.call(cmd) != 0: - Print.error("Failed to merge branch %s." % (branch)) + Logger.error("Failed to merge branch %s." % (branch)) ask_for_manual_fixing() edit = True return edit @@ -456,9 +422,9 @@ def extract_source(dsc_file, verbose=False): cmd = ["dpkg-source", "--no-preparation", "-x", dsc_file] if not verbose: cmd.insert(1, "-q") - Print.command(cmd) + Logger.command(cmd) if subprocess.call(cmd) != 0: - Print.error("Extraction of %s failed." % (os.path.basename(dsc_file))) + Logger.error("Extraction of %s failed." % (os.path.basename(dsc_file))) sys.exit(1) def apply_patch(task, patch): @@ -466,9 +432,9 @@ def apply_patch(task, patch): if patch.is_debdiff(): cmd = ["patch", "--merge", "--force", "-p", str(patch.get_strip_level()), "-i", patch.full_path] - Print.command(cmd) + Logger.command(cmd) if subprocess.call(cmd) != 0: - Print.error("Failed to apply debdiff %s to %s %s." % \ + Logger.error("Failed to apply debdiff %s to %s %s." % \ (patch.get_name(), task.package, task.get_version())) if not edit: ask_for_manual_fixing() @@ -477,9 +443,9 @@ def apply_patch(task, patch): # FIXME: edit-patch needs a non-interactive mode # https://launchpad.net/bugs/612566 cmd = ["edit-patch", patch.full_path] - Print.command(cmd) + Logger.command(cmd) if subprocess.call(cmd) != 0: - Print.error("Failed to apply diff %s to %s %s." % \ + Logger.error("Failed to apply diff %s to %s %s." % \ (patch.get_name(), task.package, task.get_version())) if not edit: ask_for_manual_fixing() @@ -493,11 +459,11 @@ def main(script_name, bug_number, build, edit, keyid, upload, workdir, builder, try: os.makedirs(workdir) except os.error, error: - Print.error("Failed to create the working directory %s [Errno " \ + Logger.error("Failed to create the working directory %s [Errno " \ "%i]: %s." % (workdir, error.errno, error.strerror)) sys.exit(1) if workdir != os.getcwd(): - Print.command(["cd", workdir]) + Logger.command(["cd", workdir]) os.chdir(workdir) script_name = os.path.basename(sys.argv[0]) @@ -510,13 +476,13 @@ def main(script_name, bug_number, build, edit, keyid, upload, workdir, builder, bug_tasks = map(lambda x: BugTask(x, launchpad), bug.bug_tasks) ubuntu_tasks = filter(lambda x: x.is_ubuntu_task(), bug_tasks) if len(ubuntu_tasks) == 0: - Print.error("No Ubuntu bug task found on bug #%i." % (bug_number)) + Logger.error("No Ubuntu bug task found on bug #%i." % (bug_number)) sys.exit(1) elif len(ubuntu_tasks) == 1: task = ubuntu_tasks[0] if len(ubuntu_tasks) > 1: if verbose: - Print.info("%i Ubuntu tasks exist for bug #%i." % \ + Logger.info("%i Ubuntu tasks exist for bug #%i." % \ (len(ubuntu_tasks), bug_number)) for task in ubuntu_tasks: print task.get_short_info() @@ -524,7 +490,7 @@ def main(script_name, bug_number, build, edit, keyid, upload, workdir, builder, if len(open_ubuntu_tasks) == 1: task = open_ubuntu_tasks[0] else: - Print.normal("https://launchpad.net/bugs/%i has %i Ubuntu tasks:" \ + Logger.normal("https://launchpad.net/bugs/%i has %i Ubuntu tasks:" \ % (bug_number, len(ubuntu_tasks))) for i in xrange(len(ubuntu_tasks)): print "%i) %s" % (i + 1, @@ -532,7 +498,7 @@ def main(script_name, bug_number, build, edit, keyid, upload, workdir, builder, selected = input_number("To which Ubuntu tasks do the patch belong", 1, len(ubuntu_tasks)) task = ubuntu_tasks[selected - 1] - Print.info("Selected Ubuntu task: %s" % (task.get_short_info())) + Logger.info("Selected Ubuntu task: %s" % (task.get_short_info())) dsc_file = task.download_source() assert os.path.isfile(dsc_file), "%s does not exist." % (dsc_file) @@ -540,15 +506,15 @@ def main(script_name, bug_number, build, edit, keyid, upload, workdir, builder, if patch: patch = download_patch(patch) - Print.info("Ubuntu package: %s" % (task.package)) + Logger.info("Ubuntu package: %s" % (task.package)) if task.is_merge(): - Print.info("The task is a merge request.") + Logger.info("The task is a merge request.") extract_source(dsc_file, verbose) # change directory directory = task.package + '-' + task.get_version().upstream_version - Print.command(["cd", directory]) + Logger.command(["cd", directory]) os.chdir(directory) edit |= apply_patch(task, patch) @@ -556,7 +522,7 @@ def main(script_name, bug_number, build, edit, keyid, upload, workdir, builder, branch_dir = download_branch(task.get_branch_link()) # change directory - Print.command(["cd", branch_dir]) + Logger.command(["cd", branch_dir]) os.chdir(branch_dir) edit |= merge_branch(branch) @@ -568,9 +534,9 @@ def main(script_name, bug_number, build, edit, keyid, upload, workdir, builder, edit = True # update the Maintainer field - Print.command(["update-maintainer"]) + Logger.command(["update-maintainer"]) if ubuntutools.update_maintainer.update_maintainer(verbose) != 0: - Print.error("update-maintainer script failed.") + Logger.error("update-maintainer script failed.") sys.exit(1) # Get new version of package @@ -578,7 +544,7 @@ def main(script_name, bug_number, build, edit, keyid, upload, workdir, builder, try: new_version = changelog.get_version() except IndexError: - Print.error("Debian package version could not be determined. " \ + Logger.error("Debian package version could not be determined. " \ "debian/changelog is probably malformed.") ask_for_manual_fixing() continue @@ -586,15 +552,15 @@ def main(script_name, bug_number, build, edit, keyid, upload, workdir, builder, # Check if version of the new package is greater than the version in # the archive. if new_version <= task.get_version(): - Print.error("The version %s is not greater than the already " \ + Logger.error("The version %s is not greater than the already " \ "available %s." % (new_version, task.get_version())) ask_for_manual_fixing() continue cmd = ["dch", "--maintmaint", "--edit", ""] - Print.command(cmd) + Logger.command(cmd) if subprocess.call(cmd) != 0: - Print.info("Failed to update timestamp in debian/changelog.") + Logger.info("Failed to update timestamp in debian/changelog.") # Build source package if patch: @@ -615,9 +581,9 @@ def main(script_name, bug_number, build, edit, keyid, upload, workdir, builder, env = os.environ if upload == 'ubuntu': env['DEB_VENDOR'] = 'Ubuntu' - Print.command(cmd) + Logger.command(cmd) if subprocess.call(cmd, env=env) != 0: - Print.error("Failed to build source tarball.") + Logger.error("Failed to build source tarball.") # TODO: Add a "retry" option ask_for_manual_fixing() continue @@ -634,7 +600,7 @@ def main(script_name, bug_number, build, edit, keyid, upload, workdir, builder, debdiff_filename = os.path.join(workdir, debdiff_name) if not verbose: cmd.insert(1, "-q") - Print.command(cmd + [">", debdiff_filename]) + Logger.command(cmd + [">", debdiff_filename]) process = subprocess.Popen(cmd, stdout=subprocess.PIPE) debdiff = process.communicate()[0] @@ -646,7 +612,7 @@ def main(script_name, bug_number, build, edit, keyid, upload, workdir, builder, # Make sure that the Launchpad bug will be closed changes_file = new_dsc_file[:-4] + "_source.changes" if bug_number not in get_fixed_lauchpad_bugs(changes_file): - Print.error("Launchpad bug #%i is not closed by new version." % \ + Logger.error("Launchpad bug #%i is not closed by new version." % \ (bug_number)) ask_for_manual_fixing() continue @@ -660,7 +626,7 @@ def main(script_name, bug_number, build, edit, keyid, upload, workdir, builder, allowed = map(lambda s: s + "-proposed", supported_series) + \ [devel_series] if changelog.distributions not in allowed: - Print.error("%s is not an allowed series. It needs to be one " \ + Logger.error("%s is not an allowed series. It needs to be one " \ "of %s." % (changelog.distributions, ", ".join(allowed))) ask_for_manual_fixing() @@ -668,7 +634,7 @@ def main(script_name, bug_number, build, edit, keyid, upload, workdir, builder, elif upload and upload.startwith("ppa/"): allowed = supported_series + [devel_series] if changelog.distributions not in allowed: - Print.error("%s is not an allowed series. It needs to be one " \ + Logger.error("%s is not an allowed series. It needs to be one " \ "of %s." % (changelog.distributions, ", ".join(allowed))) ask_for_manual_fixing() @@ -683,7 +649,7 @@ def main(script_name, bug_number, build, edit, keyid, upload, workdir, builder, dist = re.sub("-.*$", "", changelog.distributions) result = builder.build(new_dsc_file, dist, buildresult) if result != 0: - Print.error("Failed to build %s from source with %s." % \ + Logger.error("Failed to build %s from source with %s." % \ (os.path.basename(new_dsc_file), builder.get_name())) # TODO: Add "retry" and "update" option @@ -699,7 +665,7 @@ def main(script_name, bug_number, build, edit, keyid, upload, workdir, builder, cmd = ["lintian", "-IE", "--pedantic", "-q", build_changes] lintian_filename = os.path.join(workdir, task.package + "_" + strip_epoch(new_version) + ".lintian") - Print.command(cmd + [">", lintian_filename]) + Logger.command(cmd + [">", lintian_filename]) process = subprocess.Popen(cmd, stdout=subprocess.PIPE) report = process.communicate()[0] @@ -727,26 +693,26 @@ def main(script_name, bug_number, build, edit, keyid, upload, workdir, builder, print "Abort." sys.exit(USER_ABORT) cmd = ["dput", "--force", upload, changes_file] - Print.command(cmd) + Logger.command(cmd) if subprocess.call(cmd) != 0: - Print.error("Upload of %s to %s failed." % \ + Logger.error("Upload of %s to %s failed." % \ (os.path.basename(changes_file), upload)) sys.exit(1) if branch: cmd = ['debcommit'] - Print.command(cmd) + Logger.command(cmd) if subprocess.call(cmd) != 0: - Print.error('Bzr commit failed.') + Logger.error('Bzr commit failed.') sys.exit(1) cmd = ['bzr', 'mark-uploaded'] - Print.command(cmd) + Logger.command(cmd) if subprocess.call(cmd) != 0: - Print.error('Bzr tagging failed.') + Logger.error('Bzr tagging failed.') sys.exit(1) cmd = ['bzr', 'push', ':parent'] - Print.command(cmd) + Logger.command(cmd) if subprocess.call(cmd) != 0: - Print.error('Bzr push failed.') + Logger.error('Bzr push failed.') sys.exit(1) # Leave while loop if everything worked @@ -790,20 +756,20 @@ if __name__ == "__main__": help="Specify a working directory.") (options, args) = parser.parse_args() - Print.set_verbosity(options.verbose) + Logger.set_verbosity(options.verbose) if len(args) == 0: - Print.error("No bug number specified.") + Logger.error("No bug number specified.") sys.exit(1) elif len(args) > 1: - Print.error("Multiple bug numbers specified: %s" % (", ".join(args))) + Logger.error("Multiple bug numbers specified: %s" % (", ".join(args))) sys.exit(1) bug_number = args[0] if bug_number.isdigit(): bug_number = int(bug_number) else: - Print.error("Invalid bug number specified: %s" % (bug_number)) + Logger.error("Invalid bug number specified: %s" % (bug_number)) sys.exit(1) if options.builder == "pbuilder": @@ -811,7 +777,7 @@ if __name__ == "__main__": elif options.builder == "sbuild": builder = Sbuild() else: - Print.error("Unsupported builder specified: %s. Only pbuilder and " + Logger.error("Unsupported builder specified: %s. Only pbuilder and " "sbuild are supported." % (options.builder)) sys.exit(1) diff --git a/ubuntutools/logger.py b/ubuntutools/logger.py new file mode 100644 index 0000000..db6a016 --- /dev/null +++ b/ubuntutools/logger.py @@ -0,0 +1,55 @@ +# +# logger.py - A simple logging helper class +# +# Copyright (C) 2010, Benjamin Drung +# +# Permission to use, copy, modify, and/or distribute this software +# for any purpose with or without fee is hereby granted, provided +# that the above copyright notice and this permission notice appear +# in all copies. +# +# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL +# WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE +# AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR +# CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM +# LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, +# NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN +# CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +import os +import sys + +class Logger(object): + script_name = os.path.basename(sys.argv[0]) + verbose = False + + @classmethod + def command(cls, cmd): + if cls.verbose: + for i in xrange(len(cmd)): + if cmd[i].find(" ") >= 0: + cmd[i] = '"' + cmd[i] + '"' + print "%s: I: %s" % (cls.script_name, " ".join(cmd)) + + @classmethod + def debug(cls, message): + if cls.verbose: + print "%s: D: %s" % (cls.script_name, message) + + @classmethod + def error(cls, message): + print >> sys.stderr, "%s: Error: %s" % (cls.script_name, message) + + @classmethod + def info(cls, message): + if cls.verbose: + print "%s: I: %s" % (cls.script_name, message) + + @classmethod + def normal(cls, message): + print "%s: %s" % (cls.script_name, message) + + @classmethod + def set_verbosity(cls, verbose): + cls.verbose = verbose