mirror of
https://git.launchpad.net/ubuntu-dev-tools
synced 2025-05-12 01:11:29 +00:00
sponsor-patch: More refactoring.
This commit is contained in:
parent
d52393da1b
commit
1e126f74d1
@ -1,6 +1,6 @@
|
|||||||
#!/usr/bin/python
|
#!/usr/bin/python
|
||||||
#
|
#
|
||||||
# Copyright (C) 2010, Benjamin Drung <bdrung@ubuntu.com>
|
# Copyright (C) 2010-2011, Benjamin Drung <bdrung@ubuntu.com>
|
||||||
#
|
#
|
||||||
# Permission to use, copy, modify, and/or distribute this software for any
|
# Permission to use, copy, modify, and/or distribute this software for any
|
||||||
# purpose with or without fee is hereby granted, provided that the above
|
# purpose with or without fee is hereby granted, provided that the above
|
||||||
@ -26,8 +26,8 @@ from ubuntutools.config import UDTConfig
|
|||||||
from ubuntutools.builder import get_builder
|
from ubuntutools.builder import get_builder
|
||||||
from ubuntutools.sponsor_patch.sponsor_patch import sponsor_patch
|
from ubuntutools.sponsor_patch.sponsor_patch import sponsor_patch
|
||||||
|
|
||||||
def main():
|
def parse(script_name):
|
||||||
script_name = os.path.basename(sys.argv[0])
|
"""Parse the command line parameters."""
|
||||||
usage = ("%s [options] <bug number>\n" % (script_name)
|
usage = ("%s [options] <bug number>\n" % (script_name)
|
||||||
+ "One of --upload, --workdir, or --sponsor must be specified.")
|
+ "One of --upload, --workdir, or --sponsor must be specified.")
|
||||||
epilog = "See %s(1) for more info." % (script_name)
|
epilog = "See %s(1) for more info." % (script_name)
|
||||||
@ -90,14 +90,20 @@ def main():
|
|||||||
if options.workdir is None:
|
if options.workdir is None:
|
||||||
options.workdir = config.get_value("WORKDIR")
|
options.workdir = config.get_value("WORKDIR")
|
||||||
|
|
||||||
builder = get_builder(options.builder)
|
|
||||||
if not builder:
|
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
if options.sponsoring:
|
if options.sponsoring:
|
||||||
options.build = True
|
options.build = True
|
||||||
options.upload = "ubuntu"
|
options.upload = "ubuntu"
|
||||||
|
|
||||||
|
return (options, bug_number)
|
||||||
|
|
||||||
|
def main():
|
||||||
|
script_name = os.path.basename(sys.argv[0])
|
||||||
|
(options, bug_number) = parse(script_name)
|
||||||
|
|
||||||
|
builder = get_builder(options.builder)
|
||||||
|
if not builder:
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
if not options.upload and not options.workdir:
|
if not options.upload and not options.workdir:
|
||||||
Logger.error("Please specify either a working directory or an upload "
|
Logger.error("Please specify either a working directory or an upload "
|
||||||
"target!")
|
"target!")
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
#
|
#
|
||||||
# bugtask.py - Internal helper class for sponsor-patch
|
# bugtask.py - Internal helper class for sponsor-patch
|
||||||
#
|
#
|
||||||
# Copyright (C) 2010, Benjamin Drung <bdrung@ubuntu.com>
|
# Copyright (C) 2010-2011, Benjamin Drung <bdrung@ubuntu.com>
|
||||||
#
|
#
|
||||||
# Permission to use, copy, modify, and/or distribute this software for any
|
# Permission to use, copy, modify, and/or distribute this software for any
|
||||||
# purpose with or without fee is hereby granted, provided that the above
|
# purpose with or without fee is hereby granted, provided that the above
|
||||||
@ -54,14 +54,15 @@ class BugTask(object):
|
|||||||
|
|
||||||
def download_source(self):
|
def download_source(self):
|
||||||
source_files = self.get_source().sourceFileUrls()
|
source_files = self.get_source().sourceFileUrls()
|
||||||
dsc_file = None
|
dsc_file = ""
|
||||||
for url in source_files:
|
for url in source_files:
|
||||||
filename = urllib.unquote(os.path.basename(url))
|
filename = urllib.unquote(os.path.basename(url))
|
||||||
Logger.info("Downloading %s..." % (filename))
|
Logger.info("Downloading %s..." % (filename))
|
||||||
urllib.urlretrieve(url, filename)
|
urllib.urlretrieve(url, filename)
|
||||||
if url.endswith(".dsc"):
|
if url.endswith(".dsc"):
|
||||||
dsc_file = filename
|
dsc_file = os.path.join(os.getcwd(), filename)
|
||||||
return os.path.join(os.getcwd(), dsc_file)
|
assert os.path.isfile(dsc_file), "%s does not exist." % (dsc_file)
|
||||||
|
return dsc_file
|
||||||
|
|
||||||
def get_branch_link(self):
|
def get_branch_link(self):
|
||||||
return "lp:" + self.project + "/" + self.get_series() + "/" + \
|
return "lp:" + self.project + "/" + self.get_series() + "/" + \
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
#
|
#
|
||||||
# patch.py - Internal helper class for sponsor-patch
|
# patch.py - Internal helper class for sponsor-patch
|
||||||
#
|
#
|
||||||
# Copyright (C) 2010, Benjamin Drung <bdrung@ubuntu.com>
|
# Copyright (C) 2010-2011, Benjamin Drung <bdrung@ubuntu.com>
|
||||||
#
|
#
|
||||||
# Permission to use, copy, modify, and/or distribute this software for any
|
# Permission to use, copy, modify, and/or distribute this software for any
|
||||||
# purpose with or without fee is hereby granted, provided that the above
|
# purpose with or without fee is hereby granted, provided that the above
|
||||||
@ -16,31 +16,79 @@
|
|||||||
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
|
||||||
import os
|
import os
|
||||||
|
import re
|
||||||
|
|
||||||
|
from devscripts.logger import Logger
|
||||||
|
|
||||||
from ubuntutools import subprocess
|
from ubuntutools import subprocess
|
||||||
|
from ubuntutools.sponsor_patch.question import ask_for_manual_fixing
|
||||||
|
|
||||||
class Patch(object):
|
class Patch(object):
|
||||||
def __init__(self, patch_file):
|
"""This object represents a patch that can be downloaded from Launchpad."""
|
||||||
self.patch_file = patch_file
|
|
||||||
self.full_path = os.path.realpath(self.patch_file)
|
def __init__(self, patch):
|
||||||
assert os.path.isfile(self.full_path), "%s does not exist." % \
|
self._patch = patch
|
||||||
(self.full_path)
|
self._patch_file = re.sub(" ", "_", patch.title)
|
||||||
cmd = ["diffstat", "-l", "-p0", self.full_path]
|
if not reduce(lambda r, x: r or self._patch.title.endswith(x),
|
||||||
|
(".debdiff", ".diff", ".patch"), False):
|
||||||
|
Logger.info("Patch %s does not have a proper file extension." % \
|
||||||
|
(self._patch.title))
|
||||||
|
self._patch_file += ".patch"
|
||||||
|
self._full_path = os.path.realpath(self._patch_file)
|
||||||
|
self._changed_files = None
|
||||||
|
|
||||||
|
def apply(self, task):
|
||||||
|
"""Applies the patch in the current directory."""
|
||||||
|
assert self._changed_files is not None, \
|
||||||
|
"You forgot to download the patch."
|
||||||
|
edit = False
|
||||||
|
if self.is_debdiff():
|
||||||
|
cmd = ["patch", "--merge", "--force", "-p",
|
||||||
|
str(self.get_strip_level()), "-i", self._full_path]
|
||||||
|
Logger.command(cmd)
|
||||||
|
if subprocess.call(cmd) != 0:
|
||||||
|
Logger.error("Failed to apply debdiff %s to %s %s.",
|
||||||
|
self._patch_file, task.package, task.get_version())
|
||||||
|
if not edit:
|
||||||
|
ask_for_manual_fixing()
|
||||||
|
edit = True
|
||||||
|
else:
|
||||||
|
cmd = ["add-patch", self._full_path]
|
||||||
|
Logger.command(cmd)
|
||||||
|
if subprocess.call(cmd) != 0:
|
||||||
|
Logger.error("Failed to apply diff %s to %s %s.",
|
||||||
|
self._patch_file, task.package, task.get_version())
|
||||||
|
if not edit:
|
||||||
|
ask_for_manual_fixing()
|
||||||
|
edit = True
|
||||||
|
return edit
|
||||||
|
|
||||||
|
def download(self):
|
||||||
|
"""Downloads the patch from Launchpad."""
|
||||||
|
Logger.info("Downloading %s." % (self._patch_file))
|
||||||
|
patch_f = open(self._patch_file, "w")
|
||||||
|
patch_f.write(self._patch.data.open().read())
|
||||||
|
patch_f.close()
|
||||||
|
|
||||||
|
cmd = ["diffstat", "-l", "-p0", self._full_path]
|
||||||
process = subprocess.Popen(cmd, stdout=subprocess.PIPE)
|
process = subprocess.Popen(cmd, stdout=subprocess.PIPE)
|
||||||
changed_files = process.communicate()[0]
|
changed_files = process.communicate()[0]
|
||||||
self.changed_files = [l for l in changed_files.split("\n") if l != ""]
|
self._changed_files = [l for l in changed_files.split("\n") if l != ""]
|
||||||
|
|
||||||
def get_name(self):
|
|
||||||
return self.patch_file
|
|
||||||
|
|
||||||
def get_strip_level(self):
|
def get_strip_level(self):
|
||||||
|
"""Returns the stript level for the patch."""
|
||||||
|
assert self._changed_files is not None, \
|
||||||
|
"You forgot to download the patch."
|
||||||
strip_level = None
|
strip_level = None
|
||||||
if self.is_debdiff():
|
if self.is_debdiff():
|
||||||
changelog = [f for f in self.changed_files
|
changelog = [f for f in self._changed_files
|
||||||
if f.endswith("debian/changelog")][0]
|
if f.endswith("debian/changelog")][0]
|
||||||
strip_level = len(changelog.split(os.sep)) - 2
|
strip_level = len(changelog.split(os.sep)) - 2
|
||||||
return strip_level
|
return strip_level
|
||||||
|
|
||||||
def is_debdiff(self):
|
def is_debdiff(self):
|
||||||
return len([f for f in self.changed_files
|
"""Checks if the patch is a debdiff (= modifies debian/changelog)."""
|
||||||
|
assert self._changed_files is not None, \
|
||||||
|
"You forgot to download the patch."
|
||||||
|
return len([f for f in self._changed_files
|
||||||
if f.endswith("debian/changelog")]) > 0
|
if f.endswith("debian/changelog")]) > 0
|
||||||
|
30
ubuntutools/sponsor_patch/question.py
Normal file
30
ubuntutools/sponsor_patch/question.py
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
#
|
||||||
|
# question.py - Internal helper class for sponsor-patch
|
||||||
|
#
|
||||||
|
# Copyright (C) 2011, Benjamin Drung <bdrung@ubuntu.com>
|
||||||
|
#
|
||||||
|
# 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 sys
|
||||||
|
|
||||||
|
from ubuntutools.question import YesNoQuestion
|
||||||
|
|
||||||
|
def ask_for_manual_fixing():
|
||||||
|
answer = YesNoQuestion().ask("Do you want to resolve this issue manually",
|
||||||
|
"yes")
|
||||||
|
if answer == "no":
|
||||||
|
user_abort()
|
||||||
|
|
||||||
|
def user_abort():
|
||||||
|
print "User abort."
|
||||||
|
sys.exit(2)
|
364
ubuntutools/sponsor_patch/source_package.py
Normal file
364
ubuntutools/sponsor_patch/source_package.py
Normal file
@ -0,0 +1,364 @@
|
|||||||
|
#
|
||||||
|
# source_package.py - Internal helper class for sponsor-patch
|
||||||
|
#
|
||||||
|
# Copyright (C) 2011, Benjamin Drung <bdrung@ubuntu.com>
|
||||||
|
#
|
||||||
|
# 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 re
|
||||||
|
import sys
|
||||||
|
|
||||||
|
import debian.changelog
|
||||||
|
import debian.deb822
|
||||||
|
|
||||||
|
from devscripts.logger import Logger
|
||||||
|
|
||||||
|
from ubuntutools import subprocess
|
||||||
|
from ubuntutools.harvest import Harvest
|
||||||
|
from ubuntutools.question import Question
|
||||||
|
|
||||||
|
from ubuntutools.sponsor_patch.question import ask_for_manual_fixing, user_abort
|
||||||
|
|
||||||
|
def _get_series(launchpad):
|
||||||
|
"""Returns a tuple with the development and list of supported series."""
|
||||||
|
#pylint: disable=E1101
|
||||||
|
ubuntu = launchpad.distributions['ubuntu']
|
||||||
|
#pylint: enable=E1101
|
||||||
|
devel_series = ubuntu.current_series.name
|
||||||
|
supported_series = [series.name for series in ubuntu.series
|
||||||
|
if series.active and series.name != devel_series]
|
||||||
|
return (devel_series, supported_series)
|
||||||
|
|
||||||
|
def strip_epoch(version):
|
||||||
|
"""Removes the epoch from a Debian version string.
|
||||||
|
|
||||||
|
strip_epoch(1:1.52-1) will return "1.52-1" and strip_epoch(1.1.3-1) will
|
||||||
|
return "1.1.3-1".
|
||||||
|
"""
|
||||||
|
|
||||||
|
parts = version.full_version.split(':')
|
||||||
|
if len(parts) > 1:
|
||||||
|
del parts[0]
|
||||||
|
version_without_epoch = ':'.join(parts)
|
||||||
|
return version_without_epoch
|
||||||
|
|
||||||
|
class SourcePackage(object):
|
||||||
|
"""This class represents a source package."""
|
||||||
|
|
||||||
|
def __init__(self, package, builder, workdir, branch):
|
||||||
|
self._package = package
|
||||||
|
self._builder = builder
|
||||||
|
self._workdir = workdir
|
||||||
|
self._branch = branch
|
||||||
|
self._changelog = None
|
||||||
|
self._version = None
|
||||||
|
self._build_log = None
|
||||||
|
|
||||||
|
def ask_and_upload(self, upload):
|
||||||
|
"""Ask the user before uploading the source package.
|
||||||
|
|
||||||
|
Returns true if the source package is uploaded successfully. Returns
|
||||||
|
false if the user wants to change something.
|
||||||
|
"""
|
||||||
|
|
||||||
|
# Upload package
|
||||||
|
if upload:
|
||||||
|
lintian_filename = self._run_lintian()
|
||||||
|
print "\nPlease check %s %s carefully:\nfile://%s\nfile://%s" % \
|
||||||
|
(self._package, self._version, self._debdiff_filename,
|
||||||
|
lintian_filename)
|
||||||
|
if self._build_log:
|
||||||
|
print "file://%s" % self._build_log
|
||||||
|
|
||||||
|
harvest = Harvest(self._package)
|
||||||
|
if harvest.data:
|
||||||
|
print harvest.report()
|
||||||
|
|
||||||
|
if upload == "ubuntu":
|
||||||
|
target = "the official Ubuntu archive"
|
||||||
|
else:
|
||||||
|
target = upload
|
||||||
|
question = Question(["yes", "edit", "no"])
|
||||||
|
answer = question.ask("Do you want to upload the package to %s" % \
|
||||||
|
target, "no")
|
||||||
|
if answer == "edit":
|
||||||
|
return False
|
||||||
|
elif answer == "no":
|
||||||
|
user_abort()
|
||||||
|
cmd = ["dput", "--force", upload, self._changes_file]
|
||||||
|
Logger.command(cmd)
|
||||||
|
if subprocess.call(cmd) != 0:
|
||||||
|
Logger.error("Upload of %s to %s failed." % \
|
||||||
|
(os.path.basename(self._changes_file), upload))
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
# Push the branch if the package is uploaded to the Ubuntu archive.
|
||||||
|
if upload == "ubuntu" and self._branch:
|
||||||
|
cmd = ['debcommit']
|
||||||
|
Logger.command(cmd)
|
||||||
|
if subprocess.call(cmd) != 0:
|
||||||
|
Logger.error('Bzr commit failed.')
|
||||||
|
sys.exit(1)
|
||||||
|
cmd = ['bzr', 'mark-uploaded']
|
||||||
|
Logger.command(cmd)
|
||||||
|
if subprocess.call(cmd) != 0:
|
||||||
|
Logger.error('Bzr tagging failed.')
|
||||||
|
sys.exit(1)
|
||||||
|
cmd = ['bzr', 'push', ':parent']
|
||||||
|
Logger.command(cmd)
|
||||||
|
if subprocess.call(cmd) != 0:
|
||||||
|
Logger.error('Bzr push failed.')
|
||||||
|
sys.exit(1)
|
||||||
|
return True
|
||||||
|
|
||||||
|
def build(self, update):
|
||||||
|
"""Tries to build the package.
|
||||||
|
|
||||||
|
Returns true if the package was built successfully. Returns false
|
||||||
|
if the user wants to change something.
|
||||||
|
"""
|
||||||
|
|
||||||
|
dist = re.sub("-.*$", "", self._changelog.distributions)
|
||||||
|
build_name = self._package + "_" + strip_epoch(self._version) + \
|
||||||
|
"_" + self._builder.get_architecture() + ".build"
|
||||||
|
self._build_log = os.path.join(self._buildresult, build_name)
|
||||||
|
|
||||||
|
successful_built = False
|
||||||
|
while not successful_built:
|
||||||
|
if update:
|
||||||
|
ret = self._builder.update(dist)
|
||||||
|
if ret != 0:
|
||||||
|
ask_for_manual_fixing()
|
||||||
|
break
|
||||||
|
# We want to update the build environment only once, but not
|
||||||
|
# after every manual fix.
|
||||||
|
update = False
|
||||||
|
|
||||||
|
# build package
|
||||||
|
result = self._builder.build(self._dsc_file, dist,
|
||||||
|
self._buildresult)
|
||||||
|
if result != 0:
|
||||||
|
question = Question(["yes", "update", "retry", "no"])
|
||||||
|
answer = question.ask("Do you want to resolve this issue "
|
||||||
|
"manually", "yes")
|
||||||
|
if answer == "yes":
|
||||||
|
break
|
||||||
|
elif answer == "update":
|
||||||
|
update = True
|
||||||
|
continue
|
||||||
|
elif answer == "retry":
|
||||||
|
continue
|
||||||
|
else:
|
||||||
|
user_abort()
|
||||||
|
successful_built = True
|
||||||
|
if not successful_built:
|
||||||
|
# We want to do a manual fix if the build failed.
|
||||||
|
return False
|
||||||
|
return True
|
||||||
|
|
||||||
|
@property
|
||||||
|
def _buildresult(self):
|
||||||
|
"""Returns the directory for the build result."""
|
||||||
|
return os.path.join(self._workdir, "buildresult")
|
||||||
|
|
||||||
|
def build_source(self, keyid, upload, previous_version):
|
||||||
|
"""Tries to build the source package.
|
||||||
|
|
||||||
|
Returns true if the source package was built successfully. Returns false
|
||||||
|
if the user wants to change something.
|
||||||
|
"""
|
||||||
|
|
||||||
|
if self._branch:
|
||||||
|
cmd = ['bzr', 'builddeb', '-S', '--', '--no-lintian']
|
||||||
|
else:
|
||||||
|
cmd = ['debuild', '--no-lintian', '-S']
|
||||||
|
cmd.append("-v" + previous_version.full_version)
|
||||||
|
if previous_version.upstream_version == \
|
||||||
|
self._changelog.upstream_version and upload == "ubuntu":
|
||||||
|
# FIXME: Add proper check that catches cases like changed
|
||||||
|
# compression (.tar.gz -> tar.bz2) and multiple orig source tarballs
|
||||||
|
cmd.append("-sd")
|
||||||
|
else:
|
||||||
|
cmd.append("-sa")
|
||||||
|
if not keyid is None:
|
||||||
|
cmd += ["-k" + keyid]
|
||||||
|
env = os.environ
|
||||||
|
if upload == 'ubuntu':
|
||||||
|
env['DEB_VENDOR'] = 'Ubuntu'
|
||||||
|
Logger.command(cmd)
|
||||||
|
if subprocess.call(cmd, env=env) != 0:
|
||||||
|
Logger.error("Failed to build source tarball.")
|
||||||
|
# TODO: Add a "retry" option
|
||||||
|
ask_for_manual_fixing()
|
||||||
|
return False
|
||||||
|
return True
|
||||||
|
|
||||||
|
@property
|
||||||
|
def _changes_file(self):
|
||||||
|
"""Returns the file name of the .changes file."""
|
||||||
|
return os.path.join(self._workdir, self._package + "_" +
|
||||||
|
strip_epoch(self._version) +
|
||||||
|
"_source.changes")
|
||||||
|
|
||||||
|
def check_target(self, upload, launchpad):
|
||||||
|
"""Make sure that the target is correct.
|
||||||
|
|
||||||
|
Returns true if the target is correct. Returns false if the user
|
||||||
|
wants to change something.
|
||||||
|
"""
|
||||||
|
|
||||||
|
(devel_series, supported_series) = _get_series(launchpad)
|
||||||
|
|
||||||
|
if upload == "ubuntu":
|
||||||
|
allowed = [s + "-proposed" for s in supported_series] + \
|
||||||
|
[devel_series]
|
||||||
|
if self._changelog.distributions not in allowed:
|
||||||
|
Logger.error(("%s is not an allowed series. It needs to be one "
|
||||||
|
"of %s.") % (self._changelog.distributions,
|
||||||
|
", ".join(allowed)))
|
||||||
|
ask_for_manual_fixing()
|
||||||
|
return False
|
||||||
|
elif upload and upload.startswith("ppa/"):
|
||||||
|
allowed = supported_series + [devel_series]
|
||||||
|
if self._changelog.distributions not in allowed:
|
||||||
|
Logger.error(("%s is not an allowed series. It needs to be one "
|
||||||
|
"of %s.") % (self._changelog.distributions,
|
||||||
|
", ".join(allowed)))
|
||||||
|
ask_for_manual_fixing()
|
||||||
|
return False
|
||||||
|
return True
|
||||||
|
|
||||||
|
def check_version(self, previous_version):
|
||||||
|
"""Check if the version of the package is greater than the given one.
|
||||||
|
|
||||||
|
Return true if the version of the package is newer. Returns false
|
||||||
|
if the user wants to change something.
|
||||||
|
"""
|
||||||
|
|
||||||
|
if self._version <= previous_version:
|
||||||
|
Logger.error("The version %s is not greater than the already "
|
||||||
|
"available %s.", self._version, previous_version)
|
||||||
|
ask_for_manual_fixing()
|
||||||
|
return False
|
||||||
|
return True
|
||||||
|
|
||||||
|
@property
|
||||||
|
def _debdiff_filename(self):
|
||||||
|
"""Returns the file name of the .debdiff file."""
|
||||||
|
debdiff_name = self._package + "_" + strip_epoch(self._version) + \
|
||||||
|
".debdiff"
|
||||||
|
return os.path.join(self._workdir, debdiff_name)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def _dsc_file(self):
|
||||||
|
"""Returns the file name of the .dsc file."""
|
||||||
|
return os.path.join(self._workdir, self._package + "_" +
|
||||||
|
strip_epoch(self._version) + ".dsc")
|
||||||
|
|
||||||
|
def generate_debdiff(self, dsc_file):
|
||||||
|
"""Generates a debdiff between the given .dsc file and this source
|
||||||
|
package."""
|
||||||
|
|
||||||
|
assert os.path.isfile(dsc_file), "%s does not exist." % (dsc_file)
|
||||||
|
assert os.path.isfile(self._dsc_file), "%s does not exist." % \
|
||||||
|
(self._dsc_file)
|
||||||
|
cmd = ["debdiff", dsc_file, self._dsc_file]
|
||||||
|
if not Logger.verbose:
|
||||||
|
cmd.insert(1, "-q")
|
||||||
|
Logger.command(cmd + [">", self._debdiff_filename])
|
||||||
|
process = subprocess.Popen(cmd, stdout=subprocess.PIPE)
|
||||||
|
debdiff = process.communicate()[0]
|
||||||
|
|
||||||
|
# write debdiff file
|
||||||
|
debdiff_file = open(self._debdiff_filename, "w")
|
||||||
|
debdiff_file.writelines(debdiff)
|
||||||
|
debdiff_file.close()
|
||||||
|
|
||||||
|
def is_fixed(self, bug_number):
|
||||||
|
"""Make sure that the given bug number is closed.
|
||||||
|
|
||||||
|
Returns true if the bug is closed. Returns false if the user wants to
|
||||||
|
change something.
|
||||||
|
"""
|
||||||
|
|
||||||
|
assert os.path.isfile(self._changes_file), "%s does not exist." % \
|
||||||
|
(self._changes_file)
|
||||||
|
changes = debian.deb822.Changes(file(self._changes_file))
|
||||||
|
fixed_bugs = []
|
||||||
|
if "Launchpad-Bugs-Fixed" in changes:
|
||||||
|
fixed_bugs = changes["Launchpad-Bugs-Fixed"].split(" ")
|
||||||
|
fixed_bugs = [int(bug) for bug in fixed_bugs]
|
||||||
|
|
||||||
|
if bug_number not in fixed_bugs:
|
||||||
|
Logger.error("Launchpad bug #%i is not closed by new version." % \
|
||||||
|
(bug_number))
|
||||||
|
ask_for_manual_fixing()
|
||||||
|
return False
|
||||||
|
return True
|
||||||
|
|
||||||
|
def reload_changelog(self):
|
||||||
|
"""Reloads debian/changelog and update version."""
|
||||||
|
|
||||||
|
# Check the changelog
|
||||||
|
self._changelog = debian.changelog.Changelog()
|
||||||
|
try:
|
||||||
|
self._changelog.parse_changelog(file("debian/changelog"),
|
||||||
|
max_blocks=1, strict=True)
|
||||||
|
except debian.changelog.ChangelogParseError, error:
|
||||||
|
Logger.error("The changelog entry doesn't validate: %s", str(error))
|
||||||
|
ask_for_manual_fixing()
|
||||||
|
return False
|
||||||
|
|
||||||
|
# Get new version of package
|
||||||
|
try:
|
||||||
|
self._version = self._changelog.get_version()
|
||||||
|
except IndexError:
|
||||||
|
Logger.error("Debian package version could not be determined. " \
|
||||||
|
"debian/changelog is probably malformed.")
|
||||||
|
ask_for_manual_fixing()
|
||||||
|
return False
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
def _run_lintian(self):
|
||||||
|
"""Runs lintian on either the source or binary changes file.
|
||||||
|
|
||||||
|
Returns the filename of the created lintian output file.
|
||||||
|
"""
|
||||||
|
|
||||||
|
# Determine whether to use the source or binary build for lintian
|
||||||
|
if self._build_log:
|
||||||
|
build_changes = self._package + "_" + strip_epoch(self._version) + \
|
||||||
|
"_" + self._builder.get_architecture() + ".changes"
|
||||||
|
changes_for_lintian = os.path.join(self._buildresult, build_changes)
|
||||||
|
else:
|
||||||
|
changes_for_lintian = self._changes_file
|
||||||
|
|
||||||
|
# Check lintian
|
||||||
|
assert os.path.isfile(changes_for_lintian), "%s does not exist." % \
|
||||||
|
(changes_for_lintian)
|
||||||
|
cmd = ["lintian", "-IE", "--pedantic", "-q", changes_for_lintian]
|
||||||
|
lintian_filename = os.path.join(self._workdir,
|
||||||
|
self._package + "_" +
|
||||||
|
strip_epoch(self._version) + ".lintian")
|
||||||
|
Logger.command(cmd + [">", lintian_filename])
|
||||||
|
process = subprocess.Popen(cmd, stdout=subprocess.PIPE)
|
||||||
|
report = process.communicate()[0]
|
||||||
|
|
||||||
|
# write lintian report file
|
||||||
|
lintian_file = open(lintian_filename, "w")
|
||||||
|
lintian_file.writelines(report)
|
||||||
|
lintian_file.close()
|
||||||
|
|
||||||
|
return lintian_filename
|
@ -17,27 +17,21 @@
|
|||||||
|
|
||||||
import os
|
import os
|
||||||
import pwd
|
import pwd
|
||||||
import re
|
|
||||||
import shutil
|
import shutil
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
import debian.changelog
|
|
||||||
import debian.deb822
|
|
||||||
import launchpadlib.launchpad
|
import launchpadlib.launchpad
|
||||||
|
|
||||||
from devscripts.logger import Logger
|
from devscripts.logger import Logger
|
||||||
|
|
||||||
from ubuntutools import subprocess
|
from ubuntutools import subprocess
|
||||||
from ubuntutools.harvest import Harvest
|
|
||||||
from ubuntutools.update_maintainer import update_maintainer
|
from ubuntutools.update_maintainer import update_maintainer
|
||||||
from ubuntutools.question import Question, YesNoQuestion, input_number
|
from ubuntutools.question import input_number
|
||||||
|
|
||||||
from ubuntutools.sponsor_patch.bugtask import BugTask
|
from ubuntutools.sponsor_patch.bugtask import BugTask
|
||||||
from ubuntutools.sponsor_patch.patch import Patch
|
from ubuntutools.sponsor_patch.patch import Patch
|
||||||
|
from ubuntutools.sponsor_patch.question import ask_for_manual_fixing
|
||||||
def user_abort():
|
from ubuntutools.sponsor_patch.source_package import SourcePackage
|
||||||
print "User abort."
|
|
||||||
sys.exit(2)
|
|
||||||
|
|
||||||
def get_source_package_name(bug_task):
|
def get_source_package_name(bug_task):
|
||||||
package = None
|
package = None
|
||||||
@ -67,26 +61,6 @@ process, exit the shell such that it returns an exit code other than zero.
|
|||||||
Logger.error("Shell exited with exit value %i." % (returncode))
|
Logger.error("Shell exited with exit value %i." % (returncode))
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
def strip_epoch(version):
|
|
||||||
"""Removes the epoch from a Debian version string.
|
|
||||||
|
|
||||||
strip_epoch(1:1.52-1) will return "1.52-1" and strip_epoch(1.1.3-1) will
|
|
||||||
return "1.1.3-1".
|
|
||||||
|
|
||||||
"""
|
|
||||||
|
|
||||||
parts = version.full_version.split(':')
|
|
||||||
if len(parts) > 1:
|
|
||||||
del parts[0]
|
|
||||||
version_without_epoch = ':'.join(parts)
|
|
||||||
return version_without_epoch
|
|
||||||
|
|
||||||
def ask_for_manual_fixing():
|
|
||||||
answer = YesNoQuestion().ask("Do you want to resolve this issue manually",
|
|
||||||
"yes")
|
|
||||||
if answer == "no":
|
|
||||||
user_abort()
|
|
||||||
|
|
||||||
def ask_for_patch_or_branch(bug, attached_patches, linked_branches):
|
def ask_for_patch_or_branch(bug, attached_patches, linked_branches):
|
||||||
patch = None
|
patch = None
|
||||||
branch = None
|
branch = None
|
||||||
@ -118,7 +92,7 @@ def ask_for_patch_or_branch(bug, attached_patches, linked_branches):
|
|||||||
if selected <= len(linked_branches):
|
if selected <= len(linked_branches):
|
||||||
branch = linked_branches[selected - 1].bzr_identity
|
branch = linked_branches[selected - 1].bzr_identity
|
||||||
else:
|
else:
|
||||||
patch = attached_patches[selected - len(linked_branches) - 1]
|
patch = Patch(attached_patches[selected - len(linked_branches) - 1])
|
||||||
return (patch, branch)
|
return (patch, branch)
|
||||||
|
|
||||||
def get_patch_or_branch(bug):
|
def get_patch_or_branch(bug):
|
||||||
@ -136,7 +110,7 @@ def get_patch_or_branch(bug):
|
|||||||
"attachment as patch.") % bug.id)
|
"attachment as patch.") % bug.id)
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
elif len(attached_patches) == 1 and len(linked_branches) == 0:
|
elif len(attached_patches) == 1 and len(linked_branches) == 0:
|
||||||
patch = attached_patches[0]
|
patch = Patch(attached_patches[0])
|
||||||
elif len(attached_patches) == 0 and len(linked_branches) == 1:
|
elif len(attached_patches) == 0 and len(linked_branches) == 1:
|
||||||
branch = linked_branches[0].bzr_identity
|
branch = linked_branches[0].bzr_identity
|
||||||
else:
|
else:
|
||||||
@ -144,20 +118,6 @@ def get_patch_or_branch(bug):
|
|||||||
linked_branches)
|
linked_branches)
|
||||||
return (patch, branch)
|
return (patch, branch)
|
||||||
|
|
||||||
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):
|
|
||||||
Logger.info("Patch %s does not have a proper file extension." % \
|
|
||||||
(patch.title))
|
|
||||||
patch_filename += ".patch"
|
|
||||||
|
|
||||||
Logger.info("Downloading %s." % (patch_filename))
|
|
||||||
patch_file = open(patch_filename, "w")
|
|
||||||
patch_file.write(patch.data.open().read())
|
|
||||||
patch_file.close()
|
|
||||||
return Patch(patch_filename)
|
|
||||||
|
|
||||||
def download_branch(branch):
|
def download_branch(branch):
|
||||||
dir_name = os.path.basename(branch)
|
dir_name = os.path.basename(branch)
|
||||||
if os.path.isdir(dir_name):
|
if os.path.isdir(dir_name):
|
||||||
@ -188,29 +148,6 @@ def extract_source(dsc_file, verbose=False):
|
|||||||
Logger.error("Extraction of %s failed." % (os.path.basename(dsc_file)))
|
Logger.error("Extraction of %s failed." % (os.path.basename(dsc_file)))
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
def apply_patch(task, patch):
|
|
||||||
edit = False
|
|
||||||
if patch.is_debdiff():
|
|
||||||
cmd = ["patch", "--merge", "--force", "-p",
|
|
||||||
str(patch.get_strip_level()), "-i", patch.full_path]
|
|
||||||
Logger.command(cmd)
|
|
||||||
if subprocess.call(cmd) != 0:
|
|
||||||
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()
|
|
||||||
edit = True
|
|
||||||
else:
|
|
||||||
cmd = ["add-patch", patch.full_path]
|
|
||||||
Logger.command(cmd)
|
|
||||||
if subprocess.call(cmd) != 0:
|
|
||||||
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()
|
|
||||||
edit = True
|
|
||||||
return edit
|
|
||||||
|
|
||||||
def get_open_ubuntu_bug_task(launchpad, bug):
|
def get_open_ubuntu_bug_task(launchpad, bug):
|
||||||
"""Returns an open Ubuntu bug task for a given Launchpad bug.
|
"""Returns an open Ubuntu bug task for a given Launchpad bug.
|
||||||
|
|
||||||
@ -258,16 +195,6 @@ def _create_and_change_into(workdir):
|
|||||||
Logger.command(["cd", workdir])
|
Logger.command(["cd", workdir])
|
||||||
os.chdir(workdir)
|
os.chdir(workdir)
|
||||||
|
|
||||||
def _get_series(launchpad):
|
|
||||||
"""Returns a tuple with the development and list of supported series."""
|
|
||||||
#pylint: disable=E1101
|
|
||||||
ubuntu = launchpad.distributions['ubuntu']
|
|
||||||
#pylint: enable=E1101
|
|
||||||
devel_series = ubuntu.current_series.name
|
|
||||||
supported_series = [series.name for series in ubuntu.series
|
|
||||||
if series.active and series.name != devel_series]
|
|
||||||
return (devel_series, supported_series)
|
|
||||||
|
|
||||||
def _update_maintainer_field():
|
def _update_maintainer_field():
|
||||||
"""Update the Maintainer field in debian/control."""
|
"""Update the Maintainer field in debian/control."""
|
||||||
Logger.command(["update-maintainer"])
|
Logger.command(["update-maintainer"])
|
||||||
@ -282,317 +209,28 @@ def _update_timestamp():
|
|||||||
if subprocess.call(cmd) != 0:
|
if subprocess.call(cmd) != 0:
|
||||||
Logger.info("Failed to update timestamp in debian/changelog.")
|
Logger.info("Failed to update timestamp in debian/changelog.")
|
||||||
|
|
||||||
|
def _download_and_change_into(task, dsc_file, patch, branch):
|
||||||
|
"""Downloads the patch and branch and changes into the source directory."""
|
||||||
|
|
||||||
class SourcePackage(object):
|
if patch:
|
||||||
"""This class represents a source package."""
|
patch.download()
|
||||||
|
|
||||||
def __init__(self, package, builder, workdir, branch):
|
Logger.info("Ubuntu package: %s" % (task.package))
|
||||||
self._package = package
|
if task.is_merge():
|
||||||
self._builder = builder
|
Logger.info("The task is a merge request.")
|
||||||
self._workdir = workdir
|
|
||||||
self._branch = branch
|
|
||||||
self._changelog = None
|
|
||||||
self._version = None
|
|
||||||
self._build_log = None
|
|
||||||
|
|
||||||
def ask_and_upload(self, upload):
|
extract_source(dsc_file, Logger.verbose)
|
||||||
"""Ask the user before uploading the source package.
|
|
||||||
|
|
||||||
Returns true if the source package is uploaded successfully. Returns
|
|
||||||
false if the user wants to change something.
|
|
||||||
"""
|
|
||||||
|
|
||||||
# Upload package
|
# change directory
|
||||||
if upload:
|
directory = task.package + '-' + task.get_version().upstream_version
|
||||||
lintian_filename = self._run_lintian()
|
Logger.command(["cd", directory])
|
||||||
print "\nPlease check %s %s carefully:\nfile://%s\nfile://%s" % \
|
os.chdir(directory)
|
||||||
(self._package, self._version, self._debdiff_filename,
|
elif branch:
|
||||||
lintian_filename)
|
branch_dir = download_branch(task.get_branch_link())
|
||||||
if self._build_log:
|
|
||||||
print "file://%s" % self._build_log
|
|
||||||
|
|
||||||
harvest = Harvest(self._package)
|
|
||||||
if harvest.data:
|
|
||||||
print harvest.report()
|
|
||||||
|
|
||||||
if upload == "ubuntu":
|
|
||||||
target = "the official Ubuntu archive"
|
|
||||||
else:
|
|
||||||
target = upload
|
|
||||||
question = Question(["yes", "edit", "no"])
|
|
||||||
answer = question.ask("Do you want to upload the package to %s" % \
|
|
||||||
target, "no")
|
|
||||||
if answer == "edit":
|
|
||||||
return False
|
|
||||||
elif answer == "no":
|
|
||||||
user_abort()
|
|
||||||
cmd = ["dput", "--force", upload, self._changes_file]
|
|
||||||
Logger.command(cmd)
|
|
||||||
if subprocess.call(cmd) != 0:
|
|
||||||
Logger.error("Upload of %s to %s failed." % \
|
|
||||||
(os.path.basename(self._changes_file), upload))
|
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
# Push the branch if the package is uploaded to the Ubuntu archive.
|
|
||||||
if upload == "ubuntu" and self._branch:
|
|
||||||
cmd = ['debcommit']
|
|
||||||
Logger.command(cmd)
|
|
||||||
if subprocess.call(cmd) != 0:
|
|
||||||
Logger.error('Bzr commit failed.')
|
|
||||||
sys.exit(1)
|
|
||||||
cmd = ['bzr', 'mark-uploaded']
|
|
||||||
Logger.command(cmd)
|
|
||||||
if subprocess.call(cmd) != 0:
|
|
||||||
Logger.error('Bzr tagging failed.')
|
|
||||||
sys.exit(1)
|
|
||||||
cmd = ['bzr', 'push', ':parent']
|
|
||||||
Logger.command(cmd)
|
|
||||||
if subprocess.call(cmd) != 0:
|
|
||||||
Logger.error('Bzr push failed.')
|
|
||||||
sys.exit(1)
|
|
||||||
return True
|
|
||||||
|
|
||||||
def build(self, update):
|
|
||||||
"""Tries to build the package.
|
|
||||||
|
|
||||||
Returns true if the package was built successfully. Returns false
|
|
||||||
if the user wants to change something.
|
|
||||||
"""
|
|
||||||
|
|
||||||
dist = re.sub("-.*$", "", self._changelog.distributions)
|
|
||||||
build_name = self._package + "_" + strip_epoch(self._version) + \
|
|
||||||
"_" + self._builder.get_architecture() + ".build"
|
|
||||||
self._build_log = os.path.join(self._buildresult, build_name)
|
|
||||||
|
|
||||||
successful_built = False
|
|
||||||
while not successful_built:
|
|
||||||
if update:
|
|
||||||
ret = self._builder.update(dist)
|
|
||||||
if ret != 0:
|
|
||||||
ask_for_manual_fixing()
|
|
||||||
break
|
|
||||||
# We want to update the build environment only once, but not
|
|
||||||
# after every manual fix.
|
|
||||||
update = False
|
|
||||||
|
|
||||||
# build package
|
|
||||||
result = self._builder.build(self._dsc_file, dist,
|
|
||||||
self._buildresult)
|
|
||||||
if result != 0:
|
|
||||||
question = Question(["yes", "update", "retry", "no"])
|
|
||||||
answer = question.ask("Do you want to resolve this issue "
|
|
||||||
"manually", "yes")
|
|
||||||
if answer == "yes":
|
|
||||||
break
|
|
||||||
elif answer == "update":
|
|
||||||
update = True
|
|
||||||
continue
|
|
||||||
elif answer == "retry":
|
|
||||||
continue
|
|
||||||
else:
|
|
||||||
user_abort()
|
|
||||||
successful_built = True
|
|
||||||
if not successful_built:
|
|
||||||
# We want to do a manual fix if the build failed.
|
|
||||||
return False
|
|
||||||
return True
|
|
||||||
|
|
||||||
@property
|
|
||||||
def _buildresult(self):
|
|
||||||
"""Returns the directory for the build result."""
|
|
||||||
return os.path.join(self._workdir, "buildresult")
|
|
||||||
|
|
||||||
def build_source(self, keyid, upload, previous_version):
|
|
||||||
"""Tries to build the source package.
|
|
||||||
|
|
||||||
Returns true if the source package was built successfully. Returns false
|
|
||||||
if the user wants to change something.
|
|
||||||
"""
|
|
||||||
|
|
||||||
if self._branch:
|
|
||||||
cmd = ['bzr', 'builddeb', '-S', '--', '--no-lintian']
|
|
||||||
else:
|
|
||||||
cmd = ['debuild', '--no-lintian', '-S']
|
|
||||||
cmd.append("-v" + previous_version.full_version)
|
|
||||||
if previous_version.upstream_version == \
|
|
||||||
self._changelog.upstream_version and upload == "ubuntu":
|
|
||||||
# FIXME: Add proper check that catches cases like changed
|
|
||||||
# compression (.tar.gz -> tar.bz2) and multiple orig source tarballs
|
|
||||||
cmd.append("-sd")
|
|
||||||
else:
|
|
||||||
cmd.append("-sa")
|
|
||||||
if not keyid is None:
|
|
||||||
cmd += ["-k" + keyid]
|
|
||||||
env = os.environ
|
|
||||||
if upload == 'ubuntu':
|
|
||||||
env['DEB_VENDOR'] = 'Ubuntu'
|
|
||||||
Logger.command(cmd)
|
|
||||||
if subprocess.call(cmd, env=env) != 0:
|
|
||||||
Logger.error("Failed to build source tarball.")
|
|
||||||
# TODO: Add a "retry" option
|
|
||||||
ask_for_manual_fixing()
|
|
||||||
return False
|
|
||||||
return True
|
|
||||||
|
|
||||||
@property
|
|
||||||
def _changes_file(self):
|
|
||||||
"""Returns the file name of the .changes file."""
|
|
||||||
return os.path.join(self._workdir, self._package + "_" +
|
|
||||||
strip_epoch(self._version) +
|
|
||||||
"_source.changes")
|
|
||||||
|
|
||||||
def check_target(self, upload, launchpad):
|
|
||||||
"""Make sure that the target is correct.
|
|
||||||
|
|
||||||
Returns true if the target is correct. Returns false if the user
|
|
||||||
wants to change something.
|
|
||||||
"""
|
|
||||||
|
|
||||||
(devel_series, supported_series) = _get_series(launchpad)
|
|
||||||
|
|
||||||
if upload == "ubuntu":
|
|
||||||
allowed = [s + "-proposed" for s in supported_series] + \
|
|
||||||
[devel_series]
|
|
||||||
if self._changelog.distributions not in allowed:
|
|
||||||
Logger.error(("%s is not an allowed series. It needs to be one "
|
|
||||||
"of %s.") % (self._changelog.distributions,
|
|
||||||
", ".join(allowed)))
|
|
||||||
ask_for_manual_fixing()
|
|
||||||
return False
|
|
||||||
elif upload and upload.startswith("ppa/"):
|
|
||||||
allowed = supported_series + [devel_series]
|
|
||||||
if self._changelog.distributions not in allowed:
|
|
||||||
Logger.error(("%s is not an allowed series. It needs to be one "
|
|
||||||
"of %s.") % (self._changelog.distributions,
|
|
||||||
", ".join(allowed)))
|
|
||||||
ask_for_manual_fixing()
|
|
||||||
return False
|
|
||||||
return True
|
|
||||||
|
|
||||||
def check_version(self, previous_version):
|
|
||||||
"""Check if the version of the package is greater than the given one.
|
|
||||||
|
|
||||||
Return true if the version of the package is newer. Returns false
|
|
||||||
if the user wants to change something.
|
|
||||||
"""
|
|
||||||
|
|
||||||
if self._version <= previous_version:
|
|
||||||
Logger.error("The version %s is not greater than the already "
|
|
||||||
"available %s.", self._version, previous_version)
|
|
||||||
ask_for_manual_fixing()
|
|
||||||
return False
|
|
||||||
return True
|
|
||||||
|
|
||||||
@property
|
|
||||||
def _debdiff_filename(self):
|
|
||||||
"""Returns the file name of the .debdiff file."""
|
|
||||||
debdiff_name = self._package + "_" + strip_epoch(self._version) + \
|
|
||||||
".debdiff"
|
|
||||||
return os.path.join(self._workdir, debdiff_name)
|
|
||||||
|
|
||||||
@property
|
|
||||||
def _dsc_file(self):
|
|
||||||
"""Returns the file name of the .dsc file."""
|
|
||||||
return os.path.join(self._workdir, self._package + "_" +
|
|
||||||
strip_epoch(self._version) + ".dsc")
|
|
||||||
|
|
||||||
def generate_debdiff(self, dsc_file):
|
|
||||||
"""Generates a debdiff between the given .dsc file and this source
|
|
||||||
package."""
|
|
||||||
|
|
||||||
assert os.path.isfile(dsc_file), "%s does not exist." % (dsc_file)
|
|
||||||
assert os.path.isfile(self._dsc_file), "%s does not exist." % \
|
|
||||||
(self._dsc_file)
|
|
||||||
cmd = ["debdiff", dsc_file, self._dsc_file]
|
|
||||||
if not Logger.verbose:
|
|
||||||
cmd.insert(1, "-q")
|
|
||||||
Logger.command(cmd + [">", self._debdiff_filename])
|
|
||||||
process = subprocess.Popen(cmd, stdout=subprocess.PIPE)
|
|
||||||
debdiff = process.communicate()[0]
|
|
||||||
|
|
||||||
# write debdiff file
|
|
||||||
debdiff_file = open(self._debdiff_filename, "w")
|
|
||||||
debdiff_file.writelines(debdiff)
|
|
||||||
debdiff_file.close()
|
|
||||||
|
|
||||||
def is_fixed(self, bug_number):
|
|
||||||
"""Make sure that the given bug number is closed.
|
|
||||||
|
|
||||||
Returns true if the bug is closed. Returns false if the user wants to
|
|
||||||
change something.
|
|
||||||
"""
|
|
||||||
|
|
||||||
assert os.path.isfile(self._changes_file), "%s does not exist." % \
|
|
||||||
(self._changes_file)
|
|
||||||
changes = debian.deb822.Changes(file(self._changes_file))
|
|
||||||
fixed_bugs = []
|
|
||||||
if "Launchpad-Bugs-Fixed" in changes:
|
|
||||||
fixed_bugs = changes["Launchpad-Bugs-Fixed"].split(" ")
|
|
||||||
fixed_bugs = [int(bug) for bug in fixed_bugs]
|
|
||||||
|
|
||||||
if bug_number not in fixed_bugs:
|
|
||||||
Logger.error("Launchpad bug #%i is not closed by new version." % \
|
|
||||||
(bug_number))
|
|
||||||
ask_for_manual_fixing()
|
|
||||||
return False
|
|
||||||
return True
|
|
||||||
|
|
||||||
def reload_changelog(self):
|
|
||||||
"""Reloads debian/changelog and update version."""
|
|
||||||
|
|
||||||
# Check the changelog
|
|
||||||
self._changelog = debian.changelog.Changelog()
|
|
||||||
try:
|
|
||||||
self._changelog.parse_changelog(file("debian/changelog"),
|
|
||||||
max_blocks=1, strict=True)
|
|
||||||
except debian.changelog.ChangelogParseError, error:
|
|
||||||
Logger.error("The changelog entry doesn't validate: %s", str(error))
|
|
||||||
ask_for_manual_fixing()
|
|
||||||
return False
|
|
||||||
|
|
||||||
# Get new version of package
|
|
||||||
try:
|
|
||||||
self._version = self._changelog.get_version()
|
|
||||||
except IndexError:
|
|
||||||
Logger.error("Debian package version could not be determined. " \
|
|
||||||
"debian/changelog is probably malformed.")
|
|
||||||
ask_for_manual_fixing()
|
|
||||||
return False
|
|
||||||
|
|
||||||
return True
|
|
||||||
|
|
||||||
def _run_lintian(self):
|
|
||||||
"""Runs lintian on either the source or binary changes file.
|
|
||||||
|
|
||||||
Returns the filename of the created lintian output file.
|
|
||||||
"""
|
|
||||||
|
|
||||||
# Determine whether to use the source or binary build for lintian
|
|
||||||
if self._build_log:
|
|
||||||
build_changes = self._package + "_" + strip_epoch(self._version) + \
|
|
||||||
"_" + self._builder.get_architecture() + ".changes"
|
|
||||||
changes_for_lintian = os.path.join(self._buildresult, build_changes)
|
|
||||||
else:
|
|
||||||
changes_for_lintian = self._changes_file
|
|
||||||
|
|
||||||
# Check lintian
|
|
||||||
assert os.path.isfile(changes_for_lintian), "%s does not exist." % \
|
|
||||||
(changes_for_lintian)
|
|
||||||
cmd = ["lintian", "-IE", "--pedantic", "-q", changes_for_lintian]
|
|
||||||
lintian_filename = os.path.join(self._workdir,
|
|
||||||
self._package + "_" +
|
|
||||||
strip_epoch(self._version) + ".lintian")
|
|
||||||
Logger.command(cmd + [">", lintian_filename])
|
|
||||||
process = subprocess.Popen(cmd, stdout=subprocess.PIPE)
|
|
||||||
report = process.communicate()[0]
|
|
||||||
|
|
||||||
# write lintian report file
|
|
||||||
lintian_file = open(lintian_filename, "w")
|
|
||||||
lintian_file.writelines(report)
|
|
||||||
lintian_file.close()
|
|
||||||
|
|
||||||
return lintian_filename
|
|
||||||
|
|
||||||
|
# change directory
|
||||||
|
Logger.command(["cd", branch_dir])
|
||||||
|
os.chdir(branch_dir)
|
||||||
|
|
||||||
def sponsor_patch(bug_number, build, builder, edit, keyid, lpinstance, update,
|
def sponsor_patch(bug_number, build, builder, edit, keyid, lpinstance, update,
|
||||||
upload, workdir):
|
upload, workdir):
|
||||||
@ -609,30 +247,12 @@ def sponsor_patch(bug_number, build, builder, edit, keyid, lpinstance, update,
|
|||||||
task = get_open_ubuntu_bug_task(launchpad, bug)
|
task = get_open_ubuntu_bug_task(launchpad, bug)
|
||||||
|
|
||||||
dsc_file = task.download_source()
|
dsc_file = task.download_source()
|
||||||
assert os.path.isfile(dsc_file), "%s does not exist." % (dsc_file)
|
|
||||||
|
_download_and_change_into(task, dsc_file, patch, branch)
|
||||||
|
|
||||||
if patch:
|
if patch:
|
||||||
patch = download_patch(patch)
|
edit |= patch.apply(task)
|
||||||
|
|
||||||
Logger.info("Ubuntu package: %s" % (task.package))
|
|
||||||
if task.is_merge():
|
|
||||||
Logger.info("The task is a merge request.")
|
|
||||||
|
|
||||||
extract_source(dsc_file, Logger.verbose)
|
|
||||||
|
|
||||||
# change directory
|
|
||||||
directory = task.package + '-' + task.get_version().upstream_version
|
|
||||||
Logger.command(["cd", directory])
|
|
||||||
os.chdir(directory)
|
|
||||||
|
|
||||||
edit |= apply_patch(task, patch)
|
|
||||||
elif branch:
|
elif branch:
|
||||||
branch_dir = download_branch(task.get_branch_link())
|
|
||||||
|
|
||||||
# change directory
|
|
||||||
Logger.command(["cd", branch_dir])
|
|
||||||
os.chdir(branch_dir)
|
|
||||||
|
|
||||||
edit |= merge_branch(branch)
|
edit |= merge_branch(branch)
|
||||||
|
|
||||||
source_package = SourcePackage(task.package, builder, workdir, branch)
|
source_package = SourcePackage(task.package, builder, workdir, branch)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user