Merge branch 'megamerge_request' of git+ssh://git.launchpad.net/~ddstreet/ubuntu-dev-tools/+git/ubuntu-dev-tools

MR: https://code.launchpad.net/~ddstreet/ubuntu-dev-tools/+git/ubuntu-dev-tools/+merge/375292
Signed-off-by: Mattia Rizzolo <mattia@debian.org>
This commit is contained in:
Mattia Rizzolo 2019-12-01 19:28:17 +01:00
commit 87f226258a
No known key found for this signature in database
GPG Key ID: 0816B9E18C762BAD
76 changed files with 2675 additions and 1590 deletions

View File

@ -36,11 +36,13 @@ from ubuntutools.builder import get_builder
from ubuntutools.lp.lpapicache import (Launchpad, Distribution,
SeriesNotFoundException,
PackageNotFoundException)
from ubuntutools.logger import Logger
from ubuntutools.misc import (system_distribution, vendor_to_distroinfo,
codename_to_distribution)
from ubuntutools.question import YesNoQuestion
from ubuntutools import getLogger
Logger = getLogger(__name__)
def error(msg):
Logger.error(msg)
@ -48,7 +50,7 @@ def error(msg):
def check_call(cmd, *args, **kwargs):
Logger.command(cmd)
Logger.debug(' '.join(cmd))
ret = subprocess.call(cmd, *args, **kwargs)
if ret != 0:
error('%s returned %d.' % (cmd[0], ret))
@ -302,7 +304,7 @@ def orig_needed(upload, workdir, pkg):
not headers['content-location'].startswith('https://launchpadlibrarian.net')):
return True
except HttpLib2Error as e:
Logger.info(e)
Logger.debug(e)
return True
return False

View File

@ -28,7 +28,9 @@ from launchpadlib.launchpad import Launchpad
from launchpadlib.errors import HTTPError
from ubuntutools.config import UDTConfig
from ubuntutools.logger import Logger
from ubuntutools import getLogger
Logger = getLogger(__name__)
def error_out(msg):

5
debian/changelog vendored
View File

@ -12,6 +12,11 @@ ubuntu-dev-tools (0.175) UNRELEASED; urgency=medium
[ Dan Streetman ]
* tests/pylint.conf: use jobs=0 to speed up tests.
* submittodebian: use a context manager while opening a file.
* d/control: add dependency on python3-lazr.restfulclient.
* Big refactor/rewrite of the whole archive.py module, together with a
restracturing of all the pull-pkg-* commands.
* Unify the logging using the standard python logging module, and remove the
local ubuntutools.logger module.
-- Mattia Rizzolo <mattia@debian.org> Mon, 28 Oct 2019 14:32:20 +0100

9
debian/control vendored
View File

@ -104,7 +104,13 @@ Description: useful tools for Ubuntu developers
a Debian package and its immediate parent to generate a debdiff.
- pull-debian-source - downloads the latest source package available in
Debian of a package.
- pull-lp-source - downloads latest source package from Launchpad.
- pull-lp-source - downloads source package from Launchpad.
- pull-lp-debs - downloads debs package(s) from Launchpad.
- pull-lp-ddebs - downloads dbgsym/ddebs package(s) from Launchpad.
- pull-lp-udebs - downloads udebs package(s) from Launchpad.
- pull-debian-* - same as pull-lp-* but for Debian packages.
- pull-uca-* - same as pull-lp-* but for Ubuntu Cloud Archive packages.
- pull-pkg - common script that provides above pull-* functionality.
- pull-revu-source - downloads the latest source package from REVU
- requestbackport - file a backporting request.
- requestsync - files a sync request with Debian changelog and rationale.
@ -132,6 +138,7 @@ Depends:
python3-distro-info,
python3-httplib2,
python3-launchpadlib,
python3-lazr.restfulclient,
sensible-utils,
${misc:Depends},
${python3:Depends},

1
doc/pull-debian-ddebs.1 Symbolic link
View File

@ -0,0 +1 @@
pull-pkg.1

1
doc/pull-debian-debs.1 Symbolic link
View File

@ -0,0 +1 @@
pull-pkg.1

View File

@ -1,89 +0,0 @@
.\" Copyright (C) 2010-2011, Stefano Rivera <stefanor@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.
.TH PULL\-DEBIAN\-SOURCE "1" "22 January 2011" "ubuntu\-dev\-tools"
.SH NAME
pull\-debian\-source \- download and extract a source package from Debian
.SH SYNOPSIS
.B pull\-debian\-source \fR[\fIoptions\fR] <\fIsource package\fR>
[\fIrelease\fR|\fIversion\fR]
.SH DESCRIPTION
\fBpull\-debian\-source\fR downloads and extracts the specified
\fIversion\fR of \fIsource package\fR, or the latest version in the
specified Debian \fIrelease\fR.
.P
\fBpull\-debian\-source\fR will try the preferred mirror, default
mirror, security mirror, and fall back to \fBLaunchpad\fR or
\fBsnapshot.debian.org\fR, in search of the requested version.
.SH OPTIONS
.TP
.I source package
The source package to download from Debian.
.TP
.I release
The release to download the source package from. Defaults to
\fBunstable\fR.
.TP
.I version
The specific version of the package to download.
.TP
.BR \-d ", " \-\-download\-only
Do not extract the source package.
.TP
.B \-m \fIDEBIAN_MIRROR\fR, \fB\-\-mirror\fR=\fIDEBIAN_MIRROR\fR
Use the specified mirror.
Should be in the form \fBhttp://ftp.debian.org/debian\fR.
If the package isn't found on this mirror, \fBpull\-debian\-source\fR
will fall back to the default mirror.
.TP
.B \-s \fIDEBSEC_MIRROR\fR, \fB\-\-security\-mirror\fR=\fIDEBSEC_MIRROR\fR
Use the specified mirror.
Should be in the form \fBhttp://security.debian.org\fR.
If the package isn't found on this mirror, \fBpull\-debian\-source\fR
will fall back to the default mirror.
.TP
.B \-\-no\-conf
Do not read any configuration files, or configuration from environment
variables.
.TP
.BR \-h ", " \-\-help
Display the usage instructions and exit.
.SH ENVIRONMENT
All of the \fBCONFIGURATION VARIABLES\fR below are also supported as
environment variables.
Variables in the environment take precedence to those in configuration
files.
.SH CONFIGURATION VARIABLES
The following variables can be set in the environment or in
.BR ubuntu\-dev\-tools (5)
configuration files.
In each case, the script\-specific variable takes precedence over the
package\-wide variable.
.TP
.BR PULL_DEBIAN_SOURCE_DEBIAN_MIRROR ", " UBUNTUTOOLS_DEBIAN_MIRROR
The default value for \fB\-\-mirror\fR.
.TP
.BR PULL_DEBIAN_SOURCE_DEBSEC_MIRROR ", " UBUNTUTOOLS_DEBSEC_MIRROR
The default value for \fB\-\-security\-mirror\fR.
.SH SEE ALSO
.BR dget (1),
.BR pull\-debian\-debdiff (1),
.BR pull\-lp\-source (1),
.BR ubuntu\-dev\-tools (5)

1
doc/pull-debian-source.1 Symbolic link
View File

@ -0,0 +1 @@
pull-pkg.1

1
doc/pull-debian-udebs.1 Symbolic link
View File

@ -0,0 +1 @@
pull-pkg.1

1
doc/pull-lp-ddebs.1 Symbolic link
View File

@ -0,0 +1 @@
pull-pkg.1

1
doc/pull-lp-debs.1 Symbolic link
View File

@ -0,0 +1 @@
pull-pkg.1

View File

@ -1,79 +0,0 @@
.TH PULL\-LP\-SOURCE "1" "4 August 2008" "ubuntu-dev-tools"
.SH NAME
pull\-lp\-source \- download a source package from Launchpad
.SH SYNOPSIS
.B pull\-lp\-source \fR[\fIoptions\fR]\fB \fBsource package\fR
[\fIrelease\fR|\fIversion\fR]
.SH DESCRIPTION
\fBpull\-lp\-source\fR downloads and extracts the specified
\fIversion\fR of <\fBsource package\fR> from Launchpad, or the latest
version of the specified \fIrelease\fR.
To request a version from a particular pocket say
\fIrelease\fB\-\fIpocket\fR (with a magic \fB\-release\fR for only the
release pocket).
If no \fIversion\fR or \fIrelease\fR is specified, the latest version in
the development release will be downloaded.
.SH OPTIONS
Listed below are the command line options for pull\-lp\-source:
.TP
.B source package
This is the source package that you would like to be downloaded from Launchpad.
.TP
.B version
This is the version of the source package to be downloaded.
.TP
.B release
This is the release that you would like the source package to be downloaded from.
This value defaults to the current development release.
.TP
.BR \-h ", " \-\-help
Display a help message and exit.
.TP
.BR \-d ", " \-\-download\-only
Do not extract the source package.
.TP
.B \-m \fIUBUNTU_MIRROR\fR, \fB\-\-mirror\fR=\fIUBUNTU_MIRROR\fR
Use the specified Ubuntu mirror.
Should be in the form \fBhttp://archive.ubuntu.com/ubuntu\fR.
If the package isn't found on this mirror, \fBpull\-lp\-source\fR will
fall back to Launchpad, as its name implies.
.TP
.B \-\-no\-conf
Do not read any configuration files, or configuration from environment
variables.
.SH ENVIRONMENT
All of the \fBCONFIGURATION VARIABLES\fR below are also supported as
environment variables.
Variables in the environment take precedence to those in configuration
files.
.TP
.B
DIST
Specifies the default target.
.SH CONFIGURATION VARIABLES
The following variables can be set in the environment or in
.BR ubuntu\-dev\-tools (5)
configuration files.
In each case, the script\-specific variable takes precedence over the
package\-wide variable.
.TP
.BR PULL_LP_SOURCE_UBUNTU_MIRROR ", " UBUNTUTOOLS_UBUNTU_MIRROR
The default value for \fB\-\-mirror\fR.
.SH SEE ALSO
.BR dget (1),
.BR pull\-debian\-source (1),
.BR pull\-debian\-debdiff (1),
.BR ubuntu\-dev\-tools (5)
.SH AUTHOR
.PP
\fBpull\-lp\-source\fR and this manual page were written by Iain Lane
<iain@orangesquash.org.uk>.
Both are released under the GNU General Public License, version 3 or later.

1
doc/pull-lp-source.1 Symbolic link
View File

@ -0,0 +1 @@
pull-pkg.1

1
doc/pull-lp-udebs.1 Symbolic link
View File

@ -0,0 +1 @@
pull-pkg.1

146
doc/pull-pkg.1 Normal file
View File

@ -0,0 +1,146 @@
.TH PULL\-PKG "1" "28 August 2017" "ubuntu-dev-tools"
.SH NAME
pull\-pkg \- download a package for Debian, Ubuntu, UCA, or a PPA
.SH SYNOPSIS
.B pull\-pkg \fR[\fIoptions\fR]\fR <\fIpackage name\fR>
[\fIrelease\fR|\fIversion\fR]
.SH DESCRIPTION
\fBpull\-pkg\fR downloads the specified \fIversion\fR of
<\fIpackage name\fR>, or the latest version from the
specified \fIrelease\fR. To request a version from
a particular pocket say \fIrelease\fB\-\fIpocket\fR (with a magic
\fB\-release\fR for only the release pocket).
If no \fIversion\fR or \fIrelease\fR is specified, the latest version in
the development release will be downloaded.
There are convenience scripts that set pull type and distribution
appropriately: these are
\fBpull\-lp\-source\fR, \fBpull\-lp\-debs\fR, \fBpull\-lp\-ddebs\fR,
and \fBpull\-lp\-udebs\fR, which all pull Ubuntu packages;
\fBpull\-debian\-source\fR, \fBpull\-debian\-debs\fR, \fBpull\-debian\-ddebs\fR,
and \fBpull\-debian\-udebs\fR, which all pull Debian packages;
\fBpull\-uca\-source\fR, \fBpull\-uca\-debs\fR, \fBpull\-uca\-ddebs\fR,
and \fBpull\-uca\-udebs\fR, which all pull Ubuntu Cloud Archive packages;
and \fBpull\-ppa\-source\fR, \fBpull\-ppa\-debs\fR, \fBpull\-ppa\-ddebs\fR,
and \fBpull\-ppa\-udebs\fR, which all pull from a specified Personal Package
Archive on Launchpad. Each script pulls the file type in its name, i.e.
\fIsource\fR, \fIdebs\fR, \fIddebs\fR, or \fIudebs\fR.
.SH OPTIONS
Listed below are the command line options for pull\-pkg:
.TP
.I package name
This is name of the package to downloaded.
You can use either the source package name, or binary package name.
.TP
.I version
This is the version of the package to downloaded.
.TP
.I release
This is the release to downloaded from.
For debian, you can use either the release name like \fBjessie\fR
or \fBsid\fR, or you can use the special release names \fBunstable\fR,
\fBstable\fR, or \fBtesting\fR.
For ubuntu, you can use either the release name like \fBxenial\fR
or the release-pocket like \fBxenial-proposed\fR.
For ubuntu cloud archive (uca) you can use either the uca release
name like \fBmitaka\fR or the ubuntu and uca release names like
\fBtrusty-mitaka\fR. Defaults to the current development release.
.TP
.BR \-h ", " \-\-help
Display a help message and exit.
.TP
.BR \-v ", " \-\-verbose
Be verbose about what is being done.
.TP
.BR \-d ", " \-\-download\-only
Do not extract the source package (applies only to source packages).
.TP
.B \-m \fIMIRROR\fR, \fB\-\-mirror\fR=\fIMIRROR\fR
Use the specified mirror server.
Should be in the form \fBhttp://archive.ubuntu.com/ubuntu\fR or
\fBhttp://deb.debian.org/debian\fR. If not specified or if the
package is not found on the specified mirror, this will fall
back to the default mirror(s) and/or mirror(s) from environment
variables, and then will fall back to Launchpad or Debian Snapshot.
This can be specified multiple times to try multiple mirrors.
.TP
.B \-\-no\-conf
Do not use mirrors from the default configuration, or from
any environment variables.
.TP
.B \-a \fIARCH\fR, \fB\-\-arch\fR=\fIARCH\fR
Get binary packages from the \fIARCH\fR architecture.
Defaults to the local architecture, if it can be deteected.
.TP
.B \-p \fIPULL\fR, \fB\-\-pull\fR=\fIPULL\fR
What to pull: \fBsource\fR, \fBdebs\fR, \fBddebs\fR, \fBudebs\fR,
or \fBlist\fR. The \fBlist\fR action only lists all a package's
source and binary files, but does not actually download any.
Defaults to \fBsource\fR.
.TP
.B \-D \fIDISTRO\fR, \fB\-\-distro\fR=\fIDISTRO\fR
Pull from: \fBdebian\fR, \fBuca\fR, \fBubuntu\fR, or a \fBppa\fR.
\fBlp\fR can be used instead of \fBubuntu\fR.
Any string containing \fBcloud\fR can be used instead of \fBuca\fR.
If pulling from a ppa, you must specify the PPA. Deafults to \fBubuntu\fR.
.TP
.B \-\-ppa\fR=ppa:\fIUSER/NAME\fR
Applies only when \fBdistro\fR is \fIppa\fR. Can be provided either as
a value to the \fB\-\-ppa\fR option parameter, or as a plain option
(like \fIrelease\fR or \fIversion\fR). When specified as a plain option,
the form must be \fBppa:USER/NAME\fR; when specified as a value to the
\fB\-\-ppa\fR option parameter, the leading \fBppa:\fR is optional.
.SH ENVIRONMENT
All of the \fBCONFIGURATION VARIABLES\fR below are also supported as
environment variables.
Variables in the environment take precedence to those in configuration
files.
.SH CONFIGURATION VARIABLES
The following variables can be set in the environment or in
.BR ubuntu\-dev\-tools (5)
configuration files.
In each case, the script\-specific variable takes precedence over the
package\-wide variable.
.TP
.BR UBUNTUTOOLS_UBUNTU_MIRROR
The default mirror.
.TP
.BR PULL_PKG_UBUNTU_MIRROR
The default mirror when using the \fBpull\-pkg\fR script.
.TP
.BR PULL_[LP|DEBIAN|PPA|UCA]_[SOURCE|DEBS|DDEBS|UDEBS]_MIRROR
The default mirror when using the associated script.
.SH SEE ALSO
.BR dget (1),
.BR pull\-lp\-source (1),
.BR pull\-lp\-debs (1),
.BR pull\-lp\-ddebs (1),
.BR pull\-lp\-udebs (1),
.BR pull\-debian\-source (1),
.BR pull\-debian\-debs (1),
.BR pull\-debian\-ddebs (1),
.BR pull\-debian\-udebs (1),
.BR pull\-ppa\-source (1),
.BR pull\-ppa\-debs (1),
.BR pull\-ppa\-ddebs (1),
.BR pull\-ppa\-udebs (1),
.BR pull\-uca\-source (1),
.BR pull\-uca\-debs (1),
.BR pull\-uca\-ddebs (1),
.BR pull\-uca\-udebs (1),
.BR pull\-debian\-debdiff (1),
.BR ubuntu\-dev\-tools (5)
.SH AUTHOR
.PP
\fBpull\-pkg\fR was written by Dan Streetman <ddstreet@canonical.com>,
based on the original \fBpull\-lp\-source\fR; it and this manual page
were written by Iain Lane <iain@orangesquash.org.uk>.
All are released under the GNU General Public License, version 3 or later.

1
doc/pull-ppa-ddebs.1 Symbolic link
View File

@ -0,0 +1 @@
pull-pkg.1

1
doc/pull-ppa-debs.1 Symbolic link
View File

@ -0,0 +1 @@
pull-pkg.1

1
doc/pull-ppa-source.1 Symbolic link
View File

@ -0,0 +1 @@
pull-pkg.1

1
doc/pull-ppa-udebs.1 Symbolic link
View File

@ -0,0 +1 @@
pull-pkg.1

1
doc/pull-uca-ddebs.1 Symbolic link
View File

@ -0,0 +1 @@
pull-pkg.1

1
doc/pull-uca-debs.1 Symbolic link
View File

@ -0,0 +1 @@
pull-pkg.1

1
doc/pull-uca-source.1 Symbolic link
View File

@ -0,0 +1 @@
pull-pkg.1

1
doc/pull-uca-udebs.1 Symbolic link
View File

@ -0,0 +1 @@
pull-pkg.1

View File

@ -27,6 +27,9 @@ from httplib2 import Http, HttpLib2Error
import ubuntutools.misc
from ubuntutools import getLogger
Logger = getLogger(__name__)
def main():
parser = optparse.OptionParser(
@ -52,11 +55,11 @@ def main():
try:
headers, page = Http().request(url)
except HttpLib2Error as e:
print(str(e), file=sys.stderr)
Logger.exception(e)
sys.exit(1)
if headers.status != 200:
print("%s: %s %s" % (url, headers.status, headers.reason),
file=sys.stderr)
Logger.error("%s: %s %s" % (url, headers.status,
headers.reason))
sys.exit(1)
for merge in json.loads(page):
@ -71,7 +74,7 @@ def main():
pretty_uploader = '{} {}'.format(author, uploader)
if (match is None or match in package or match in author
or match in uploader or match in teams):
print('%s\t%s' % (package, pretty_uploader))
Logger.info('%s\t%s' % (package, pretty_uploader))
if __name__ == '__main__':

View File

@ -36,6 +36,9 @@ from launchpadlib.launchpad import Launchpad
from ubuntutools.lp.libsupport import translate_web_api
from ubuntutools import getLogger
Logger = getLogger(__name__)
def check_args():
howmany = -1
@ -57,8 +60,7 @@ def check_args():
# Check that we have an URL.
if not args:
print("An URL pointing to a Launchpad bug list is required.",
file=sys.stderr)
Logger.error("An URL pointing to a Launchpad bug list is required.")
opt_parser.print_help()
sys.exit(1)
else:
@ -87,15 +89,14 @@ def main():
if len(url.split("?", 1)) == 2:
# search options not supported, because there is no mapping web ui
# options <-> API options
print("Options in url are not supported, url: %s" % url,
file=sys.stderr)
Logger.error("Options in url are not supported, url: %s" % url)
sys.exit(1)
launchpad = None
try:
launchpad = Launchpad.login_with("ubuntu-dev-tools", 'production')
except IOError as error:
print(error)
Logger.exception(error)
sys.exit(1)
api_url = translate_web_api(url, launchpad)
@ -104,8 +105,8 @@ def main():
except Exception as error:
response = getattr(error, "response", {})
if response.get("status", None) == "404":
print(("The URL at '%s' does not appear to be a valid url to a "
"product") % url, file=sys.stderr)
Logger.error("The URL at '%s' does not appear to be a "
"valid url to a product" % url)
sys.exit(1)
else:
raise
@ -113,12 +114,12 @@ def main():
bug_list = [b for b in product.searchTasks() if filter_unsolved(b)]
if not bug_list:
print("Bug list of %s is empty." % url)
Logger.info("Bug list of %s is empty." % url)
sys.exit(0)
if howmany == -1:
howmany = len(bug_list)
print("""
Logger.info("""
## ||<rowbgcolor="#CCFFCC"> This task is done || somebody || ||
## ||<rowbgcolor="#FFFFCC"> This task is assigned || somebody || <status> ||
## ||<rowbgcolor="#FFEBBB"> This task isn't || ... || ||
@ -128,13 +129,13 @@ def main():
for i in list(bug_list)[:howmany]:
bug = i.bug
print('||<rowbgcolor="#FFEBBB"> [%s %s] || %s || ||'
% (bug.web_link, bug.id, bug.title))
Logger.info('||<rowbgcolor="#FFEBBB"> [%s %s] || %s || ||' %
(bug.web_link, bug.id, bug.title))
if __name__ == '__main__':
try:
main()
except KeyboardInterrupt:
print("Aborted.", file=sys.stderr)
Logger.error("Aborted.")
sys.exit(1)

View File

@ -30,7 +30,9 @@ import webbrowser
from launchpadlib.launchpad import Launchpad
from ubuntutools.config import UDTConfig
from ubuntutools.logger import Logger
from ubuntutools import getLogger
Logger = getLogger(__name__)
try:
import debianbts
@ -134,7 +136,7 @@ def main():
d_watch = u_bug.addWatch(remote_bug=bug_num, bug_tracker=lp_debbugs)
d_task.bug_watch = d_watch
d_task.lp_save()
Logger.normal("Opened %s", u_bug.web_link)
Logger.info("Opened %s", u_bug.web_link)
if not options.browserless:
webbrowser.open(u_bug.web_link)

View File

@ -22,9 +22,12 @@ import sys
from debian.changelog import Changelog
from ubuntutools import getLogger
Logger = getLogger(__name__)
def usage(exit_code=1):
print('''Usage: merge-changelog <left changelog> <right changelog>
Logger.info('''Usage: merge-changelog <left changelog> <right changelog>
merge-changelog takes two changelogs that once shared a common source,
merges them back together, and prints the merged result to stdout. This
@ -61,7 +64,7 @@ def merge_changelog(left_changelog, right_changelog):
assert block.version == version
print(str(block).strip(), end='\n\n')
Logger.info(str(block).strip() + '\n\n')
def main():

View File

@ -39,9 +39,11 @@ from distro_info import DebianDistroInfo, UbuntuDistroInfo, DistroDataOutdated
import ubuntutools.misc
import ubuntutools.version
from ubuntutools.config import UDTConfig
from ubuntutools.logger import Logger
from ubuntutools.question import YesNoQuestion
from ubuntutools import getLogger
Logger = getLogger(__name__)
class PbuilderDist(object):
def __init__(self, builder):
@ -103,9 +105,10 @@ class PbuilderDist(object):
'~/pbuilder/'))
if 'SUDO_USER' in os.environ:
Logger.warn('Running under sudo. '
Logger.warning('Running under sudo. '
'This is probably not what you want. '
'pbuilder-dist will use sudo itself, when necessary.')
'pbuilder-dist will use sudo itself, '
'when necessary.')
if os.stat(os.environ['HOME']).st_uid != os.getuid():
Logger.error("You don't own $HOME")
sys.exit(1)
@ -280,7 +283,7 @@ class PbuilderDist(object):
codename = debian_info.codename(self.target_distro,
default=self.target_distro)
except DistroDataOutdated as error:
Logger.warn(error)
Logger.warning(error)
if codename in (debian_info.devel(), 'experimental'):
self.enable_security = False
self.enable_updates = False
@ -307,7 +310,7 @@ class PbuilderDist(object):
try:
dev_release = self.target_distro == UbuntuDistroInfo().devel()
except DistroDataOutdated as error:
Logger.warn(error)
Logger.warning(error)
dev_release = True
if dev_release:
@ -396,7 +399,7 @@ def show_help(exit_code=0):
Print a help message for pbuilder-dist, and exit with the given code.
"""
print('See man pbuilder-dist for more information.')
Logger.info('See man pbuilder-dist for more information.')
sys.exit(exit_code)
@ -498,7 +501,7 @@ def main():
if '--debug-echo' not in args:
sys.exit(subprocess.call(app.get_command(args)))
else:
print(app.get_command([arg for arg in args if arg != '--debug-echo']))
Logger.info(app.get_command([arg for arg in args if arg != '--debug-echo']))
if __name__ == '__main__':

11
pull-debian-ddebs Executable file
View File

@ -0,0 +1,11 @@
#!/usr/bin/python3
#
# pull-debian-ddebs -- pull ddeb package files for debian
# Basic usage: pull-debian-ddebs <package name> [version|release]
#
# See pull-pkg
from ubuntutools.pullpkg import PullPkg
if __name__ == '__main__':
PullPkg.main(distro='debian', pull='ddebs')

View File

@ -24,9 +24,11 @@ import debian.changelog
from ubuntutools.archive import DebianSourcePackage, DownloadError
from ubuntutools.config import UDTConfig
from ubuntutools.logger import Logger
from ubuntutools.version import Version
from ubuntutools import getLogger
Logger = getLogger(__name__)
def previous_version(package, version, distance):
"Given an (extracted) package, determine the version distance versions ago"
@ -79,7 +81,7 @@ def main():
opts.debsec_mirror = config.get_value('DEBSEC_MIRROR')
mirrors = [opts.debsec_mirror, opts.debian_mirror]
Logger.normal('Downloading %s %s', package, version)
Logger.info('Downloading %s %s', package, version)
newpkg = DebianSourcePackage(package, version, mirrors=mirrors)
try:
@ -96,7 +98,7 @@ def main():
if not oldversion:
Logger.error('No previous version could be found')
sys.exit(1)
Logger.normal('Downloading %s %s', package, oldversion)
Logger.info('Downloading %s %s', package, oldversion)
oldpkg = DebianSourcePackage(package, oldversion, mirrors=mirrors)
try:
@ -104,11 +106,11 @@ def main():
except DownloadError as e:
Logger.error('Failed to download: %s', str(e))
sys.exit(1)
print('file://' + oldpkg.debdiff(newpkg, diffstat=True))
Logger.info('file://' + oldpkg.debdiff(newpkg, diffstat=True))
if __name__ == '__main__':
try:
main()
except KeyboardInterrupt:
Logger.normal('User abort.')
Logger.info('User abort.')

11
pull-debian-debs Executable file
View File

@ -0,0 +1,11 @@
#!/usr/bin/python3
#
# pull-debian-debs -- pull deb package files for debian
# Basic usage: pull-debian-debs <package name> [version|release]
#
# See pull-pkg
from ubuntutools.pullpkg import PullPkg
if __name__ == '__main__':
PullPkg.main(distro='debian', pull='debs')

View File

@ -1,148 +1,11 @@
#!/usr/bin/python3
#
# pull-debian-source -- pull a source package from Launchpad
# Copyright (C) 2011, Stefano Rivera <stefanor@ubuntu.com>
# Inspired by a tool of the same name by Nathan Handler.
# pull-debian-source -- pull source package files for debian
# Basic usage: pull-debian-source <package name> [version|release]
#
# 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 json
import optparse
import sys
import urllib.request
import urllib.error
from distro_info import DebianDistroInfo, DistroDataOutdated
from ubuntutools.archive import DebianSourcePackage, DownloadError, rmadison
from ubuntutools.config import UDTConfig
from ubuntutools.logger import Logger
def is_suite(version):
"""If version could be considered to be a Debian suite, return the
canonical suite name. Otherwise None
"""
debian_info = DebianDistroInfo()
debian_releases = debian_info.all + ['experimental']
if '-' in version:
release, pocket = version.split('-', 1)
release = debian_info.codename(release, default=release)
if release in debian_releases:
if pocket in ('proposed-updates', 'p-u'):
return (release + '-proposed-updates')
elif pocket == 'security':
return (release + '-security')
else:
release = debian_info.codename(version, default=version)
if release in debian_releases:
return release
return None
def source_package_for(binary, release):
"""Query DDE to find the source package for a particular binary"""
try:
release = DebianDistroInfo().codename(release, default=release)
except DistroDataOutdated as e:
Logger.warn(e)
url = ('http://dde.debian.net/dde/q/udd/dist/d:debian/r:%s/p:%s/?t=json'
% (release, binary))
data = None
try:
data = json.load(urllib.request.urlopen(url))['r']
except urllib.error.URLError as e:
Logger.error('Unable to retrieve package information from DDE: '
'%s (%s)', url, str(e))
except ValueError as e:
Logger.error('Unable to parse JSON response from DDE: '
'%s (%s)', url, str(e))
if not data:
return None
return data[0]['source']
def main():
usage = 'Usage: %prog <package> [release|version]'
parser = optparse.OptionParser(usage)
parser.add_option('-d', '--download-only',
dest='download_only', default=False, action='store_true',
help='Do not extract the source package')
parser.add_option('-m', '--mirror', metavar='DEBIAN_MIRROR',
dest='debian_mirror',
help='Preferred Debian mirror (default: %s)'
% UDTConfig.defaults['DEBIAN_MIRROR'])
parser.add_option('-s', '--security-mirror', metavar='DEBSEC_MIRROR',
dest='debsec_mirror',
help='Preferred Debian Security mirror (default: %s)'
% UDTConfig.defaults['DEBSEC_MIRROR'])
parser.add_option('--no-conf',
dest='no_conf', default=False, action='store_true',
help="Don't read config files or environment variables")
parser.add_option('--no-verify-signature',
dest='verify_signature', default=True,
action='store_false',
help="Allow signature verification failure")
(options, args) = parser.parse_args()
if not args:
parser.error('Must specify package name')
elif len(args) > 2:
parser.error('Too many arguments. '
'Must only specify package and (optionally) release.')
config = UDTConfig(options.no_conf)
if options.debian_mirror is None:
options.debian_mirror = config.get_value('DEBIAN_MIRROR')
if options.debsec_mirror is None:
options.debsec_mirror = config.get_value('DEBSEC_MIRROR')
package = args[0].lower()
version = args[1] if len(args) > 1 else 'unstable'
component = None
suite = is_suite(version)
if suite is not None:
line = list(rmadison('debian', package, suite, 'source'))
if not line:
source_package = source_package_for(package, suite)
if source_package is not None and package != source_package:
package = source_package
line = list(rmadison('debian', package, suite, 'source'))
if not line:
Logger.error('Unable to find %s in Debian suite "%s".', package,
suite)
sys.exit(1)
line = line[-1]
version = line['version']
component = line['component']
Logger.normal('Downloading %s version %s', package, version)
srcpkg = DebianSourcePackage(package, version, component=component,
mirrors=[options.debian_mirror,
options.debsec_mirror])
try:
srcpkg.pull(verify_signature=options.verify_signature)
except DownloadError as e:
Logger.error('Failed to download: %s', str(e))
sys.exit(1)
if not options.download_only:
srcpkg.unpack()
# See pull-pkg
from ubuntutools.pullpkg import PullPkg
if __name__ == '__main__':
try:
main()
except KeyboardInterrupt:
Logger.normal('User abort.')
PullPkg.main(distro='debian', pull='source')

11
pull-debian-udebs Executable file
View File

@ -0,0 +1,11 @@
#!/usr/bin/python3
#
# pull-debian-udebs -- pull udeb package files for debian
# Basic usage: pull-debian-udebs <package name> [version|release]
#
# See pull-pkg
from ubuntutools.pullpkg import PullPkg
if __name__ == '__main__':
PullPkg.main(distro='debian', pull='udebs')

11
pull-lp-ddebs Executable file
View File

@ -0,0 +1,11 @@
#!/usr/bin/python3
#
# pull-lp-ddebs -- pull ddeb package files for ubuntu
# Basic usage: pull-lp-ddebs <package name> [version|release]
#
# See pull-pkg
from ubuntutools.pullpkg import PullPkg
if __name__ == '__main__':
PullPkg.main(distro='ubuntu', pull='ddebs')

11
pull-lp-debs Executable file
View File

@ -0,0 +1,11 @@
#!/usr/bin/python3
#
# pull-lp-debs -- pull deb package files for ubuntu
# Basic usage: pull-lp-debs <package name> [version|release]
#
# See pull-pkg
from ubuntutools.pullpkg import PullPkg
if __name__ == '__main__':
PullPkg.main(distro='ubuntu', pull='debs')

View File

@ -1,150 +1,11 @@
#!/usr/bin/python3
#
# pull-lp-source -- pull a source package from Launchpad
# Basic usage: pull-lp-source <source package> [<release>]
# pull-lp-source -- pull source package files for ubuntu
# Basic usage: pull-lp-source <package name> [version|release]
#
# Copyright (C) 2008, Iain Lane <iain@orangesquash.org.uk>,
# 2010-2011, Stefano Rivera <stefanor@ubuntu.com>
#
# ##################################################################
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 3
# 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 General Public License for more details.
#
# See file /usr/share/common-licenses/GPL for more details.
#
# ##################################################################
import json
import os
import sys
import urllib.error
import urllib.request
from optparse import OptionParser
from distro_info import UbuntuDistroInfo, DistroDataOutdated
from ubuntutools.archive import UbuntuSourcePackage, DownloadError
from ubuntutools.config import UDTConfig
from ubuntutools.lp.lpapicache import Distribution, Launchpad
from ubuntutools.lp.udtexceptions import (SeriesNotFoundException,
PackageNotFoundException,
PocketDoesNotExistError)
from ubuntutools.logger import Logger
from ubuntutools.misc import split_release_pocket
def source_package_for(binary, release):
"""Query DDE to find the source package for a particular binary
Should really do this with LP, but it's not possible LP: #597041
"""
url = ('http://dde.debian.net/dde/q/udd/dist/d:ubuntu/r:%s/p:%s/?t=json'
% (release, binary))
data = None
try:
data = json.load(urllib.request.urlopen(url))['r']
except urllib.error.URLError as e:
Logger.error('Unable to retrieve package information from DDE: '
'%s (%s)', url, str(e))
except ValueError as e:
Logger.error('Unable to parse JSON response from DDE: '
'%s (%s)', url, str(e))
if not data:
return None
return data[0]['source']
def main():
usage = "Usage: %prog <package> [release|version]"
opt_parser = OptionParser(usage)
opt_parser.add_option('-d', '--download-only',
dest='download_only', default=False,
action='store_true',
help="Do not extract the source package")
opt_parser.add_option('-m', '--mirror', metavar='UBUNTU_MIRROR',
dest='ubuntu_mirror',
help='Preferred Ubuntu mirror (default: Launchpad)')
opt_parser.add_option('--no-conf',
dest='no_conf', default=False, action='store_true',
help="Don't read config files or environment "
"variables")
(options, args) = opt_parser.parse_args()
if not args:
opt_parser.error("Must specify package name")
config = UDTConfig(options.no_conf)
if options.ubuntu_mirror is None:
options.ubuntu_mirror = config.get_value('UBUNTU_MIRROR')
# Login anonymously to LP
Launchpad.login_anonymously()
package = str(args[0]).lower()
ubuntu_info = UbuntuDistroInfo()
if len(args) > 1: # Custom distribution specified.
version = str(args[1])
else:
try:
version = os.getenv('DIST') or ubuntu_info.devel()
except DistroDataOutdated as e:
Logger.warn("%s\nOr specify a distribution.", e)
sys.exit(1)
component = None
# Release, not package version number:
release = None
pocket = None
try:
(release, pocket) = split_release_pocket(version, default=None)
except PocketDoesNotExistError:
pass
if release in ubuntu_info.all:
archive = Distribution('ubuntu').getArchive()
try:
spph = archive.getSourcePackage(package, release, pocket)
except SeriesNotFoundException as e:
Logger.error(str(e))
sys.exit(1)
except PackageNotFoundException as e:
source_package = source_package_for(package, release)
if source_package is not None and source_package != package:
try:
spph = archive.getSourcePackage(source_package, release,
pocket)
package = source_package
except PackageNotFoundException:
Logger.error(str(e))
sys.exit(1)
else:
Logger.error(str(e))
sys.exit(1)
version = spph.getVersion()
component = spph.getComponent()
Logger.normal('Downloading %s version %s', package, version)
srcpkg = UbuntuSourcePackage(package, version, component=component,
mirrors=[options.ubuntu_mirror])
try:
srcpkg.pull()
except DownloadError as e:
Logger.error('Failed to download: %s', str(e))
sys.exit(1)
if not options.download_only:
srcpkg.unpack()
# See pull-pkg
from ubuntutools.pullpkg import PullPkg
if __name__ == '__main__':
try:
main()
except KeyboardInterrupt:
Logger.normal('User abort.')
PullPkg.main(distro='ubuntu', pull='source')

11
pull-lp-udebs Executable file
View File

@ -0,0 +1,11 @@
#!/usr/bin/python3
#
# pull-lp-udebs -- pull udeb package files for ubuntu
# Basic usage: pull-lp-udebs <package name> [version|release]
#
# See pull-pkg
from ubuntutools.pullpkg import PullPkg
if __name__ == '__main__':
PullPkg.main(distro='ubuntu', pull='udebs')

29
pull-pkg Executable file
View File

@ -0,0 +1,29 @@
#!/usr/bin/python3
#
# pull-pkg -- pull package files for debian/ubuntu/uca/ppa
# Basic usage: pull-pkg -D distro -p type <package name> [version|release]
#
# Copyright (C) 2008, Iain Lane <iain@orangesquash.org.uk>,
# 2010-2011, Stefano Rivera <stefanor@ubuntu.com>
# 2017-2018, Dan Streetman <ddstreet@canonical.com>
#
# ##################################################################
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 3
# 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 General Public License for more details.
#
# See file /usr/share/common-licenses/GPL for more details.
#
# ##################################################################
from ubuntutools.pullpkg import PullPkg
if __name__ == '__main__':
PullPkg.main()

12
pull-ppa-ddebs Executable file
View File

@ -0,0 +1,12 @@
#!/usr/bin/python3
#
# pull-ppa-ddebs -- pull ddeb package files for a Launchpad Personal Package Archive
# Basic usage: pull-ppa-ddebs <package name> <ppa:USER/NAME> [version|release]
# pull-ppa-ddebs --ppa USER/NAME <package name> [version|release]
#
# See pull-pkg
from ubuntutools.pullpkg import PullPkg
if __name__ == '__main__':
PullPkg.main(distro='ppa', pull='ddebs')

12
pull-ppa-debs Executable file
View File

@ -0,0 +1,12 @@
#!/usr/bin/python3
#
# pull-ppa-debs -- pull deb package files for a Launchpad Personal Package Archive
# Basic usage: pull-ppa-debs <package name> <ppa:USER/NAME> [version|release]
# pull-ppa-debs --ppa USER/NAME <package name> [version|release]
#
# See pull-pkg
from ubuntutools.pullpkg import PullPkg
if __name__ == '__main__':
PullPkg.main(distro='ppa', pull='debs')

12
pull-ppa-source Executable file
View File

@ -0,0 +1,12 @@
#!/usr/bin/python3
#
# pull-ppa-source -- pull source package files for a Launchpad Personal Package Archive
# Basic usage: pull-ppa-source <package name> <ppa:USER/NAME> [version|release]
# pull-ppa-source --ppa USER/NAME <package name> [version|release]
#
# See pull-pkg
from ubuntutools.pullpkg import PullPkg
if __name__ == '__main__':
PullPkg.main(distro='ppa', pull='source')

12
pull-ppa-udebs Executable file
View File

@ -0,0 +1,12 @@
#!/usr/bin/python3
#
# pull-ppa-udebs -- pull udeb package files for a Launchpad Personal Package Archive
# Basic usage: pull-ppa-udebs <package name> <ppa:USER/NAME> [version|release]
# pull-ppa-udebs --ppa USER/NAME <package name> [version|release]
#
# See pull-pkg
from ubuntutools.pullpkg import PullPkg
if __name__ == '__main__':
PullPkg.main(distro='ppa', pull='udebs')

11
pull-uca-ddebs Executable file
View File

@ -0,0 +1,11 @@
#!/usr/bin/python3
#
# pull-uca-ddebs -- pull ddeb package files for ubuntu cloud archive
# Basic usage: pull-uca-ddebs <package name> [version|release]
#
# See pull-pkg
from ubuntutools.pullpkg import PullPkg
if __name__ == '__main__':
PullPkg.main(distro='uca', pull='ddebs')

11
pull-uca-debs Executable file
View File

@ -0,0 +1,11 @@
#!/usr/bin/python3
#
# pull-uca-debs -- pull deb package files for ubuntu cloud archive
# Basic usage: pull-uca-debs <package name> [version|release]
#
# See pull-pkg
from ubuntutools.pullpkg import PullPkg
if __name__ == '__main__':
PullPkg.main(distro='uca', pull='debs')

View File

@ -1,157 +1,11 @@
#!/usr/bin/python3
#
# pull-uca-source -- pull a source package from Ubuntu Cloud Archive
# Basic usage: pull-uca-source <source package> <openstack release> [version]
# pull-uca-source -- pull source package files for ubuntu cloud archive
# Basic usage: pull-uca-source <package name> [version|release]
#
# Copyright (C) 2008, Iain Lane <iain@orangesquash.org.uk>,
# 2010-2011, Stefano Rivera <stefanor@ubuntu.com>
# 2016, Corey Bryant <corey.bryant@ubuntu.com>
# 2016, Dan Streetman <dan.streetman@canonical.com>
#
# ##################################################################
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 3
# 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 General Public License for more details.
#
# See file /usr/share/common-licenses/GPL for more details.
#
# ##################################################################
import re
import sys
from optparse import OptionParser
from ubuntutools.archive import UbuntuCloudArchiveSourcePackage, DownloadError
from ubuntutools.config import UDTConfig
from ubuntutools.lp.lpapicache import Launchpad
from ubuntutools.lp.udtexceptions import PocketDoesNotExistError
from ubuntutools.logger import Logger
from ubuntutools.misc import split_release_pocket
from lazr.restfulclient.errors import NotFound
from launchpadlib.launchpad import Launchpad as LP
def showOpenstackReleases(uca):
releases = []
for p in uca.ppas:
if re.match(r"\w*-staging", p.name):
releases.append(re.sub("-staging", "", p.name))
Logger.error("Openstack releases are:\n\t%s", ", ".join(releases))
def getSPPH(lp, archive, package, version=None, series=None, pocket=None, try_binary=True):
params = {'exact_match': True, 'order_by_date': True}
if pocket:
params['pocket'] = pocket
if series:
params['distro_series'] = series()
elif version:
params['version'] = version
Logger.normal("checking %s version %s pocket %s", package, version, pocket)
spphs = archive.getPublishedSources(source_name=package, **params)
if spphs:
return spphs[0]
if not try_binary:
return None
# Didn't find any, maybe the package is a binary package name
if series:
del params['distro_series']
archs = lp.load(series().architectures_collection_link).entries
params['distro_arch_series'] = archs[0]['self_link']
bpphs = archive.getPublishedBinaries(binary_name=package, **params)
if bpphs:
bpph_build = lp.load(bpphs[0].build_link)
source_package = bpph_build.source_package_name
return getSPPH(lp, archive, source_package, version, series, pocket,
try_binary=False)
return None
def main():
usage = "Usage: %prog <package> <openstack release> [version]"
opt_parser = OptionParser(usage)
opt_parser.add_option('-d', '--download-only',
dest='download_only', default=False,
action='store_true',
help="Do not extract the source package")
opt_parser.add_option('-m', '--mirror', metavar='OPENSTACK_MIRROR',
dest='openstack_mirror',
help='Preferred Openstack mirror (default: Launchpad)')
opt_parser.add_option('--no-conf',
dest='no_conf', default=False, action='store_true',
help="Don't read config files or environment "
"variables")
(options, args) = opt_parser.parse_args()
if len(args) < 2:
opt_parser.error("Must specify package name and openstack release")
config = UDTConfig(options.no_conf)
if options.openstack_mirror is None:
options.openstack_mirror = config.get_value('OPENSTACK_MIRROR')
mirrors = []
if options.openstack_mirror:
mirrors.append(options.openstack_mirror)
# Login anonymously to LP
Launchpad.login_anonymously()
lp = LP.login_anonymously("pull-uca-source", "production")
uca = lp.people("ubuntu-cloud-archive")
package = str(args[0]).lower()
release = str(args[1]).lower()
version = None
if len(args) > 2:
version = str(args[2])
pocket = None
try:
(release, pocket) = split_release_pocket(release, default=None)
except PocketDoesNotExistError:
pass
try:
archive = uca.getPPAByName(name="%s-staging" % release)
except NotFound:
Logger.error('Archive does not exist for Openstack release: %s',
release)
showOpenstackReleases(uca)
sys.exit(1)
spph = getSPPH(lp, archive, package, version, pocket=pocket)
if not spph:
Logger.error("Package %s in %s not found.", package, release)
sys.exit(1)
package = spph.source_package_name
version = spph.source_package_version
component = spph.component_name
Logger.normal('Downloading %s version %s component %s', package, version, component)
srcpkg = UbuntuCloudArchiveSourcePackage(release, package, version, component=component,
mirrors=mirrors)
try:
srcpkg.pull()
except DownloadError as e:
Logger.error('Failed to download: %s', str(e))
sys.exit(1)
if not options.download_only:
srcpkg.unpack()
# See pull-pkg
from ubuntutools.pullpkg import PullPkg
if __name__ == '__main__':
try:
main()
except KeyboardInterrupt:
Logger.normal('User abort.')
PullPkg.main(distro='uca', pull='source')

11
pull-uca-udebs Executable file
View File

@ -0,0 +1,11 @@
#!/usr/bin/python3
#
# pull-uca-udebs -- pull udeb package files for ubuntu cloud archive
# Basic usage: pull-uca-udebs <package name> [version|release]
#
# See pull-pkg
from ubuntutools.pullpkg import PullPkg
if __name__ == '__main__':
PullPkg.main(distro='uca', pull='udebs')

View File

@ -25,11 +25,13 @@ from distro_info import UbuntuDistroInfo
from ubuntutools.config import UDTConfig
from ubuntutools.lp.lpapicache import Launchpad, Distribution
from ubuntutools.lp.udtexceptions import PackageNotFoundException
from ubuntutools.logger import Logger
from ubuntutools.question import (YesNoQuestion, EditBugReport,
confirmation_prompt)
from ubuntutools.rdepends import query_rdepends, RDependsException
from ubuntutools import getLogger
Logger = getLogger(__name__)
class DestinationException(Exception):
pass
@ -106,16 +108,11 @@ def check_existing(package, destinations):
if not bugs:
return
Logger.normal("There are existing bug reports that look similar to your "
Logger.info("There are existing bug reports that look similar to your "
"request. Please check before continuing:")
by_id = {}
for bug_task in bugs:
bug = bug_task.bug
by_id[bug.id] = bug
for id_, bug in sorted(by_id.items()):
Logger.normal(" * LP: #%-7i: %s %s", bug.id, bug.title, bug.web_link)
for bug in sorted(set(bug_task.bug for bug_task in bugs)):
Logger.info(" * LP: #%-7i: %s %s", bug.id, bug.title, bug.web_link)
confirmation_prompt()
@ -190,7 +187,7 @@ def locate_package(package, distribution):
except KeyError:
continue
package = apt_pkg.candidate.source_name
Logger.normal("Binary package specified, considering its source "
Logger.info("Binary package specified, considering its source "
"package instead: %s", package)
@ -204,7 +201,7 @@ def request_backport(package_spph, source, destinations):
Logger.error("%s (%s) has no published binaries in %s. ",
package_spph.getPackageName(), package_spph.getVersion(),
source)
Logger.normal("Is it stuck in bin-NEW? It can't be backported until "
Logger.info("Is it stuck in bin-NEW? It can't be backported until "
"the binaries have been accepted.")
sys.exit(1)
@ -256,7 +253,7 @@ def request_backport(package_spph, source, destinations):
editor.edit()
subject, body = editor.get_report()
Logger.normal('The final report is:\nSummary: %s\nDescription:\n%s\n',
Logger.info('The final report is:\nSummary: %s\nDescription:\n%s\n',
subject, body)
if YesNoQuestion().ask("Request this backport", "yes") == "no":
sys.exit(1)
@ -268,7 +265,7 @@ def request_backport(package_spph, source, destinations):
for target in targets[1:]:
bug.addTask(target=target)
Logger.normal("Backport request filed as %s", bug.web_link)
Logger.info("Backport request filed as %s", bug.web_link)
def main():

View File

@ -38,6 +38,9 @@ from ubuntutools.misc import require_utf8
from ubuntutools.question import confirmation_prompt, EditBugReport
from ubuntutools.version import Version
from ubuntutools import getLogger
Logger = getLogger(__name__)
#
# entry point
#
@ -97,7 +100,7 @@ def main():
config = UDTConfig(options.no_conf)
if options.deprecated_lp_flag:
print("The --lp flag is now default, ignored.")
Logger.info("The --lp flag is now default, ignored.")
if options.email:
options.lpapi = False
else:
@ -115,8 +118,8 @@ def main():
elif options.lpinstance == 'staging':
bug_mail_domain = 'bugs.staging.launchpad.net'
else:
print('Error: Unknown launchpad instance: %s' % options.lpinstance,
file=sys.stderr)
Logger.error('Error: Unknown launchpad instance: %s'
% options.lpinstance)
sys.exit(1)
mailserver_host = config.get_value('SMTP_SERVER',
@ -130,8 +133,8 @@ def main():
firstmx = mxlist[0]
mailserver_host = firstmx[1]
except ImportError:
print('Please install python3-dns to support Launchpad mail '
'server lookup.', file=sys.stderr)
Logger.error('Please install python-dns to support '
'Launchpad mail server lookup.')
sys.exit(1)
mailserver_port = config.get_value('SMTP_PORT', default=25,
@ -167,9 +170,8 @@ def main():
get_ubuntu_delta_changelog,
mail_bug, need_sponsorship)
if not any(x in os.environ for x in ('UBUMAIL', 'DEBEMAIL', 'EMAIL')):
print('E: The environment variable UBUMAIL, DEBEMAIL or EMAIL '
'needs to be set to let this script mail the sync request.',
file=sys.stderr)
Logger.error('The environment variable UBUMAIL, DEBEMAIL or EMAIL needs '
'to be set to let this script mail the sync request.')
sys.exit(1)
newsource = options.newpkg
@ -187,15 +189,14 @@ def main():
else:
ubu_info = UbuntuDistroInfo()
release = ubu_info.devel()
print('W: Target release missing - assuming %s' % release,
file=sys.stderr)
Logger.warning('Target release missing - assuming %s' % release)
elif len(args) == 2:
release = args[1]
elif len(args) == 3:
release = args[1]
force_base_version = Version(args[2])
else:
print('E: Too many arguments.', file=sys.stderr)
Logger.error('Too many arguments.')
parser.print_help()
sys.exit(1)
@ -210,13 +211,12 @@ def main():
ubuntu_version = Version('~')
ubuntu_component = None # Set after getting the Debian info
if not newsource:
print(("'%s' doesn't exist in 'Ubuntu %s'.\n"
"Do you want to sync a new package?")
% (srcpkg, release))
Logger.info("'%s' doesn't exist in 'Ubuntu %s'." % (srcpkg, release))
Logger.info("Do you want to sync a new package?")
confirmation_prompt()
newsource = True
except udtexceptions.SeriesNotFoundException as error:
print("E: %s" % error, file=sys.stderr)
Logger.error(error)
sys.exit(1)
# Get the requested Debian source package
@ -225,10 +225,10 @@ def main():
debian_version = Version(debian_srcpkg.getVersion())
debian_component = debian_srcpkg.getComponent()
except udtexceptions.PackageNotFoundException as error:
print("E: %s" % error, file=sys.stderr)
Logger.error(error)
sys.exit(1)
except udtexceptions.SeriesNotFoundException as error:
print("E: %s" % error, file=sys.stderr)
Logger.error(error)
sys.exit(1)
if ubuntu_component is None:
@ -246,17 +246,17 @@ def main():
debian_version = Version(debian_srcpkg.getVersion())
debian_component = debian_srcpkg.getComponent()
except udtexceptions.PackageNotFoundException as error:
print("E: %s" % error, file=sys.stderr)
Logger.error(error)
sys.exit(1)
if ubuntu_version == debian_version:
print('E: The versions in Debian and Ubuntu are the same already '
'(%s). Aborting.' % ubuntu_version, file=sys.stderr)
Logger.error('The versions in Debian and Ubuntu are the '
'same already (%s). Aborting.' % ubuntu_version)
sys.exit(1)
if ubuntu_version > debian_version:
print(('E: The version in Ubuntu (%s) is newer than the version in '
'Debian (%s). Aborting.')
% (ubuntu_version, debian_version), file=sys.stderr)
Logger.error('The version in Ubuntu (%s) is newer than '
'the version in Debian (%s). Aborting.'
% (ubuntu_version, debian_version))
sys.exit(1)
# -s flag not specified - check if we do need sponsorship
@ -264,8 +264,8 @@ def main():
sponsorship = need_sponsorship(srcpkg, ubuntu_component, release)
if not sponsorship and not ffe:
print('Consider using syncpackage(1) for syncs that do not require '
'feature freeze exceptions.', file=sys.stderr)
Logger.error('Consider using syncpackage(1) for syncs that '
'do not require feature freeze exceptions.')
# Check for existing package reports
if not newsource:
@ -283,9 +283,9 @@ def main():
if 'ubuntu' in str(ubuntu_version):
need_interaction = True
print('Changes have been made to the package in Ubuntu.\n'
'Please edit the report and give an explanation.\n'
'Not saving the report file will abort the request.')
Logger.info('Changes have been made to the package in Ubuntu.')
Logger.info('Please edit the report and give an explanation.')
Logger.info('Not saving the report file will abort the request.')
report += ('Explanation of the Ubuntu delta and why it can be '
'dropped:\n%s\n>>> ENTER_EXPLANATION_HERE <<<\n\n'
% get_ubuntu_delta_changelog(ubuntu_srcpkg))
@ -293,9 +293,9 @@ def main():
if ffe:
need_interaction = True
print('To approve FeatureFreeze exception, you need to state\n'
'the reason why you feel it is necessary.\n'
'Not saving the report file will abort the request.')
Logger.info('To approve FeatureFreeze exception, you need to state')
Logger.info('the reason why you feel it is necessary.')
Logger.info('Not saving the report file will abort the request.')
report += ('Explanation of FeatureFreeze exception:\n'
'>>> ENTER_EXPLANATION_HERE <<<\n\n')
@ -312,10 +312,10 @@ def main():
changelog = debian_srcpkg.getChangelog(since_version=base_version)
if not changelog:
if not options.missing_changelog_ok:
print("E: Did not retrieve any changelog entries. "
Logger.error("Did not retrieve any changelog entries. "
"Do you need to specify '-C'? "
"Was the package recently uploaded? (check "
"http://packages.debian.org/changelogs/)", file=sys.stderr)
"http://packages.debian.org/changelogs/)")
sys.exit(1)
else:
need_interaction = True
@ -327,8 +327,8 @@ def main():
title, report = editor.get_report()
if 'XXX FIXME' in report:
print("E: changelog boilerplate found in report, please manually add "
"changelog when using '-C'", file=sys.stderr)
Logger.error("changelog boilerplate found in report, "
"please manually add changelog when using '-C'")
sys.exit(1)
# bug status and bug subscriber
@ -359,5 +359,5 @@ if __name__ == '__main__':
try:
main()
except KeyboardInterrupt:
print("\nUser abort.")
Logger.error("User abort.")
sys.exit(2)

View File

@ -19,11 +19,13 @@ import sys
from distro_info import DistroDataOutdated
from ubuntutools.logger import Logger
from ubuntutools.misc import (system_distribution, vendor_to_distroinfo,
codename_to_distribution)
from ubuntutools.rdepends import query_rdepends, RDependsException
from ubuntutools import getLogger
Logger = getLogger(__name__)
DEFAULT_MAX_DEPTH = 10 # We want avoid any infinite loop...
@ -32,7 +34,7 @@ def main():
try:
default_release = system_distro_info.devel()
except DistroDataOutdated as e:
Logger.warn(e)
Logger.warning(e)
default_release = 'unstable'
description = ("List reverse-dependencies of package. "
@ -85,7 +87,7 @@ def main():
options.release = distro_info.codename(options.release,
default=options.release)
except DistroDataOutdated:
# We already printed a warning
# We already logged a warning
pass
if options.build_depends:
@ -143,14 +145,14 @@ def main():
def display_verbose(package, values):
if not values:
print("No reverse dependencies found")
Logger.info("No reverse dependencies found")
return
def print_field(field):
print(field)
print('=' * len(field))
def log_field(field):
Logger.info(field)
Logger.info('=' * len(field))
def print_package(values, package, arch, dependency, offset=0):
def log_package(values, package, arch, dependency, offset=0):
line = ' ' * offset + '* %s' % package
if all_archs and set(arch) != all_archs:
line += ' [%s]' % ' '.join(sorted(arch))
@ -158,13 +160,13 @@ def display_verbose(package, values):
if len(line) < 30:
line += ' ' * (30 - len(line))
line += ' (for %s)' % dependency
print(line)
Logger.info(line)
data = values.get(package)
if data:
offset = offset + 1
for rdeps in data.values():
for rdep in rdeps:
print_package(values,
log_package(values,
rdep['Package'],
rdep.get('Architectures', all_archs),
rdep.get('Dependency'),
@ -179,17 +181,17 @@ def display_verbose(package, values):
all_archs.update(rdep['Architectures'])
for field, rdeps in values[package].items():
print_field(field)
Logger.info(field)
rdeps.sort(key=lambda x: x['Package'])
for rdep in rdeps:
print_package(values,
log_package(values,
rdep['Package'],
rdep.get('Architectures', all_archs),
rdep.get('Dependency'))
print()
Logger.info("")
if all_archs:
print("Packages without architectures listed are "
Logger.info("Packages without architectures listed are "
"reverse-dependencies in: %s"
% ', '.join(sorted(list(all_archs))))
@ -201,7 +203,7 @@ def display_consise(values):
for rdep in rdeps:
result.add(rdep['Package'])
print('\n'.join(sorted(list(result))))
Logger.info('\n'.join(sorted(list(result))))
if __name__ == '__main__':

View File

@ -24,7 +24,9 @@ import urllib.request
from ubuntutools.lp.lpapicache import (Distribution, Launchpad,
PackageNotFoundException)
from ubuntutools.logger import Logger
from ubuntutools import getLogger
Logger = getLogger(__name__)
DATA_URL = 'http://qa.ubuntuwire.org/ubuntu-seeded-packages/seeded.json.gz'
@ -88,28 +90,28 @@ def output_binaries(index, binaries):
'''Print binaries found in index'''
for binary in binaries:
if binary in index:
print("%s is seeded in:" % binary)
print(present_on(index[binary]))
Logger.info("%s is seeded in:" % binary)
Logger.info(present_on(index[binary]))
else:
print("%s is not seeded (and may not exist)." % binary)
Logger.info("%s is not seeded (and may not exist)." % binary)
def output_by_source(index, by_source):
'''Print binaries found in index. Grouped by source'''
'''Logger.Info(binaries found in index. Grouped by source'''
for source, binaries in by_source.items():
seen = False
if not binaries:
print("Status unknown: No binary packages built by the latest "
Logger.info("Status unknown: No binary packages built by the latest "
"%s.\nTry again using -b and the expected binary packages."
% source)
continue
for binary in binaries:
if binary in index:
seen = True
print("%s (from %s) is seeded in:" % (binary, source))
print(present_on(index[binary]))
Logger.info("%s (from %s) is seeded in:" % (binary, source))
Logger.info(present_on(index[binary]))
if not seen:
print("%s's binaries are not seeded." % source)
Logger.info("%s's binaries are not seeded." % source)
def main():

View File

@ -27,11 +27,25 @@ scripts = [
'mk-sbuild',
'pbuilder-dist',
'pbuilder-dist-simple',
'pull-pkg',
'pull-debian-debdiff',
'pull-debian-source',
'pull-debian-debs',
'pull-debian-ddebs',
'pull-debian-udebs',
'pull-lp-source',
'pull-lp-debs',
'pull-lp-ddebs',
'pull-lp-udebs',
'pull-ppa-source',
'pull-ppa-debs',
'pull-ppa-ddebs',
'pull-ppa-udebs',
'pull-revu-source',
'pull-uca-source',
'pull-uca-debs',
'pull-uca-ddebs',
'pull-uca-udebs',
'requestbackport',
'requestsync',
'reverse-build-depends',

View File

@ -19,12 +19,15 @@ import os
import shutil
import sys
import tempfile
import logging
from ubuntutools.builder import get_builder
from ubuntutools.config import UDTConfig
from ubuntutools.logger import Logger
from ubuntutools.sponsor_patch.sponsor_patch import sponsor_patch, check_dependencies
from ubuntutools import getLogger
Logger = getLogger(__name__)
def parse(script_name):
"""Parse the command line parameters."""
@ -64,7 +67,8 @@ def parse(script_name):
"temporary directory, deleted afterwards).")
(options, args) = parser.parse_args()
Logger.set_verbosity(options.verbose)
if options.verbose:
Logger.setLevel(logging.DEBUG)
check_dependencies()
if len(args) == 0:
@ -123,7 +127,7 @@ def main():
options.keyid, options.lpinstance, options.update,
options.upload, workdir)
except KeyboardInterrupt:
print("\nUser abort.")
Logger.error("User abort.")
sys.exit(2)
finally:
if options.workdir is None:

View File

@ -27,7 +27,9 @@ import os
import re
import shutil
import sys
from subprocess import call, check_call, Popen, PIPE
from subprocess import call, check_call, run, Popen, PIPE, DEVNULL
from tempfile import mkdtemp
from debian.changelog import Changelog
@ -37,6 +39,9 @@ from ubuntutools.config import ubu_email
from ubuntutools.question import YesNoQuestion, EditFile
from ubuntutools.update_maintainer import update_maintainer, restore_maintainer
from ubuntutools import getLogger
Logger = getLogger(__name__)
def get_most_recent_debian_version(changelog):
for block in changelog:
@ -85,10 +90,9 @@ def gen_debdiff(tmpdir, changelog):
debdiff = os.path.join(tmpdir, '%s_%s.debdiff' % (pkg, newver))
devnull = open('/dev/null', 'w')
diff_cmd = ['bzr', 'diff', '-r', 'tag:' + str(oldver)]
if call(diff_cmd, stdout=devnull, stderr=devnull) == 1:
print("Extracting bzr diff between %s and %s" % (oldver, newver))
if call(diff_cmd, stdout=DEVNULL, stderr=DEVNULL) == 1:
Logger.info("Extracting bzr diff between %s and %s" % (oldver, newver))
else:
if oldver.epoch is not None:
oldver = str(oldver)[str(oldver).index(":") + 1:]
@ -101,17 +105,13 @@ def gen_debdiff(tmpdir, changelog):
check_file(olddsc)
check_file(newdsc)
print("Generating debdiff between %s and %s" % (oldver, newver))
Logger.info("Generating debdiff between %s and %s" % (oldver, newver))
diff_cmd = ['debdiff', olddsc, newdsc]
diff = Popen(diff_cmd, stdout=PIPE)
debdiff_f = open(debdiff, 'w')
filterdiff = Popen(['filterdiff', '-x', '*changelog*'],
stdin=diff.stdout, stdout=debdiff_f)
diff.stdout.close()
filterdiff.wait()
debdiff_f.close()
devnull.close()
with Popen(diff_cmd, stdout=PIPE, encoding='utf-8') as diff:
with open(debdiff, 'w', encoding='utf-8') as debdiff_f:
run(['filterdiff', '-x', '*changelog*'],
stdin=diff.stdout, stdout=debdiff_f, encoding='utf-8')
return debdiff
@ -122,7 +122,7 @@ def check_file(fname, critical=True):
else:
if not critical:
return False
print("Couldn't find «%s».\n" % fname)
Logger.info("Couldn't find «%s».\n" % fname)
sys.exit(1)
@ -130,7 +130,7 @@ def submit_bugreport(body, debdiff, deb_version, changelog):
try:
devel = UbuntuDistroInfo().devel()
except DistroDataOutdated as e:
print(str(e))
Logger.info(str(e))
devel = ''
if os.path.dirname(sys.argv[0]).startswith('/usr/bin'):
@ -200,7 +200,7 @@ no-cc
with open(fn, 'w') as f:
f.write(reportbugrc)
print("""\
Logger.info("""\
You have not configured reportbug. Assuming this is the first time you have
used it. Writing a ~/.reportbugrc that will use Debian's mail server, and CC
the bug to you at <%s>
@ -224,7 +224,7 @@ def main():
parser.parse_args()
if not os.path.exists('/usr/bin/reportbug'):
print("This utility requires the «reportbug» package, which isn't "
Logger.error("This utility requires the «reportbug» package, which isn't "
"currently installed.")
sys.exit(1)

View File

@ -21,6 +21,7 @@
# ##################################################################
import fnmatch
import logging
import optparse
import os
import shutil
@ -37,7 +38,6 @@ from ubuntutools.config import UDTConfig, ubu_email
from ubuntutools.lp import udtexceptions
from ubuntutools.lp.lpapicache import (Distribution, Launchpad, PersonTeam,
SourcePackagePublishingHistory)
from ubuntutools.logger import Logger
from ubuntutools.misc import split_release_pocket
from ubuntutools.question import YesNoQuestion
from ubuntutools.requestsync.mail import (
@ -45,6 +45,9 @@ from ubuntutools.requestsync.mail import (
from ubuntutools.requestsync.lp import get_debian_srcpkg, get_ubuntu_srcpkg
from ubuntutools.version import Version
from ubuntutools import getLogger
Logger = getLogger(__name__)
def remove_signature(dscname):
'''Removes the signature from a .dsc file if the .dsc file is signed.'''
@ -116,7 +119,7 @@ def sync_dsc(src_pkg, debian_dist, release, name, email, bugs, ubuntu_mirror,
ubuntu_ver = Version('~')
ubu_pkg = None
need_orig = True
Logger.normal('%s does not exist in Ubuntu.', name)
Logger.info('%s does not exist in Ubuntu.', name)
Logger.debug('Source %s: current version %s, new version %s',
src_pkg.source, ubuntu_ver, new_ver)
@ -128,7 +131,7 @@ def sync_dsc(src_pkg, debian_dist, release, name, email, bugs, ubuntu_mirror,
Logger.error('--force is required to discard Ubuntu changes.')
sys.exit(1)
Logger.warn('Overwriting modified Ubuntu version %s, '
Logger.warning('Overwriting modified Ubuntu version %s, '
'setting current version to %s',
ubuntu_ver.full_version, cur_ver.full_version)
if simulate:
@ -144,7 +147,7 @@ def sync_dsc(src_pkg, debian_dist, release, name, email, bugs, ubuntu_mirror,
needs_fakesync = not (need_orig or ubu_pkg.verify_orig())
if needs_fakesync and fakesync:
Logger.warn('Performing a fakesync')
Logger.warning('Performing a fakesync')
elif not needs_fakesync and fakesync:
Logger.error('Fakesync not required, aborting.')
sys.exit(1)
@ -163,7 +166,7 @@ def sync_dsc(src_pkg, debian_dist, release, name, email, bugs, ubuntu_mirror,
# change into package directory
directory = src_pkg.source + '-' + new_ver.upstream_version
Logger.command(('cd', directory))
Logger.debug('cd' + directory)
os.chdir(directory)
# read Debian distribution from debian/changelog if not specified
@ -183,9 +186,9 @@ def sync_dsc(src_pkg, debian_dist, release, name, email, bugs, ubuntu_mirror,
cmd.append("-sa")
else:
cmd.append("-sd")
if not Logger.verbose:
if not Logger.isEnabledFor(logging.DEBUG):
cmd += ["-q"]
Logger.command(cmd + ['>', '../' + changes_filename])
Logger.debug(' '.join(cmd) + '> ../' + changes_filename)
changes = subprocess.check_output(cmd, encoding='utf-8')
# Add additional bug numbers
@ -193,7 +196,7 @@ def sync_dsc(src_pkg, debian_dist, release, name, email, bugs, ubuntu_mirror,
changes = add_fixed_bugs(changes, bugs)
# remove extracted (temporary) files
Logger.command(('cd', '..'))
Logger.debug('cd ..')
os.chdir('..')
shutil.rmtree(directory, True)
@ -208,7 +211,7 @@ def sync_dsc(src_pkg, debian_dist, release, name, email, bugs, ubuntu_mirror,
cmd = ["debsign", changes_filename]
if keyid is not None:
cmd.insert(1, "-k" + keyid)
Logger.command(cmd)
Logger.debug(' '.join(cmd))
subprocess.check_call(cmd)
else:
# Create fakesync changelog entry
@ -223,14 +226,14 @@ def sync_dsc(src_pkg, debian_dist, release, name, email, bugs, ubuntu_mirror,
cmd = ['dch', '-v', new_ver.full_version, '--force-distribution',
'-D', release, message]
env = {'DEBFULLNAME': name, 'DEBEMAIL': email}
Logger.command(cmd)
Logger.debug(' '.join(cmd))
subprocess.check_call(cmd, env=env)
# update the Maintainer field
cmd = ["update-maintainer"]
if not Logger.verbose:
if not Logger.isEnabledFor(logging.DEBUG):
cmd.append("-q")
Logger.command(cmd)
Logger.debug(' '.join(cmd))
subprocess.check_call(cmd)
# Build source package
@ -240,7 +243,7 @@ def sync_dsc(src_pkg, debian_dist, release, name, email, bugs, ubuntu_mirror,
cmd += ['-sa']
if keyid:
cmd += ["-k" + keyid]
Logger.command(cmd)
Logger.debug(' '.join(cmd))
returncode = subprocess.call(cmd)
if returncode != 0:
Logger.error('Source-only build with debuild failed. '
@ -339,7 +342,7 @@ def copy(src_pkg, release, bugs, sponsoree=None, simulate=False, force=False):
ubuntu_spph.getComponent(),
mirrors=[])
Logger.normal('Source %s -> %s/%s: current version %s, new version %s',
Logger.info('Source %s -> %s/%s: current version %s, new version %s',
src_pkg.source, ubuntu_series, ubuntu_pocket,
ubuntu_pkg.version, src_pkg.version)
@ -358,20 +361,20 @@ def copy(src_pkg, release, bugs, sponsoree=None, simulate=False, force=False):
sys.exit(1)
except udtexceptions.PackageNotFoundException:
base_version = Version('~')
Logger.normal('Source %s -> %s/%s: not in Ubuntu, new version %s',
Logger.info('Source %s -> %s/%s: not in Ubuntu, new version %s',
src_pkg.source, ubuntu_series, ubuntu_pocket,
src_pkg.version)
changes = debian_spph.getChangelog(since_version=base_version)
if changes:
changes = changes.strip()
Logger.normal("New changes:\n%s", changes)
Logger.info("New changes:\n%s", changes)
if simulate:
return
if sponsoree:
Logger.normal("Sponsoring this sync for %s (%s)",
Logger.info("Sponsoring this sync for %s (%s)",
sponsoree.display_name, sponsoree.name)
answer = YesNoQuestion().ask("Sync this package", "no")
if answer != "yes":
@ -392,13 +395,13 @@ def copy(src_pkg, release, bugs, sponsoree=None, simulate=False, force=False):
Logger.error(error.content)
sys.exit(1)
Logger.normal('Request succeeded; you should get an e-mail once it is '
Logger.info('Request succeeded; you should get an e-mail once it is '
'processed.')
bugs = sorted(set(bugs))
if bugs:
Logger.normal("Launchpad bugs to be closed: %s",
Logger.info("Launchpad bugs to be closed: %s",
', '.join(str(bug) for bug in bugs))
Logger.normal('Please wait for the sync to be successful before '
Logger.info('Please wait for the sync to be successful before '
'closing bugs.')
answer = YesNoQuestion().ask("Close bugs", "yes")
if answer == "yes":
@ -468,7 +471,7 @@ def close_bugs(bugs, package, version, changes, sponsoree):
if target == ubuntu or (target.name == package and
getattr(target, 'distribution', None) == ubuntu):
if task.status != 'Fix Released':
Logger.normal("Closed bug %s", task.web_link)
Logger.info("Closed bug %s", task.web_link)
task.status = 'Fix Released'
task.lp_save()
bug.newMessage(content=message)
@ -597,7 +600,8 @@ def main():
'''Handle parameters and get the ball rolling'''
(options, package) = parse()
Logger.verbose = options.verbose
if options.verbose:
Logger.setLevel('DEBUG')
config = UDTConfig(options.no_conf)
if options.debian_mirror is None:
options.debian_mirror = config.get_value('DEBIAN_MIRROR')
@ -626,7 +630,7 @@ def main():
options.release = "%s-proposed" % ubuntu.current_series.name
if not options.fakesync and not options.lp:
Logger.warn("The use of --no-lp is not recommended for uploads "
Logger.warning("The use of --no-lp is not recommended for uploads "
"targeted at Ubuntu. "
"The archive-admins discourage its use, except for "
"fakesyncs.")
@ -687,17 +691,17 @@ def main():
if blacklist_fail:
Logger.error("Source package %s is blacklisted.", src_pkg.source)
elif blacklisted == 'ALWAYS':
Logger.normal("Source package %s is blacklisted.", src_pkg.source)
Logger.info(u"Source package %s is blacklisted.", src_pkg.source)
if messages:
for message in messages:
for line in textwrap.wrap(message):
Logger.normal(line)
Logger.info(line)
if comments:
Logger.normal("Blacklist Comments:")
Logger.info("Blacklist Comments:")
for comment in comments:
for line in textwrap.wrap(comment):
Logger.normal(" " + line)
Logger.info(" " + line)
if blacklist_fail:
sys.exit(1)
@ -717,4 +721,4 @@ if __name__ == "__main__":
try:
main()
except KeyboardInterrupt:
Logger.normal('User abort.')
Logger.info('User abort.')

View File

@ -32,6 +32,9 @@ from ubuntutools.lp.udtexceptions import (SeriesNotFoundException,
from ubuntutools.lp.lpapicache import Distribution, PersonTeam
from ubuntutools.misc import split_release_pocket
from ubuntutools import getLogger
Logger = getLogger(__name__)
def main():
# Usage.
@ -108,15 +111,15 @@ def main():
# Check our operation.
if op not in ("rescore", "retry", "status"):
print("Invalid operation: %s." % op, file=sys.stderr)
Logger.error("Invalid operation: %s." % op)
sys.exit(1)
# If the user has specified an architecture to build, we only wish to
# rebuild it and nothing else.
if options.architecture:
if options.architecture[0] not in valid_archs:
print("Invalid architecture specified: %s."
% options.architecture[0], file=sys.stderr)
Logger.error("Invalid architecture specified: %s."
% options.architecture[0])
sys.exit(1)
else:
one_arch = True
@ -127,7 +130,7 @@ def main():
try:
(release, pocket) = split_release_pocket(release)
except PocketDoesNotExistError as error:
print('E: %s' % error)
Logger.error(error)
sys.exit(1)
# Get the ubuntu archive
@ -141,7 +144,7 @@ def main():
sources = ubuntu_archive.getSourcePackage(package, release, pocket)
distroseries = Distribution('ubuntu').getSeries(release)
except (SeriesNotFoundException, PackageNotFoundException) as error:
print(error)
Logger.error(error)
sys.exit(1)
# Get list of builds for that package.
builds = sources.getBuilds()
@ -163,16 +166,16 @@ def main():
pocket=pocket)
if op in ('rescore', 'retry') and not necessary_privs:
print(("You cannot perform the %s operation on a %s package as "
"you do not have the permissions to do this action.")
% (op, component), file=sys.stderr)
Logger.error("You cannot perform the %s operation on a %s "
"package as you do not have the permissions "
"to do this action." % (op, component))
sys.exit(1)
# Output details.
print("The source version for '%s' in %s (%s) is at %s."
% (package, release.capitalize(), component, version))
Logger.info("The source version for '%s' in %s (%s) is at %s." %
(package, release.capitalize(), component, version))
print("Current build status for this package:")
Logger.info("Current build status for this package:")
# Output list of arches for package and their status.
done = False
@ -182,29 +185,28 @@ def main():
continue
done = True
print("%s: %s." % (build.arch_tag, build.buildstate))
Logger.info("%s: %s." % (build.arch_tag, build.buildstate))
if op == 'rescore':
if build.can_be_rescored:
# FIXME: make priority an option
priority = 5000
print('Rescoring build %s to %d...'
% (build.arch_tag, priority))
Logger.info('Rescoring build %s to %d...' % (build.arch_tag, priority))
build.rescore(score=priority)
else:
print('Cannot rescore build on %s.' % build.arch_tag)
Logger.info('Cannot rescore build on %s.' % build.arch_tag)
if op == 'retry':
if build.can_be_retried:
print('Retrying build on %s...' % build.arch_tag)
Logger.info('Retrying build on %s...' % build.arch_tag)
build.retry()
else:
print('Cannot retry build on %s.' % build.arch_tag)
Logger.info('Cannot retry build on %s.' % build.arch_tag)
# We are done
if done:
sys.exit(0)
print(("No builds for '%s' found in the %s release - it may have been "
"built in a former release.") % (package, release.capitalize()))
Logger.info("No builds for '%s' found in the %s release" % (package, release.capitalize()))
Logger.info("It may have been built in a former release.")
sys.exit(0)
# Batch mode
@ -225,14 +227,14 @@ def main():
try:
(release, pocket) = split_release_pocket(release)
except PocketDoesNotExistError as error:
print('E: %s' % error)
Logger.error(error)
sys.exit(1)
ubuntu_archive = Distribution('ubuntu').getArchive()
try:
distroseries = Distribution('ubuntu').getSeries(release)
except SeriesNotFoundException as error:
print(error)
Logger.error(error)
sys.exit(1)
me = PersonTeam.me
@ -241,14 +243,14 @@ def main():
and me.isLpTeamMember('launchpad-buildd-admins'))
or False)
if options.priority and not can_rescore:
print("You don't have the permissions to rescore builds. "
"Ignoring your rescore request.", file=sys.stderr)
Logger.error("You don't have the permissions to rescore "
"builds. Ignoring your rescore request.")
for pkg in args:
try:
pkg = ubuntu_archive.getSourcePackage(pkg, release, pocket)
except PackageNotFoundException as error:
print(error)
Logger.error(error)
continue
# Check permissions (part 2): check upload permissions for the source
@ -258,20 +260,20 @@ def main():
pkg.getPackageName(),
pkg.getComponent())
if options.retry and not can_retry:
print(("You don't have the permissions to retry the build of "
"'%s'. Ignoring your request.")
% pkg.getPackageName(), file=sys.stderr)
Logger.error("You don't have the permissions to retry the "
"build of '%s'. Ignoring your request."
% pkg.getPackageName())
print("The source version for '%s' in '%s' (%s) is: %s"
% (pkg.getPackageName(), release, pocket, pkg.getVersion()))
Logger.info("The source version for '%s' in '%s' (%s) is: %s" %
(pkg.getPackageName(), release, pocket, pkg.getVersion()))
print(pkg.getBuildStates(archs))
Logger.info(pkg.getBuildStates(archs))
if can_retry:
print(pkg.retryBuilds(archs))
Logger.info(pkg.retryBuilds(archs))
if options.priority and can_rescore:
print(pkg.rescoreBuilds(archs, options.priority))
Logger.info(pkg.rescoreBuilds(archs, options.priority))
print()
Logger.info('')
if __name__ == '__main__':

View File

@ -24,18 +24,21 @@ import optparse
import subprocess
import sys
from ubuntutools import getLogger
Logger = getLogger(__name__)
def extract(iso, path):
command = ['isoinfo', '-R', '-i', iso, '-x', path]
pipe = subprocess.Popen(command, stdout=subprocess.PIPE,
stderr=subprocess.PIPE, encoding='utf-8')
stdout, stderr = pipe.communicate()
pipe = subprocess.run(command, encoding='utf-8',
stdout=subprocess.PIPE,
stderr=subprocess.PIPE)
if pipe.returncode != 0:
sys.stderr.write(stderr)
sys.stderr.write(pipe.stderr)
sys.exit(pipe.returncode)
return stdout
return pipe.stdout
def main():
@ -54,12 +57,11 @@ def main():
version = extract(iso, '/.disk/info')
if len(version) == 0:
print('%s does not appear to be an Ubuntu ISO' % iso,
file=sys.stderr)
Logger.error('%s does not appear to be an Ubuntu ISO' % iso)
err = True
continue
print(prefix + version)
Logger.info(prefix + version)
if err:
sys.exit(1)

View File

@ -20,9 +20,11 @@ import sys
from ubuntutools.lp.lpapicache import (Launchpad, Distribution, PersonTeam,
Packageset, PackageNotFoundException,
SeriesNotFoundException)
from ubuntutools.logger import Logger
from ubuntutools.misc import split_release_pocket
from ubuntutools import getLogger
Logger = getLogger(__name__)
def parse_arguments():
'''Parse arguments and return (options, package)'''
@ -77,51 +79,49 @@ def main():
component_uploader = archive.getUploadersForComponent(
component_name=component)[0]
print("All upload permissions for %s:" % package)
print()
print("Component (%s)" % component)
print("============" + ("=" * len(component)))
Logger.info("All upload permissions for %s:" % package)
Logger.info("")
Logger.info("Component (%s)" % component)
Logger.info("============" + ("=" * len(component)))
print_uploaders([component_uploader], options.list_team_members)
packagesets = sorted(Packageset.setsIncludingSource(
distroseries=series,
sourcepackagename=package))
if packagesets:
print()
print("Packagesets")
print("===========")
Logger.info("")
Logger.info("Packagesets")
Logger.info("===========")
for packageset in packagesets:
print()
print("%s:" % packageset.name)
Logger.info("")
Logger.info("%s:" % packageset.name)
print_uploaders(archive.getUploadersForPackageset(
packageset=packageset), options.list_team_members)
ppu_uploaders = archive.getUploadersForPackage(
source_package_name=package)
if ppu_uploaders:
print()
print("Per-Package-Uploaders")
print("=====================")
print()
Logger.info("")
Logger.info("Per-Package-Uploaders")
Logger.info("=====================")
Logger.info("")
print_uploaders(ppu_uploaders, options.list_team_members)
print()
Logger.info("")
if PersonTeam.me.canUploadPackage(archive, series, package, component,
pocket):
print("You can upload %s to %s." % (package, options.release))
Logger.info("You can upload %s to %s." % (package, options.release))
else:
print("You can not upload %s to %s, yourself."
% (package, options.release))
Logger.info("You can not upload %s to %s, yourself." % (package, options.release))
if (series.status in ('Current Stable Release', 'Supported', 'Obsolete')
and pocket == 'Release'):
print(("%s is in the '%s' state. You may want to query the "
"%s-proposed pocket.")
% (release, series.status, release))
Logger.info("%s is in the '%s' state. You may want to query the %s-proposed pocket." %
(release, series.status, release))
else:
print("But you can still contribute to it via the sponsorship "
Logger.info("But you can still contribute to it via the sponsorship "
"process: https://wiki.ubuntu.com/SponsorshipProcess")
if not options.list_uploaders:
print("To see who has the necessary upload rights, "
Logger.info("To see who has the necessary upload rights, "
"use the --list-uploaders option.")
sys.exit(1)
@ -133,9 +133,9 @@ def print_uploaders(uploaders, expand_teams=False, prefix=''):
recursion.
"""
for uploader in sorted(uploaders, key=lambda p: p.display_name):
print(("%s* %s (%s)%s" %
Logger.info("%s* %s (%s)%s" %
(prefix, uploader.display_name, uploader.name,
' [team]' if uploader.is_team else '')))
' [team]' if uploader.is_team else ''))
if expand_teams and uploader.is_team:
print_uploaders(uploader.participants, True, prefix=prefix + ' ')

View File

@ -2,3 +2,20 @@
#
# Ubuntu Development Tools
# https://launchpad.net/ubuntu-dev-tools
import logging
def _loggingBasicConfig(**kwargs):
'''Set log level to INFO and define log format to use.'''
if 'level' not in kwargs:
kwargs['level'] = logging.INFO
if 'format' not in kwargs:
kwargs['format'] = '%(message)s'
logging.basicConfig(**kwargs)
def getLogger(name=None):
'''Get standard Python logging.Logger with some ubuntutools defaults.'''
_loggingBasicConfig()
return logging.getLogger(name)

File diff suppressed because it is too large Load Diff

View File

@ -21,7 +21,8 @@
import os
import subprocess
from ubuntutools.logger import Logger
import logging
Logger = logging.getLogger(__name__)
def _build_preparation(result_directory):
@ -34,8 +35,7 @@ class Builder(object):
def __init__(self, name):
self.name = name
cmd = ["dpkg-architecture", "-qDEB_BUILD_ARCH_CPU"]
self.architecture = subprocess.check_output(
cmd, encoding='utf-8').strip()
self.architecture = subprocess.check_output(cmd, encoding='utf-8').strip()
def _build_failure(self, returncode, dsc_file):
if returncode != 0:
@ -72,7 +72,7 @@ class Pbuilder(Builder):
self.name, "--build",
"--architecture", self.architecture, "--distribution", dist,
"--buildresult", result_directory, dsc_file]
Logger.command(cmd)
Logger.debug(' '.join(cmd))
returncode = subprocess.call(cmd)
return self._build_failure(returncode, dsc_file)
@ -80,7 +80,7 @@ class Pbuilder(Builder):
cmd = ["sudo", "-E", "ARCH=" + self.architecture, "DIST=" + dist,
self.name, "--update",
"--architecture", self.architecture, "--distribution", dist]
Logger.command(cmd)
Logger.debug(' '.join(cmd))
returncode = subprocess.call(cmd)
return self._update_failure(returncode, dist)
@ -93,13 +93,13 @@ class Pbuilderdist(Builder):
_build_preparation(result_directory)
cmd = [self.name, dist, self.architecture,
"build", dsc_file, "--buildresult", result_directory]
Logger.command(cmd)
Logger.debug(' '.join(cmd))
returncode = subprocess.call(cmd)
return self._build_failure(returncode, dsc_file)
def update(self, dist):
cmd = [self.name, dist, self.architecture, "update"]
Logger.command(cmd)
Logger.debug(' '.join(cmd))
returncode = subprocess.call(cmd)
return self._update_failure(returncode, dist)
@ -111,22 +111,21 @@ class Sbuild(Builder):
def build(self, dsc_file, dist, result_directory):
_build_preparation(result_directory)
workdir = os.getcwd()
Logger.command(["cd", result_directory])
Logger.debug("cd " + result_directory)
os.chdir(result_directory)
cmd = ["sbuild", "--arch-all", "--dist=" + dist,
"--arch=" + self.architecture, dsc_file]
Logger.command(cmd)
Logger.debug(' '.join(cmd))
returncode = subprocess.call(cmd)
Logger.command(["cd", workdir])
Logger.debug("cd " + workdir)
os.chdir(workdir)
return self._build_failure(returncode, dsc_file)
def update(self, dist):
cmd = ["schroot", "--list"]
Logger.command(cmd)
process = subprocess.Popen(
cmd, stdout=subprocess.PIPE, encoding='utf-8')
chroots, _ = process.communicate()[0].strip().split()
Logger.debug(' '.join(cmd))
process = subprocess.run(cmd, stdout=subprocess.PIPE, encoding='utf-8')
chroots, _ = process.stdout.strip().split()
if process.returncode != 0:
return process.returncode
@ -146,7 +145,7 @@ class Sbuild(Builder):
["sbuild-clean", "-a", "-c"]]
for cmd in commands:
# pylint: disable=W0631
Logger.command(cmd + [chroot])
Logger.debug(' '.join(cmd) + " " + chroot)
ret = subprocess.call(cmd + [chroot])
# pylint: enable=W0631
if ret != 0:

View File

@ -23,7 +23,8 @@ import socket
import sys
import locale
from ubuntutools.logger import Logger
import logging
Logger = logging.getLogger(__name__)
class UDTConfig(object):
@ -37,10 +38,12 @@ class UDTConfig(object):
'BUILDER': 'pbuilder',
'DEBIAN_MIRROR': 'http://deb.debian.org/debian',
'DEBSEC_MIRROR': 'http://security.debian.org',
'DEBIAN_DDEBS_MIRROR': 'http://debug.mirrors.debian.org/debian-debug',
'LPINSTANCE': 'production',
'MIRROR_FALLBACK': True,
'UBUNTU_MIRROR': 'http://archive.ubuntu.com/ubuntu',
'UBUNTU_PORTS_MIRROR': 'http://ports.ubuntu.com',
'UBUNTU_DDEBS_MIRROR': 'http://ddebs.ubuntu.com',
'UPDATE_BUILDER': False,
'WORKDIR': None,
'KEYID': None,
@ -69,7 +72,7 @@ class UDTConfig(object):
for line in f:
parsed = shlex.split(line, comments=True)
if len(parsed) > 1:
Logger.warn('Cannot parse variable assignment in %s: %s',
Logger.warning('Cannot parse variable assignment in %s: %s',
getattr(f, 'name', '<config>'), line)
if len(parsed) >= 1 and '=' in parsed[0]:
key, value = parsed[0].split('=', 1)
@ -109,10 +112,8 @@ class UDTConfig(object):
replacements = self.prefix + '_' + key
if key in self.defaults:
replacements += 'or UBUNTUTOOLS_' + key
Logger.warn(
'Using deprecated configuration variable %s. '
'You should use %s.',
k, replacements)
Logger.warning('Using deprecated configuration variable %s. '
'You should use %s.', k, replacements)
return value
return default

View File

@ -1,76 +0,0 @@
#
# logger.py - A simple logging helper class
#
# Copyright (C) 2010, Benjamin Drung <bdrung@debian.org>
#
# 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
def escape_arg(arg):
"""Shell-escpae arg, if necessary.
Fairly simplistic, doesn't escape anything except whitespace.
"""
if ' ' not in arg:
return arg
return '"%s"' % arg.replace('\\', r'\\').replace('"', r'\"')
class Logger(object):
script_name = os.path.basename(sys.argv[0])
verbose = False
stdout = sys.stdout
stderr = sys.stderr
@classmethod
def _print(cls, format_, message, args=None, stderr=False):
if args:
message = message % args
stream = cls.stderr if stderr else cls.stdout
stream.write((format_ + "\n") % (cls.script_name, message))
@classmethod
def command(cls, cmd):
if cls.verbose:
cls._print("%s: I: %s", " ".join(escape_arg(arg) for arg in cmd))
@classmethod
def debug(cls, message, *args):
if cls.verbose:
cls._print("%s: D: %s", message, args, stderr=True)
@classmethod
def error(cls, message, *args):
cls._print("%s: Error: %s", message, args, stderr=True)
@classmethod
def warn(cls, message, *args):
cls._print("%s: Warning: %s", message, args, stderr=True)
@classmethod
def info(cls, message, *args):
if cls.verbose:
cls._print("%s: I: %s", message, args)
@classmethod
def normal(cls, message, *args):
cls._print("%s: %s", message, args)
@classmethod
def set_verbosity(cls, verbose):
cls.verbose = verbose

View File

@ -3,4 +3,4 @@
#
service = 'production'
api_version = '1.0'
api_version = 'devel'

View File

@ -26,7 +26,7 @@
# httplib2.debuglevel = 1
import collections
import sys
import re
from debian.changelog import Changelog
from httplib2 import Http, HttpLib2Error
@ -36,6 +36,9 @@ from lazr.restfulclient.resource import Entry
from ubuntutools.version import Version
from ubuntutools.lp import (service, api_version)
from ubuntutools.misc import (host_architecture,
DEFAULT_POCKETS, POCKETS,
DEFAULT_STATUSES, STATUSES)
from ubuntutools.lp.udtexceptions import (AlreadyLoggedInError,
ArchiveNotFoundException,
ArchSeriesNotFoundException,
@ -43,6 +46,9 @@ from ubuntutools.lp.udtexceptions import (AlreadyLoggedInError,
PocketDoesNotExistError,
SeriesNotFoundException)
import logging
Logger = logging.getLogger(__name__)
__all__ = [
'Archive',
@ -51,13 +57,12 @@ __all__ = [
'Distribution',
'DistributionSourcePackage',
'DistroSeries',
'DistroArchSeries',
'Launchpad',
'PersonTeam',
'SourcePackagePublishingHistory',
]
_POCKETS = ('Release', 'Security', 'Updates', 'Proposed', 'Backports')
class _Launchpad(object):
'''Singleton for LP API access.'''
@ -69,7 +74,7 @@ class _Launchpad(object):
self.__lp = LP.login_with('ubuntu-dev-tools', service,
version=api_version)
except IOError as error:
print('E: %s' % error, file=sys.stderr)
Logger.error(str(error))
raise
else:
raise AlreadyLoggedInError('Already logged in to Launchpad.')
@ -150,6 +155,7 @@ class BaseWrapper(object, metaclass=MetaWrapper):
cached._lpobject = data
# and add it to our cache
cls._cache[data.self_link] = cached
Logger.debug("%s: %s" % (cls.__name__, data.self_link))
# add additional class specific caching (if available)
cache = getattr(cls, 'cache', None)
if isinstance(cache, collections.Callable):
@ -188,15 +194,23 @@ class Distribution(BaseWrapper):
resource_type = 'distribution'
def __init__(self, *args):
# Don't share _series and _archives between different Distributions
if '_series' not in self.__dict__:
self._series = dict()
if '_archives' not in self.__dict__:
self._archives = dict()
self._series_by_name = dict()
self._series = dict()
self._dev_series = None
self._have_all_series = False
def cache(self):
self._cache[self.name] = self
def _cache_series(self, series):
'''
Add the DistroSeries to the cache if needed.
'''
if series.version not in self._series:
self._series_by_name[series.name] = series
self._series[series.version] = series
@classmethod
def fetch(cls, dist):
'''
@ -243,28 +257,49 @@ class Distribution(BaseWrapper):
(e.g. 'karmic') or version (e.g. '9.10').
If the series is not found: raise SeriesNotFoundException
'''
if name_or_version not in self._series:
if name_or_version in self._series:
return self._series[name_or_version]
if name_or_version in self._series_by_name:
return self._series_by_name[name_or_version]
try:
series = DistroSeries(self().getSeries(name_or_version=name_or_version))
# Cache with name and version
self._series[series.name] = series
self._series[series.version] = series
except HTTPError:
message = "Release '%s' is unknown in '%s'." % \
(name_or_version, self.display_name)
raise SeriesNotFoundException(message)
return self._series[name_or_version]
self._cache_series(series)
return series
def getDevelopmentSeries(self):
'''
Returns a DistroSeries object of the current development series.
'''
dev = DistroSeries(self.current_series_link)
# Cache it in _series if not already done
if dev.name not in self._series:
self._series[dev.name] = dev
self._series[dev.version] = dev
return dev
if not self._dev_series:
series = DistroSeries(self.current_series_link)
self._cache_series(series)
self._dev_series = series
return self._dev_series
def getAllSeries(self, active=True):
'''
Returns a list of all DistroSeries objects.
'''
if not self._have_all_series:
for s in Launchpad.load(self.series_collection_link).entries:
series = DistroSeries(s['self_link'])
self._cache_series(series)
self._have_all_series = True
allseries = filter(lambda s: s.active, self._series.values())
allseries = sorted(allseries,
key=lambda s: float(s.version),
reverse=True)
Logger.debug("Found series: %s" % ", ".join(map(lambda s: "%s (%s)" %
(s.name, s.version),
allseries)))
return collections.OrderedDict((s.name, s) for s in allseries)
class DistroArchSeries(BaseWrapper):
@ -273,6 +308,12 @@ class DistroArchSeries(BaseWrapper):
'''
resource_type = 'distro_arch_series'
def getSeries(self):
'''
Get DistroSeries for this.
'''
return DistroSeries(self._lpobject.distroseries_link)
class DistroSeries(BaseWrapper):
'''
@ -284,12 +325,16 @@ class DistroSeries(BaseWrapper):
if "_architectures" not in self.__dict__:
self._architectures = dict()
def getArchSeries(self, archtag):
def getArchSeries(self, archtag=None):
'''
Returns a DistroArchSeries object for an architecture passed by name
(e.g. 'amd64').
If arch is not specified, get the DistroArchSeries for the system arch.
The special archtag 'all' will get the system arch.
If the architecture is not found: raise ArchSeriesNotFoundException.
'''
if not archtag or archtag == 'all':
archtag = host_architecture()
if archtag not in self._architectures:
try:
architecture = DistroArchSeries(
@ -315,16 +360,35 @@ class Archive(BaseWrapper):
self._pkgset_uploaders = {}
self._component_uploaders = {}
def getSourcePackage(self, name, series=None, pocket=None):
def getSourcePackage(self, name, series=None, pocket=None, version=None,
status=None, wrapper=None, search_all_series=False):
'''
Returns a SourcePackagePublishingHistory object for the most
recent source package in the distribution 'dist', series and
pocket.
series defaults to the current development series if not specified.
series must be either a series name string, or DistroSeries object.
pocket may be a list, if so, the highest version will be returned.
It defaults to all pockets except backports.
version may be specified to get only the exact version requested.
pocket may be a string or a list. If no version is provided, it
defaults to all pockets except 'Backports'; if searching for a
specific version, it defaults to all pockets. Pocket strings must
be capitalized.
status may be a string or a list. If no version is provided, it
defaults to only 'Pending' and 'Published'; if searching for a
specific version, it defaults to all statuses. Status strings must
be capitalized.
wrapper is the class to return an instance of; defaults to
SourcePackagePublishingHistory.
search_all_series is used if series is None. If False, this will
search only the latest devel series, and if True all series
will be searched, in reverse order, starting with the latest
devel series. Defaults to False.
If the requested source package doesn't exist a
PackageNotFoundException is raised.
@ -332,114 +396,237 @@ class Archive(BaseWrapper):
return self._getPublishedItem(name, series, pocket, cache=self._srcpkgs,
function='getPublishedSources',
name_key='source_name',
wrapper=SourcePackagePublishingHistory)
wrapper=wrapper or SourcePackagePublishingHistory,
version=version,
status=status,
search_all_series=search_all_series,
binary=False)
def getBinaryPackage(self, name, archtag=None, series=None, pocket=None):
def getBinaryPackage(self, name, archtag=None, series=None, pocket=None,
version=None, status=None, wrapper=None,
search_all_series=False):
'''
Returns a BinaryPackagePublishingHistory object for the most
recent source package in the distribution 'dist', architecture
'archtag', series and pocket.
series defaults to the current development series if not specified.
series must be either a series name string, or DistroArchSeries object.
series may be omitted if version is specified.
pocket may be a list, if so, the highest version will be returned.
It defaults to all pockets except backports.
version may be specified to get only the exact version requested.
pocket may be a string or a list. If no version is provided, it
defaults to all pockets except 'Backports'; if searching for a
specific version, it defaults to all pockets. Pocket strings must
be capitalized.
status may be a string or a list. If no version is provided, it
defaults to only 'Pending' and 'Published'; if searching for a
specific version, it defaults to all statuses. Status strings must
be capitalized.
wrapper is the class to return an instance of; defaults to
BinaryPackagePublishingHistory.
search_all_series is used if series is None. If False, this will
search only the latest devel series, and if True all series
will be searched, in reverse order, starting with the latest
devel series. Defaults to False.
If the requested binary package doesn't exist a
PackageNotFoundException is raised.
'''
if archtag is None:
archtag = []
return self._getPublishedItem(name, series, pocket, archtag=archtag,
cache=self._binpkgs,
function='getPublishedBinaries',
name_key='binary_name',
wrapper=BinaryPackagePublishingHistory)
wrapper=wrapper or BinaryPackagePublishingHistory,
version=version,
status=status,
search_all_series=search_all_series,
binary=True)
def _getPublishedItem(self, name, series, pocket, cache,
function, name_key, wrapper, archtag=None):
'''Common code between getSourcePackage and getBinaryPackage
function, name_key, wrapper, archtag=None,
version=None, status=None, search_all_series=False,
binary=False):
'''
if pocket is None:
pockets = frozenset(('Proposed', 'Updates', 'Security', 'Release'))
elif isinstance(pocket, str):
pockets = frozenset((pocket,))
else:
pockets = frozenset(pocket)
Common code between getSourcePackage and getBinaryPackage.
for pocket in pockets:
if pocket not in _POCKETS:
raise PocketDoesNotExistError("Pocket '%s' does not exist." %
pocket)
Don't use this directly.
'''
if not pocket:
if version and not series:
# check ALL pockets if specific version in any series
pockets = POCKETS
else:
# otherwise, check all pockets EXCEPT 'Backports'
pockets = DEFAULT_POCKETS
elif isinstance(pocket, str):
pockets = (pocket,)
else:
pockets = tuple(pocket)
for p in pockets:
if p not in POCKETS:
raise PocketDoesNotExistError("Pocket '%s' does not exist." % p)
if not status:
if version:
# check ALL statuses if specific version
statuses = STATUSES
else:
# otherwise, only check 'Pending' and 'Published'
statuses = DEFAULT_STATUSES
elif isinstance(status, str):
statuses = (status,)
else:
statuses = tuple(status)
for s in statuses:
if s not in STATUSES:
raise ValueError("Status '%s' is not valid." % s)
dist = Distribution(self.distribution_link)
# Check if series is already a DistroSeries object or not
if not isinstance(series, DistroSeries):
if series:
# please don't pass DistroArchSeries as archtag!
# but, the code was like that before so keep
# backwards compatibility.
if isinstance(archtag, DistroArchSeries):
series = archtag
archtag = None
series_to_check = [series]
if not version and not series:
# if neither version or series are specified, use either the
# devel series or search all series
if search_all_series:
series_to_check = dist.getAllSeries().values()
else:
series_to_check = [dist.getDevelopmentSeries()]
# check each series - if only version was provided, series will be None
for series in series_to_check:
arch_series = None
if isinstance(series, DistroArchSeries):
arch_series = series
series = series.getSeries()
elif isinstance(series, DistroSeries):
pass
elif series:
series = dist.getSeries(series)
else:
series = dist.getDevelopmentSeries()
# getPublishedSources requires a distro_series, while
# getPublishedBinaries requires a distro_arch_series.
# If archtag is not None, I'll assume it's getPublishedBinaries.
if archtag is not None and archtag != []:
if not isinstance(archtag, DistroArchSeries):
if binary:
if arch_series is None and series:
arch_series = series.getArchSeries(archtag=archtag)
else:
arch_series = archtag
if archtag is None and arch_series:
archtag = arch_series.architecture_tag
if archtag is None:
archtag = host_architecture()
if archtag is not None and archtag != []:
index = (name, series.name, archtag, pockets)
else:
index = (name, series.name, pockets)
index = (name, getattr(series, 'name', None), archtag, pockets, statuses, version)
if index in cache:
return cache[index]
if index not in cache:
params = {
name_key: name,
'status': 'Published',
'exact_match': True,
}
if archtag is not None and archtag != []:
if arch_series:
params['distro_arch_series'] = arch_series()
else:
elif series:
params['distro_series'] = series()
if len(pockets) == 1:
params['pocket'] = list(pockets)[0]
params['pocket'] = pockets[0]
if len(statuses) == 1:
params['status'] = statuses[0]
if version:
params['version'] = version
Logger.debug('Calling %s(%s)' % (function,
', '.join(['%s=%s' % (k, v)
for (k, v) in params.items()])))
records = getattr(self, function)(**params)
latest = None
for record in records:
if record.pocket not in pockets:
continue
if latest is None or (Version(latest.source_package_version)
< Version(record.source_package_version)):
latest = record
err_msg = ("does not exist in the %s %s archive" %
(dist.display_name, self.name))
for record in records:
if binary:
rversion = getattr(record, 'binary_package_version', None)
else:
rversion = getattr(record, 'source_package_version', None)
skipmsg = ('Skipping version %s: ' % rversion)
if record.pocket not in pockets:
err_msg = 'pocket %s not in (%s)' % (record.pocket, ','.join(pockets))
Logger.debug(skipmsg + err_msg)
continue
if record.status not in statuses:
err_msg = 'status %s not in (%s)' % (record.status, ','.join(statuses))
Logger.debug(skipmsg + err_msg)
continue
r = wrapper(record)
if binary and archtag and archtag != r.arch:
err_msg = 'arch %s does not match requested arch %s' % (r.arch, archtag)
Logger.debug(skipmsg + err_msg)
continue
# results are ordered so first is latest
cache[index] = r
return r
version_with_epoch = None
if version and version == Version(version).strip_epoch() and len(records) == 0:
# a specific version was asked for, but we found none;
# check if one exists with an epoch to give a hint in error msg
for epoch in range(1, 9):
v = Version(version)
v.epoch = epoch
params['version'] = v.full_version
if len(getattr(self, function)(**params)) > 0:
version_with_epoch = v.full_version
Logger.debug('Found version with epoch %s' % version_with_epoch)
break
if latest is None:
if name_key == 'binary_name':
package_type = "binary package"
elif name_key == 'source_name':
package_type = "source package"
else:
package_type = "package"
msg = ("The %s '%s' does not exist in the %s %s archive" %
(package_type, name, dist.display_name, self.name))
if archtag is not None and archtag != []:
msg = "The %s '%s' " % (package_type, name)
if version:
msg += "version %s " % version
msg += err_msg
if binary and archtag:
msg += " for architecture %s" % archtag
pockets = [series.name if pocket == 'Release'
else '%s-%s' % (series.name, pocket.lower())
for pocket in pockets]
if len(pockets) > 1:
pockets[-2:] = [' or '.join(pockets[-2:])]
msg += " in " + ', '.join(pockets)
if len(series_to_check) > 1:
msg += " in any release"
if len(pockets) == 1:
msg += " for pocket %s" % pockets[0]
elif len(pockets) != len(POCKETS):
msg += " for pockets " + ', '.join(pockets)
elif series:
msg += " in %s" % series.name
if len(pockets) == 1:
msg += "-%s" % pockets[0]
elif len(pockets) != len(POCKETS):
msg += " for pockets " + ', '.join(pockets)
if len(statuses) == 1:
msg += " with status %s" % statuses[0]
elif len(statuses) != len(STATUSES):
msg += " with status in " + ', '.join(statuses)
if version_with_epoch:
msg += " (did you forget the epoch? try %s)" % version_with_epoch
raise PackageNotFoundException(msg)
cache[index] = wrapper(latest)
return cache[index]
def copyPackage(self, source_name, version, from_archive, to_pocket,
to_series=None, sponsored=None, include_binaries=False):
'''Copy a single named source into this archive.
@ -509,13 +696,24 @@ class SourcePackagePublishingHistory(BaseWrapper):
resource_type = 'source_package_publishing_history'
def __init__(self, *args):
self._archive = None
self._changelog = None
self._binaries = None
self._binaries = {}
self._have_all_binaries = False
self._distro_series = None
# Don't share _builds between different
# SourcePackagePublishingHistory objects
if '_builds' not in self.__dict__:
self._builds = dict()
def getDistroSeries(self):
'''
Return the DistroSeries.
'''
if not self._distro_series:
self._distro_series = DistroSeries(self._lpobject.distro_series_link)
return self._distro_series
def getPackageName(self):
'''
Returns the source package name.
@ -534,16 +732,33 @@ class SourcePackagePublishingHistory(BaseWrapper):
'''
return self._lpobject.component_name
def getSeriesName(self):
'''
Returns the series
Named getSeriesName() to avoid confusion with
getDistroSeries()
'''
return self.getDistroSeries().name
def getSeriesAndPocket(self):
'''
Returns a human-readable release-pocket
'''
series = DistroSeries(self._lpobject.distro_series_link)
release = series.name
if self._lpobject.pocket != 'Release':
release += '-' + self._lpobject.pocket.lower()
release = self.getSeriesName()
if self.pocket != 'Release':
release += '-' + self.pocket.lower()
return release
def getArchive(self):
'''
Get this SPPH's archive.
'''
if not self._archive:
self._archive = Archive(self._lpobject.archive_link)
return self._archive
def getChangelog(self, since_version=None):
'''
Return the changelog, optionally since a particular version
@ -553,17 +768,17 @@ class SourcePackagePublishingHistory(BaseWrapper):
if self._changelog is None:
url = self._lpobject.changelogUrl()
if url is None:
print('E: No changelog available for %s %s' %
(self.getPackageName(), self.getVersion()), file=sys.stderr)
Logger.error('No changelog available for %s %s' %
(self.getPackageName(), self.getVersion()))
return None
try:
response, changelog = Http().request(url)
except HttpLib2Error as e:
print(str(e), file=sys.stderr)
Logger.error(str(e))
return None
if response.status != 200:
print('%s: %s %s' % (url, response.status, response.reason), file=sys.stderr)
Logger.error('%s: %s %s' % (url, response.status, response.reason))
return None
self._changelog = changelog
@ -580,15 +795,97 @@ class SourcePackagePublishingHistory(BaseWrapper):
new_entries.append(str(block))
return ''.join(new_entries)
def getBinaries(self):
def getBinaries(self, arch, name=None, ext=None):
'''
Returns the resulting BinaryPackagePublishingHistorys
Returns the resulting BinaryPackagePublishingHistorys.
Must specify arch, or use 'all' to get all archs.
If name is specified, only returns BPPH matching that (regex) name.
If ext is specified, only returns BPPH matching that (regex) ext.
'''
if self._binaries is None:
self._binaries = [BinaryPackagePublishingHistory(bpph)
for bpph in
self._lpobject.getPublishedBinaries()]
return self._binaries
if not arch:
raise RuntimeError("Must specify arch")
# debs with arch 'all' have to be categorized as a specific arch
# so use requested arch if not 'all', or system arch
fallback_arch = arch
if fallback_arch == 'all':
fallback_arch = host_architecture()
if self._have_all_binaries:
# Great!
pass
elif self.status in ["Pending", "Published"]:
# Published, great! Directly query the list of binaries
binaries = map(BinaryPackagePublishingHistory,
self._lpobject.getPublishedBinaries())
for b in binaries:
a = b.arch
if a == 'all':
a = fallback_arch
if a not in self._binaries:
self._binaries[a] = {}
self._binaries[a][b.binary_package_name] = b
self._have_all_binaries = True
else:
# we have to go the long way :(
Logger.info("Please wait, this may take some time...")
archive = self.getArchive()
urls = self.binaryFileUrls()
for url in urls:
# strip out the URL leading text.
filename = url.rsplit('/', 1)[1]
# strip the file suffix
(pkgname, _, e) = filename.rpartition('.')
# split into name, version, arch
(n, v, a) = pkgname.rsplit('_', 2)
if a == 'all':
a = fallback_arch
# Only check the arch requested - saves time
if arch != 'all' and arch != a:
continue
# Only check the name requested - saves time
if name and not re.match(name, n):
continue
# Only check the ext requested - saves time
if ext and not re.match(ext, e):
continue
# If we already have this BPPH, keep going
if a in self._binaries and n in self._binaries[a]:
continue
# we ignore the version, as it may be missing epoch
# also we can't use series, as some package versions
# span multiple series! (e.g. for different archs)
params = {'name': n,
'archtag': a,
'version': self.getVersion()}
try:
bpph = archive.getBinaryPackage(**params)
except PackageNotFoundException:
Logger.debug("Could not find pkg in archive: %s" % filename)
continue
if a not in self._binaries:
self._binaries[a] = {}
self._binaries[a][n] = bpph
if not name and not ext and arch == 'all':
# We must have got them all
self._have_all_binaries = True
bpphs = []
if arch == 'all':
for a in self._binaries.values():
bpphs += a.values()
elif arch in self._binaries:
bpphs = self._binaries[arch].copy().values()
if name:
bpphs = [b for b in bpphs if re.match(name, b.binary_package_name)]
if ext:
bpphs = [b for b in bpphs if re.match(ext, b.getFileExt())]
return bpphs
def _fetch_builds(self):
'''Populate self._builds with the build records.'''
@ -648,6 +945,23 @@ class BinaryPackagePublishingHistory(BaseWrapper):
'''
resource_type = 'binary_package_publishing_history'
def __init__(self, *args):
self._arch = None
self._ext = None
@property
def arch(self):
if not self._arch:
das = DistroArchSeries(self._lpobject.distro_arch_series_link)
self._arch = das.architecture_tag
return self._arch
def getSourcePackageName(self):
'''
Returns the source package name.
'''
return self.getBuild().source_package_name
def getPackageName(self):
'''
Returns the binary package name.
@ -672,11 +986,84 @@ class BinaryPackagePublishingHistory(BaseWrapper):
Only available in the devel API, not 1.0
'''
try:
return self._lpobject.binaryFileUrls()
urls = self._lpobject.binaryFileUrls()
if not urls:
Logger.warning('BPPH %s_%s has no binaryFileUrls' %
(self.getPackageName(), self.getVersion()))
return urls
except AttributeError:
raise AttributeError("binaryFileUrls can only be found in lpapi "
"devel, not 1.0. Login using devel to have it.")
def getBuild(self):
'''
Returns the original build of the binary package.
'''
return Build(self._lpobject.build_link)
def getUrl(self):
'''
Returns the original build URL of the binary package.
'''
return "{build}/+files/{filename}".format(build=self.getBuild().getUrl(),
filename=self.getFileName())
def getFileVersion(self):
'''
Returns the file version, which is the package version without the epoch
'''
return Version(self.getVersion()).strip_epoch()
def getFileArch(self):
'''
Returns the file arch, which is 'all' if not arch-specific
'''
if bool(self._lpobject.architecture_specific):
return self.arch
else:
return 'all'
def getFileExt(self):
'''
Returns the file extension; "deb", "ddeb", or "udeb".
'''
if not self._ext:
self._ext = self._getFileExt()
return self._ext
def _getFileExt(self):
try:
# this is the best way, from the actual URL filename
return self.binaryFileUrls()[0].rpartition('.')[2]
except (AttributeError, IndexError):
Logger.debug('Could not get file ext from url, trying to guess...')
# is_debug should be reliable way of detecting ddeb...?
try:
if self.is_debug:
return "ddeb"
except AttributeError:
# is_debug only available with api version 'devel'
if self.getPackageName().endswith("-dbgsym"):
return "ddeb"
# is this reliable?
if self.getPackageName().endswith("-di") or self.getPackageName().endswith("-udeb"):
return "udeb"
# everything else - assume regular deb
return "deb"
def getFileName(self):
'''
Returns the filename for this binary package.
'''
return "{name}_{version}_{arch}.{ext}".format(name=self.getPackageName(),
version=self.getFileVersion(),
arch=self.getFileArch(),
ext=self.getFileExt())
class MetaPersonTeam(MetaWrapper):
@property
@ -705,6 +1092,7 @@ class PersonTeam(BaseWrapper, metaclass=MetaPersonTeam):
def __init__(self, *args):
# Don't share _upload between different PersonTeams
self._ppas = None
if '_upload' not in self.__dict__:
self._upload = dict()
@ -754,7 +1142,7 @@ class PersonTeam(BaseWrapper, metaclass=MetaPersonTeam):
if package is None and component is None:
raise ValueError('Either a source package name or a component has '
'to be specified.')
if pocket not in _POCKETS:
if pocket not in POCKETS:
raise PocketDoesNotExistError("Pocket '%s' does not exist." %
pocket)
@ -782,6 +1170,16 @@ class PersonTeam(BaseWrapper, metaclass=MetaPersonTeam):
return canUpload
def getPPAs(self):
if self._ppas is None:
ppas = [Archive(ppa['self_link']) for ppa in
Launchpad.load(self._lpobject.ppas_collection_link).entries]
self._ppas = {ppa.name: ppa for ppa in ppas}
return self._ppas
def getPPAByName(self, name):
return Archive(self._lpobject.getPPAByName(name=name))
class Build(BaseWrapper):
'''
@ -792,6 +1190,18 @@ class Build(BaseWrapper):
def __str__(self):
return u'%s: %s' % (self.arch_tag, self.buildstate)
def getSourcePackagePublishingHistory(self):
link = self._lpobject.current_source_publication_link
if link:
if re.search('redacted', link):
# Too old - the link has been 'redacted'
return None
return SourcePackagePublishingHistory(link)
return None
def getUrl(self):
return self()
def rescore(self, score):
if self.can_be_rescored:
self().rescore(score=score)

View File

@ -26,3 +26,8 @@ class AlreadyLoggedInError(Exception):
class ArchSeriesNotFoundException(BaseException):
"""Thrown when a distroarchseries is not found."""
pass
class InvalidDistroValueError(ValueError):
""" Thrown when distro value is invalid """
pass

View File

@ -32,6 +32,12 @@ import distro_info
from ubuntutools.lp.udtexceptions import PocketDoesNotExistError
DEFAULT_POCKETS = ('Release', 'Security', 'Updates', 'Proposed')
POCKETS = DEFAULT_POCKETS + ('Backports',)
DEFAULT_STATUSES = ('Pending', 'Published')
STATUSES = DEFAULT_STATUSES + ('Superseded', 'Deleted', 'Obsolete')
_system_distribution_chain = []
@ -141,7 +147,7 @@ def split_release_pocket(release, default='Release'):
(release, pocket) = release.rsplit('-', 1)
pocket = pocket.capitalize()
if pocket not in ('Release', 'Security', 'Updates', 'Proposed', 'Backports'):
if pocket not in POCKETS:
raise PocketDoesNotExistError("Pocket '%s' does not exist." % pocket)
return (release, pocket)

420
ubuntutools/pullpkg.py Normal file
View File

@ -0,0 +1,420 @@
# pullpkg.py -- pull package files for debian/ubuntu/uca
# modified from ../pull-lp-source and converted to module
#
# Copyright (C) 2008, Iain Lane <iain@orangesquash.org.uk>,
# 2010-2011, Stefano Rivera <stefanor@ubuntu.com>
# 2017, Dan Streetman <dan.streetman@canonical.com>
#
# ##################################################################
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 3
# 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 General Public License for more details.
#
# See file /usr/share/common-licenses/GPL for more details.
#
# ##################################################################
import re
import sys
import errno
from argparse import ArgumentParser
from distro_info import DebianDistroInfo
from ubuntutools.archive import (UbuntuSourcePackage, DebianSourcePackage,
UbuntuCloudArchiveSourcePackage,
PersonalPackageArchiveSourcePackage)
from ubuntutools.config import UDTConfig
from ubuntutools.lp.lpapicache import (Distribution, Launchpad)
from ubuntutools.lp.udtexceptions import (SeriesNotFoundException,
PackageNotFoundException,
PocketDoesNotExistError,
InvalidDistroValueError)
from ubuntutools.misc import (split_release_pocket, host_architecture, STATUSES)
from ubuntutools import _loggingBasicConfig
import logging
Logger = logging.getLogger(__name__)
PULL_SOURCE = 'source'
PULL_DEBS = 'debs'
PULL_DDEBS = 'ddebs'
PULL_UDEBS = 'udebs'
PULL_LIST = 'list'
VALID_PULLS = [PULL_SOURCE, PULL_DEBS, PULL_DDEBS, PULL_UDEBS, PULL_LIST]
VALID_BINARY_PULLS = [PULL_DEBS, PULL_DDEBS, PULL_UDEBS]
DISTRO_DEBIAN = 'debian'
DISTRO_UBUNTU = 'ubuntu'
DISTRO_UCA = 'uca'
DISTRO_PPA = 'ppa'
DISTRO_PKG_CLASS = {
DISTRO_DEBIAN: DebianSourcePackage,
DISTRO_UBUNTU: UbuntuSourcePackage,
DISTRO_UCA: UbuntuCloudArchiveSourcePackage,
DISTRO_PPA: PersonalPackageArchiveSourcePackage,
}
VALID_DISTROS = DISTRO_PKG_CLASS.keys()
class InvalidPullValueError(ValueError):
""" Thrown when --pull value is invalid """
pass
class PullPkg(object):
"""Class used to pull file(s) associated with a specific package"""
@classmethod
def main(cls, *args, **kwargs):
"""For use by stand-alone cmdline scripts.
This will handle catching certain exceptions or kbd interrupts,
setting up the root logger level to INFO, and printing out
(via Logger) a caught error message, instead of allowing the
exception to flow up to the script. This does not catch
unexpected exceptions, such as internal errors.
On (expected) error, this will call sys.exit(error);
unexpected errors will flow up to the caller.
On success, this simply returns.
"""
_loggingBasicConfig()
try:
cls(*args, **kwargs).pull()
return
except KeyboardInterrupt:
Logger.info('User abort.')
except (PackageNotFoundException, SeriesNotFoundException,
PocketDoesNotExistError, InvalidDistroValueError) as e:
Logger.error(str(e))
sys.exit(errno.ENOENT)
def __init__(self, *args, **kwargs):
self._default_pull = kwargs.get('pull')
self._default_distro = kwargs.get('distro')
self._default_arch = kwargs.get('arch', host_architecture())
def parse_args(self, args):
args = args[:]
help_default_pull = "What to pull: " + ", ".join(VALID_PULLS)
if self._default_pull:
help_default_pull += (" (default: %s)" % self._default_pull)
help_default_distro = "Pull from: " + ", ".join(VALID_DISTROS)
if self._default_distro:
help_default_distro += (" (default: %s)" % self._default_distro)
help_default_arch = ("Get binary packages for arch")
help_default_arch += ("(default: %s)" % self._default_arch)
# use add_help=False because we do parse_known_args() below, and if
# that sees --help then it exits immediately
parser = ArgumentParser(add_help=False)
parser.add_argument('-v', '--verbose', action='count', default=0,
help="Increase verbosity/debug")
parser.add_argument('-d', '--download-only', action='store_true',
help="Do not extract the source package")
parser.add_argument('-m', '--mirror', action='append',
help='Preferred mirror(s)')
parser.add_argument('--no-conf', action='store_true',
help="Don't read config files or environment variables")
parser.add_argument('--no-verify-signature', action='store_true',
help="Don't fail if dsc signature can't be verified")
parser.add_argument('-s', '--status', action='append', default=[],
help="Search for packages with specific status(es)")
parser.add_argument('-a', '--arch', default=self._default_arch,
help=help_default_arch)
parser.add_argument('-p', '--pull', default=self._default_pull,
help=help_default_pull)
parser.add_argument('-D', '--distro', default=self._default_distro,
help=help_default_distro)
# add distro-specific params
try:
distro = self.parse_distro(parser.parse_known_args(args)[0].distro)
except InvalidDistroValueError:
# don't fail at this point, finish setting up parser help/usage
distro = None
if distro == DISTRO_UBUNTU:
parser.add_argument('--security', action='store_true',
help='Check the Ubuntu Security Team PPA')
if distro == DISTRO_PPA:
parser.add_argument('--ppa', help='PPA to pull from')
if parser.parse_known_args(args)[0].ppa is None:
# check for any param starting with "ppa:"
# if found, move it to a --ppa param
for param in args:
if param.startswith('ppa:'):
args.remove(param)
args.insert(0, param)
args.insert(0, '--ppa')
break
# add the positional params
parser.add_argument('package', help="Package name to pull")
parser.add_argument('release', nargs='?', help="Release to pull from")
parser.add_argument('version', nargs='?', help="Package version to pull")
epilog = ("Note on --status: if a version is provided, all status types "
"will be searched; if no version is provided, by default only "
"'Pending' and 'Published' status will be searched.")
# since parser has no --help handler, create a new parser that does
newparser = ArgumentParser(parents=[parser], epilog=epilog)
return self.parse_options(vars(newparser.parse_args(args)))
def parse_pull(self, pull):
if not pull:
raise InvalidPullValueError("Must specify --pull")
# allow 'dbgsym' as alias for 'ddebs'
if pull == 'dbgsym':
Logger.debug("Pulling '%s' for '%s'", PULL_DDEBS, pull)
pull = PULL_DDEBS
# assume anything starting with 'bin' means 'debs'
if str(pull).startswith('bin'):
Logger.debug("Pulling '%s' for '%s'", PULL_DEBS, pull)
pull = PULL_DEBS
# verify pull action is valid
if pull not in VALID_PULLS:
raise InvalidPullValueError("Invalid pull action '%s'" % pull)
return pull
def parse_distro(self, distro):
if not distro:
raise InvalidDistroValueError("Must specify --distro")
distro = distro.lower()
# allow 'lp' for 'ubuntu'
if distro == 'lp':
Logger.debug("Using distro '%s' for '%s'", DISTRO_UBUNTU, distro)
distro = DISTRO_UBUNTU
# assume anything with 'cloud' is UCA
if re.match(r'.*cloud.*', distro):
Logger.debug("Using distro '%s' for '%s'", DISTRO_UCA, distro)
distro = DISTRO_UCA
# verify distro is valid
if distro not in VALID_DISTROS:
raise InvalidDistroValueError("Invalid distro '%s'" % distro)
return distro
def parse_release(self, distro, release):
if distro == DISTRO_UCA:
# UCA is special; it is specified UBUNTURELEASE-UCARELEASE or just
# UCARELEASE. The user could also specify UCARELEASE-POCKET. But UCA
# archives always correspond to only one UBUNTURELEASE, and UCA archives
# have only the Release pocket, so only UCARELEASE matters to us.
for r in release.split('-'):
if UbuntuCloudArchiveSourcePackage.isValidRelease(r):
Logger.debug("Using UCA release '%s'", r)
return (r, None)
raise SeriesNotFoundException('UCA release {} not found.'.format(release))
# Check if release[-pocket] is specified
(release, pocket) = split_release_pocket(release, default=None)
Logger.debug("Parsed release '%s' pocket '%s'", release, pocket)
if distro == DISTRO_DEBIAN:
# This converts from the aliases like 'unstable'
debian_info = DebianDistroInfo()
codename = debian_info.codename(release)
if codename:
Logger.info("Using release '%s' for '%s'", codename, release)
release = codename
if distro == DISTRO_PPA:
# PPAs are part of Ubuntu distribution
d = Distribution(DISTRO_UBUNTU)
else:
d = Distribution(distro)
# let SeriesNotFoundException flow up
d.getSeries(release)
Logger.debug("Using distro '%s' release '%s' pocket '%s'",
distro, release, pocket)
return (release, pocket)
def parse_release_and_version(self, distro, release, version, try_swap=True):
# Verify specified release is valid, and params in correct order
pocket = None
try:
(release, pocket) = self.parse_release(distro, release)
except (SeriesNotFoundException, PocketDoesNotExistError):
if try_swap:
Logger.debug("Param '%s' not valid series, must be version", release)
release, version = version, release
if release:
return self.parse_release_and_version(distro, release, version, False)
else:
Logger.error("Can't find series for '%s' or '%s'", release, version)
raise
return (release, version, pocket)
def parse_options(self, options):
# if any of these fail, there is a problem with the parser
# they should all be provided, though the optional ones may be None
# type bool
assert 'verbose' in options
assert 'download_only' in options
assert 'no_conf' in options
assert 'no_verify_signature' in options
assert 'status' in options
# type string
assert 'pull' in options
assert 'distro' in options
assert 'arch' in options
assert 'package' in options
# type string, optional
assert 'release' in options
assert 'version' in options
# type list of strings, optional
assert 'mirror' in options
options['pull'] = self.parse_pull(options['pull'])
options['distro'] = self.parse_distro(options['distro'])
# ensure these are always included so we can just check for None/False later
options['ppa'] = options.get('ppa', None)
options['security'] = options.get('security', False)
return options
def _get_params(self, options):
distro = options['distro']
pull = options['pull']
params = {}
params['package'] = options['package']
if options['release']:
(r, v, p) = self.parse_release_and_version(distro, options['release'],
options['version'])
params['series'] = r
params['version'] = v
params['pocket'] = p
if (params['package'].endswith('.dsc') and not params['series'] and not params['version']):
params['dscfile'] = params['package']
params.pop('package')
if options['security']:
if options['ppa']:
Logger.warning('Both --security and --ppa specified, ignoring --ppa')
Logger.debug('Checking Ubuntu Security PPA')
# --security is just a shortcut for --ppa ppa:ubuntu-security-proposed/ppa
options['ppa'] = 'ubuntu-security-proposed/ppa'
if options['ppa']:
if options['ppa'].startswith('ppa:'):
params['ppa'] = options['ppa'][4:]
else:
params['ppa'] = options['ppa']
elif distro == DISTRO_PPA:
raise ValueError('Must specify PPA to pull from')
mirrors = []
if options['mirror']:
mirrors.append(options['mirror'])
if pull == PULL_DDEBS:
config = UDTConfig(options['no_conf'])
ddebs_mirror = config.get_value(distro.upper() + '_DDEBS_MIRROR')
if ddebs_mirror:
mirrors.append(ddebs_mirror)
if mirrors:
Logger.debug("using mirrors %s", ", ".join(mirrors))
params['mirrors'] = mirrors
params['verify_signature'] = not options['no_verify_signature']
params['status'] = STATUSES if 'all' in options['status'] else options['status']
return params
def pull(self, args=sys.argv[1:]):
"""Pull (download) specified package file(s)"""
options = self.parse_args(args)
if options['verbose']:
Logger.setLevel(logging.DEBUG)
if options['verbose'] > 1:
logging.getLogger(__package__).setLevel(logging.DEBUG)
Logger.debug("pullpkg options: %s", options)
# Login anonymously to LP
Launchpad.login_anonymously()
pull = options['pull']
distro = options['distro']
params = self._get_params(options)
package = params['package']
# call implementation, and allow exceptions to flow up to caller
srcpkg = DISTRO_PKG_CLASS[distro](**params)
spph = srcpkg.lp_spph
Logger.info('Found %s', spph.display_name)
if pull == PULL_LIST:
Logger.info("Source files:")
for f in srcpkg.dsc['Files']:
Logger.info(" %s", f['name'])
Logger.info("Binary files:")
for f in spph.getBinaries(options['arch']):
Logger.info(" %s", f.getFileName())
elif pull == PULL_SOURCE:
# allow DownloadError to flow up to caller
srcpkg.pull()
if options['download_only']:
Logger.debug("--download-only specified, not extracting")
else:
srcpkg.unpack()
elif pull in VALID_BINARY_PULLS:
name = None
if package != spph.getPackageName():
Logger.info("Pulling only binary package '%s'", package)
Logger.info("Use package name '%s' to pull all binary packages",
spph.getPackageName())
name = package
# e.g. 'debs' -> 'deb'
ext = pull.rstrip('s')
if distro == DISTRO_DEBIAN:
# Debian ddebs don't use .ddeb extension, unfortunately :(
if pull in [PULL_DEBS, PULL_DDEBS]:
name = name or '.*'
ext = 'deb'
if pull == PULL_DEBS:
name += r'(?<!-dbgsym)$'
if pull == PULL_DDEBS:
name += r'-dbgsym$'
# allow DownloadError to flow up to caller
total = srcpkg.pull_binaries(name=name, ext=ext, arch=options['arch'])
if total < 1:
Logger.error("No %s found for %s %s", pull,
package, spph.getVersion())
else:
Logger.error("Internal error: invalid pull value after parse_pull()")
raise InvalidPullValueError("Invalid pull value '%s'" % pull)

View File

@ -29,9 +29,11 @@ from httplib2 import Http, HttpLib2Error
from ubuntutools.lp import udtexceptions
from ubuntutools.lp.lpapicache import (Launchpad, Distribution, PersonTeam,
DistributionSourcePackage)
from ubuntutools.logger import Logger
from ubuntutools.question import confirmation_prompt
import logging
Logger = logging.getLogger(__name__)
def get_debian_srcpkg(name, release):
debian = Distribution('debian')
@ -40,7 +42,7 @@ def get_debian_srcpkg(name, release):
try:
release = DebianDistroInfo().codename(release, None, release)
except DistroDataOutdated as e:
Logger.warn(e)
Logger.warning(e)
return debian_archive.getSourcePackage(name, release)

View File

@ -31,11 +31,12 @@ import tempfile
from debian.changelog import Changelog
from distro_info import DebianDistroInfo, DistroDataOutdated
from ubuntutools.archive import rmadison, FakeSPPH
from ubuntutools.archive import DebianSourcePackage, UbuntuSourcePackage
from ubuntutools.lp.udtexceptions import PackageNotFoundException
from ubuntutools.logger import Logger
from ubuntutools.question import confirmation_prompt, YesNoQuestion
from ubuntutools.version import Version
import logging
Logger = logging.getLogger(__name__)
__all__ = [
@ -48,32 +49,21 @@ __all__ = [
]
def _get_srcpkg(distro, name, release):
if distro == 'debian':
def get_debian_srcpkg(name, release):
# Canonicalise release:
debian_info = DebianDistroInfo()
try:
codename = debian_info.codename(release, default=release)
return DebianSourcePackage(package=name, series=codename).lp_spph
except DistroDataOutdated as e:
Logger.warn(e)
lines = list(rmadison(distro, name, suite=codename, arch='source'))
if not lines:
lines = list(rmadison(distro, name, suite=release, arch='source'))
if not lines:
raise PackageNotFoundException("'%s' doesn't appear to exist in %s '%s'" %
(name, distro.capitalize(), release))
pkg = max(lines, key=lambda x: Version(x['version']))
return FakeSPPH(pkg['source'], pkg['version'], pkg['component'], distro)
def get_debian_srcpkg(name, release):
return _get_srcpkg('debian', name, release)
Logger.warning(e)
except PackageNotFoundException:
pass
return DebianSourcePackage(package=name, series=release).lp_spph
def get_ubuntu_srcpkg(name, release):
return _get_srcpkg('ubuntu', name, release)
return UbuntuSourcePackage(package=name, series=release).lp_spph
def need_sponsorship(name, component, release):
@ -185,13 +175,13 @@ Content-Type: text/plain; charset=UTF-8
with backup:
backup.write(mail)
Logger.normal('The e-mail has been saved in %s and will be deleted '
Logger.info('The e-mail has been saved in %s and will be deleted '
'after succesful transmission', backup.name)
# connect to the server
while True:
try:
Logger.normal('Connecting to %s:%s ...', mailserver_host,
Logger.info('Connecting to %s:%s ...', mailserver_host,
mailserver_port)
s = smtplib.SMTP(mailserver_host, mailserver_port)
break
@ -238,7 +228,7 @@ Content-Type: text/plain; charset=UTF-8
s.sendmail(myemailaddr, to, mail.encode('utf-8'))
s.quit()
os.remove(backup.name)
Logger.normal('Sync request mailed.')
Logger.info('Sync request mailed.')
break
except smtplib.SMTPRecipientsRefused as smtperror:
smtp_code, smtp_message = smtperror.recipients[to]

View File

@ -23,9 +23,11 @@ from urllib.request import urlretrieve
import distro_info
import httplib2
from ubuntutools.logger import Logger
from ubuntutools.version import Version
import logging
Logger = logging.getLogger(__name__)
def is_sync(bug):
"""Checks if a Launchpad bug is a sync request.
@ -66,7 +68,7 @@ class BugTask(object):
dsc_file = ""
for url in source_files:
filename = unquote(os.path.basename(url))
Logger.info("Downloading %s..." % (filename))
Logger.debug("Downloading %s..." % (filename))
# HttpLib2 isn't suitable for large files (it reads into memory),
# but we want its https certificate validation on the .dsc
if url.endswith(".dsc"):

View File

@ -19,10 +19,12 @@ import os
import re
import subprocess
from ubuntutools.logger import Logger
from ubuntutools.sponsor_patch.question import ask_for_manual_fixing
from functools import reduce
import logging
Logger = logging.getLogger(__name__)
class Patch(object):
"""This object represents a patch that can be downloaded from Launchpad."""
@ -32,7 +34,7 @@ class Patch(object):
self._patch_file = re.sub(" |/", "_", patch.title)
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." %
Logger.debug("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)
@ -45,7 +47,7 @@ class Patch(object):
if self.is_debdiff():
cmd = ["patch", "--merge", "--force", "-p",
str(self.get_strip_level()), "-i", self._full_path]
Logger.command(cmd)
Logger.debug(' '.join(cmd))
if subprocess.call(cmd) != 0:
Logger.error("Failed to apply debdiff %s to %s %s.",
self._patch_file, task.package, task.get_version())
@ -54,7 +56,7 @@ class Patch(object):
edit = True
else:
cmd = ["add-patch", self._full_path]
Logger.command(cmd)
Logger.debug(' '.join(cmd))
if subprocess.call(cmd) != 0:
Logger.error("Failed to apply diff %s to %s %s.",
self._patch_file, task.package, task.get_version())
@ -65,7 +67,7 @@ class Patch(object):
def download(self):
"""Downloads the patch from Launchpad."""
Logger.info("Downloading %s." % (self._patch_file))
Logger.debug("Downloading %s." % (self._patch_file))
patch_f = open(self._patch_file, "w")
patch_f.write(self._patch.data.open().read())
patch_f.close()

View File

@ -23,13 +23,15 @@ import sys
import debian.changelog
import debian.deb822
from ubuntutools.logger import Logger
from ubuntutools.question import Question, YesNoQuestion
from ubuntutools.sponsor_patch.question import (ask_for_ignoring_or_fixing,
ask_for_manual_fixing,
user_abort)
import logging
Logger = logging.getLogger(__name__)
def _get_series(launchpad):
"""Returns a tuple with the development and list of supported series."""
@ -84,7 +86,7 @@ class SourcePackage(object):
if task.importance == "Undecided":
task.importance = "Wishlist"
task.lp_save()
Logger.info("Set bug #%i status to Confirmed.", bug.id)
Logger.debug("Set bug #%i status to Confirmed.", bug.id)
msg = "Sync request ACK'd."
if self._build_log:
@ -92,25 +94,25 @@ class SourcePackage(object):
(self._package, self._version,
self._builder.get_architecture())
bug.newMessage(content=msg, subject="sponsor-patch")
Logger.info("Acknowledged sync request bug #%i.", bug.id)
Logger.debug("Acknowledged sync request bug #%i.", bug.id)
bug.subscribe(person=launchpad.people['ubuntu-archive'])
Logger.info("Subscribed ubuntu-archive to bug #%i.", bug.id)
Logger.debug("Subscribed ubuntu-archive to bug #%i.", bug.id)
bug.subscribe(person=launchpad.me)
Logger.info("Subscribed me to bug #%i.", bug.id)
Logger.debug("Subscribed me to bug #%i.", bug.id)
sponsorsteam = launchpad.people['ubuntu-sponsors']
for sub in bug.subscriptions:
if sub.person == sponsorsteam and sub.canBeUnsubscribedByUser():
bug.unsubscribe(person=launchpad.people['ubuntu-sponsors'])
Logger.info("Unsubscribed ubuntu-sponsors from bug #%i.",
Logger.debug("Unsubscribed ubuntu-sponsors from bug #%i.",
bug.id)
elif sub.person == sponsorsteam:
Logger.info("Couldn't unsubscribe ubuntu-sponsors from "
Logger.debug("Couldn't unsubscribe ubuntu-sponsors from "
"bug #%i.", bug.id)
Logger.normal("Successfully acknowledged sync request bug #%i.",
Logger.info("Successfully acknowledged sync request bug #%i.",
bug.id)
else:
Logger.error("Sync requests can only be acknowledged when the "
@ -139,7 +141,7 @@ class SourcePackage(object):
elif answer == "no":
user_abort()
cmd = ["dput", "--force", upload, self._changes_file]
Logger.command(cmd)
Logger.debug(' '.join(cmd))
if subprocess.call(cmd) != 0:
Logger.error("Upload of %s to %s failed." %
(os.path.basename(self._changes_file), upload))
@ -148,17 +150,17 @@ class SourcePackage(object):
# Push the branch if the package is uploaded to the Ubuntu archive.
if upload == "ubuntu" and self._branch:
cmd = ['debcommit']
Logger.command(cmd)
Logger.debug(' '.join(cmd))
if subprocess.call(cmd) != 0:
Logger.error('Bzr commit failed.')
sys.exit(1)
cmd = ['bzr', 'mark-uploaded']
Logger.command(cmd)
Logger.debug(' '.join(cmd))
if subprocess.call(cmd) != 0:
Logger.error('Bzr tagging failed.')
sys.exit(1)
cmd = ['bzr', 'push', ':parent']
Logger.command(cmd)
Logger.debug(' '.join(cmd))
if subprocess.call(cmd) != 0:
Logger.error('Bzr push failed.')
sys.exit(1)
@ -239,7 +241,7 @@ class SourcePackage(object):
env = os.environ
if upload == 'ubuntu':
env['DEB_VENDOR'] = 'Ubuntu'
Logger.command(cmd)
Logger.debug(' '.join(cmd))
if subprocess.call(cmd, env=env) != 0:
Logger.error("Failed to build source tarball.")
# TODO: Add a "retry" option
@ -322,9 +324,9 @@ class SourcePackage(object):
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:
if not Logger.isEnabledFor(logging.DEBUG):
cmd.insert(1, "-q")
Logger.command(cmd + [">", self._debdiff_filename])
Logger.debug(' '.join(cmd) + " > " + self._debdiff_filename)
debdiff = subprocess.check_output(cmd, encoding='utf-8')
# write debdiff file
@ -417,7 +419,7 @@ class SourcePackage(object):
lintian_filename = os.path.join(self._workdir,
self._package + "_" +
strip_epoch(self._version) + ".lintian")
Logger.command(cmd + [">", lintian_filename])
Logger.debug(' '.join(cmd) + " > " + lintian_filename)
report = subprocess.check_output(cmd, encoding='utf-8')
# write lintian report file
@ -434,7 +436,7 @@ class SourcePackage(object):
cmd = ["syncpackage", self._package, "-b", str(bug_number), "-f",
"-s", requester, "-V", str(self._version),
"-d", series]
Logger.command(cmd)
Logger.debug(' '.join(cmd))
if subprocess.call(cmd) != 0:
Logger.error("Syncing of %s %s failed.", self._package,
str(self._version))

View File

@ -25,7 +25,6 @@ from distro_info import UbuntuDistroInfo
from launchpadlib.launchpad import Launchpad
from ubuntutools.logger import Logger
from ubuntutools.update_maintainer import (update_maintainer,
MaintainerUpdateException)
from ubuntutools.question import input_number
@ -35,6 +34,9 @@ from ubuntutools.sponsor_patch.patch import Patch
from ubuntutools.sponsor_patch.question import ask_for_manual_fixing
from ubuntutools.sponsor_patch.source_package import SourcePackage
import logging
Logger = logging.getLogger(__name__)
def is_command_available(command, check_sbin=False):
"Is command in $PATH?"
@ -59,7 +61,7 @@ def check_dependencies():
missing.append('pbuilder/cowbuilder/sbuild')
if missing:
Logger.warn("sponsor-patch requires %s to be installed for full "
Logger.warning("sponsor-patch requires %s to be installed for full "
"functionality", ', '.join(missing))
@ -82,7 +84,7 @@ def get_user_shell():
def edit_source():
# Spawn shell to allow modifications
cmd = [get_user_shell()]
Logger.command(cmd)
Logger.debug(' '.join(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
@ -112,7 +114,7 @@ def ask_for_patch_or_branch(bug, attached_patches, linked_branches):
patches += "es"
msg = "https://launchpad.net/bugs/%i has %s linked and %s attached:" % \
(bug.id, branches, patches)
Logger.normal(msg)
Logger.info(msg)
i = 0
for linked_branch in linked_branches:
i += 1
@ -160,7 +162,7 @@ def download_branch(branch):
if os.path.isdir(dir_name):
shutil.rmtree(dir_name)
cmd = ["bzr", "branch", branch]
Logger.command(cmd)
Logger.debug(' '.join(cmd))
if subprocess.call(cmd) != 0:
Logger.error("Failed to download branch %s." % (branch))
sys.exit(1)
@ -170,7 +172,7 @@ def download_branch(branch):
def merge_branch(branch):
edit = False
cmd = ["bzr", "merge", branch]
Logger.command(cmd)
Logger.debug(' '.join(cmd))
if subprocess.call(cmd) != 0:
Logger.error("Failed to merge branch %s." % (branch))
ask_for_manual_fixing()
@ -182,7 +184,7 @@ def extract_source(dsc_file, verbose=False):
cmd = ["dpkg-source", "--no-preparation", "-x", dsc_file]
if not verbose:
cmd.insert(1, "-q")
Logger.command(cmd)
Logger.debug(' '.join(cmd))
if subprocess.call(cmd) != 0:
Logger.error("Extraction of %s failed." % (os.path.basename(dsc_file)))
sys.exit(1)
@ -219,13 +221,13 @@ def get_open_ubuntu_bug_task(launchpad, bug, branch=None):
task = tasks[0]
elif len(ubuntu_tasks) > 1:
task_list = [t.get_short_info() for t in ubuntu_tasks]
Logger.info("%i Ubuntu tasks exist for bug #%i.\n%s", len(ubuntu_tasks),
Logger.debug("%i Ubuntu tasks exist for bug #%i.\n%s", len(ubuntu_tasks),
bug_id, "\n".join(task_list))
open_ubuntu_tasks = [x for x in ubuntu_tasks if not x.is_complete()]
if len(open_ubuntu_tasks) == 1:
task = open_ubuntu_tasks[0]
else:
Logger.normal("https://launchpad.net/bugs/%i has %i Ubuntu tasks:" %
Logger.info("https://launchpad.net/bugs/%i has %i Ubuntu tasks:" %
(bug_id, len(ubuntu_tasks)))
for i in range(len(ubuntu_tasks)):
print("%i) %s" % (i + 1,
@ -233,7 +235,7 @@ def get_open_ubuntu_bug_task(launchpad, bug, branch=None):
selected = input_number("To which Ubuntu task does the patch belong",
1, len(ubuntu_tasks))
task = ubuntu_tasks[selected - 1]
Logger.info("Selected Ubuntu task: %s" % (task.get_short_info()))
Logger.debug("Selected Ubuntu task: %s" % (task.get_short_info()))
return task
@ -248,15 +250,15 @@ def _create_and_change_into(workdir):
(workdir, error.errno, error.strerror))
sys.exit(1)
if workdir != os.getcwd():
Logger.command(["cd", workdir])
Logger.debug("cd " + workdir)
os.chdir(workdir)
def _update_maintainer_field():
"""Update the Maintainer field in debian/control."""
Logger.command(["update-maintainer"])
Logger.debug("update-maintainer")
try:
update_maintainer("debian", Logger.verbose)
update_maintainer("debian", Logger.isEnabledFor(logging.DEBUG))
except MaintainerUpdateException as e:
Logger.error("update-maintainer failed: %s", str(e))
sys.exit(1)
@ -265,9 +267,9 @@ def _update_maintainer_field():
def _update_timestamp():
"""Run dch to update the timestamp of debian/changelog."""
cmd = ["dch", "--maintmaint", "--release", ""]
Logger.command(cmd)
Logger.debug(' '.join(cmd))
if subprocess.call(cmd) != 0:
Logger.info("Failed to update timestamp in debian/changelog.")
Logger.debug("Failed to update timestamp in debian/changelog.")
def _download_and_change_into(task, dsc_file, patch, branch):
@ -277,23 +279,23 @@ def _download_and_change_into(task, dsc_file, patch, branch):
branch_dir = download_branch(task.get_branch_link())
# change directory
Logger.command(["cd", branch_dir])
Logger.debug("cd " + branch_dir)
os.chdir(branch_dir)
else:
if patch:
patch.download()
Logger.info("Ubuntu package: %s" % (task.package))
Logger.debug("Ubuntu package: %s" % (task.package))
if task.is_merge():
Logger.info("The task is a merge request.")
Logger.debug("The task is a merge request.")
if task.is_sync():
Logger.info("The task is a sync request.")
Logger.debug("The task is a sync request.")
extract_source(dsc_file, Logger.verbose)
extract_source(dsc_file, Logger.isEnabledFor(logging.DEBUG))
# change directory
directory = task.package + '-' + task.get_version().upstream_version
Logger.command(["cd", directory])
Logger.debug("cd " + directory)
os.chdir(directory)

View File

@ -20,10 +20,9 @@ import os.path
import shutil
import tempfile
from io import BytesIO
from urllib.error import HTTPError, URLError
from urllib.error import HTTPError
from urllib.request import OpenerDirector, urlopen
import debian.deb822
import httplib2
import ubuntutools.archive
@ -85,7 +84,6 @@ class LocalSourcePackageTestCase(unittest.TestCase):
self.workdir = tempfile.mkdtemp(prefix='udt-test')
self._stubout('ubuntutools.archive.Distribution')
self._stubout('ubuntutools.archive.rmadison')
self.mock_http = self._stubout('httplib2.Http.request')
self.mock_http.side_effect = self.request_proxy
@ -93,10 +91,6 @@ class LocalSourcePackageTestCase(unittest.TestCase):
self.url_opener = mock.MagicMock(spec=OpenerDirector)
self.url_opener.open.side_effect = self.urlopen_proxy
# Silence the tests a little:
self._stubout('ubuntutools.logger.Logger.stdout')
self._stubout('ubuntutools.logger.Logger.stderr')
def _stubout(self, stub):
patcher = mock.patch(stub)
self.addCleanup(patcher.stop)
@ -146,11 +140,13 @@ class LocalSourcePackageTestCase(unittest.TestCase):
return self.request_404(url)
def test_local_copy(self):
pkg = self.SourcePackage('example', '1.0-1', 'main',
pkg = self.SourcePackage(package='example',
version='1.0-1',
component='main',
dscfile='test-data/example_1.0-1.dsc',
workdir=self.workdir)
pkg.quiet = True
pkg.pull(verify_signature=False)
workdir=self.workdir,
verify_signature=False)
pkg.pull()
pkg.unpack()
def test_workdir_srcpkg_noinfo(self):
@ -160,9 +156,9 @@ class LocalSourcePackageTestCase(unittest.TestCase):
pkg = self.SourcePackage(dscfile=os.path.join(self.workdir,
'example_1.0-1.dsc'),
workdir=self.workdir)
pkg.quiet = True
pkg.pull(verify_signature=False)
workdir=self.workdir,
verify_signature=False)
pkg.pull()
pkg.unpack()
def test_workdir_srcpkg_info(self):
@ -170,12 +166,13 @@ class LocalSourcePackageTestCase(unittest.TestCase):
shutil.copy2('test-data/example_1.0.orig.tar.gz', self.workdir)
shutil.copy2('test-data/example_1.0-1.debian.tar.xz', self.workdir)
pkg = self.SourcePackage('example', '1.0-1', 'main',
pkg = self.SourcePackage(package='example', version='1.0-1',
component='main',
dscfile=os.path.join(self.workdir,
'example_1.0-1.dsc'),
workdir=self.workdir)
pkg.quiet = True
pkg.pull(verify_signature=False)
workdir=self.workdir,
verify_signature=False)
pkg.pull()
pkg.unpack()
def test_verification(self):
@ -186,103 +183,18 @@ class LocalSourcePackageTestCase(unittest.TestCase):
'r+b') as f:
f.write(b'CORRUPTION')
pkg = self.SourcePackage('example', '1.0-1', 'main',
pkg = self.SourcePackage(package='example',
version='1.0-1',
component='main',
dscfile='test-data/example_1.0-1.dsc',
workdir=self.workdir)
pkg.quiet = True
pkg.pull(verify_signature=False)
def test_pull(self):
pkg = self.SourcePackage('example', '1.0-1', 'main',
workdir=self.workdir)
pkg.url_opener = self.url_opener
pkg.quiet = True
pkg.pull(verify_signature=False)
def test_mirrors(self):
mirror = 'http://mirror'
sequence = [self.urlopen_null, self.urlopen_404, self.urlopen_proxy,
self.urlopen_proxy]
def _callable_iter(*args, **kwargs):
return sequence.pop(0)(*args, **kwargs)
url_opener = mock.MagicMock(spec=OpenerDirector)
url_opener.open.side_effect = _callable_iter
pkg = self.SourcePackage('example', '1.0-1', 'main',
workdir=self.workdir, mirrors=[mirror])
pkg.url_opener = url_opener
pkg.quiet = True
pkg.pull(verify_signature=False)
workdir=self.workdir,
verify_signature=False)
pkg.pull()
def test_dsc_missing(self):
self.mock_http.side_effect = self.request_404
pkg = self.SourcePackage('example', '1.0-1', 'main',
pkg = self.SourcePackage(package='example',
version='1.0-1',
component='main',
workdir=self.workdir)
pkg.quiet = True
self.assertRaises(ubuntutools.archive.DownloadError, pkg.pull)
class DebianLocalSourcePackageTestCase(LocalSourcePackageTestCase):
SourcePackage = ubuntutools.archive.DebianSourcePackage
def test_mirrors(self):
debian_mirror = 'http://mirror/debian'
debsec_mirror = 'http://mirror/debsec'
sequence = [self.urlopen_null,
self.urlopen_404,
self.urlopen_404,
self.urlopen_404,
self.urlopen_404,
lambda x: BytesIO(
b'{"fileinfo": {"hashabc": [{"name": "example_1.0.orig.tar.gz"}]}}'),
self.urlopen_file('example_1.0.orig.tar.gz'),
self.urlopen_proxy]
def _callable_iter(*args, **kwargs):
return sequence.pop(0)(*args, **kwargs)
url_opener = mock.MagicMock(spec=OpenerDirector)
url_opener.open.side_effect = _callable_iter
pkg = self.SourcePackage('example', '1.0-1', 'main',
workdir=self.workdir, mirrors=[debian_mirror,
debsec_mirror])
pkg.quiet = True
pkg.url_opener = url_opener
pkg.pull(verify_signature=False)
pkg.unpack()
def test_dsc_missing(self):
mirror = 'http://mirror'
self.mock_http.side_effect = self.request_404_then_proxy
patcher = mock.patch.object(debian.deb822.GpgInfo, 'from_sequence')
self.addCleanup(patcher.stop)
mock_gpg_info = patcher.start()
mock_gpg_info.return_value = debian.deb822.GpgInfo.from_output(
'[GNUPG:] GOODSIG DEADBEEF Joe Developer '
'<joe@example.net>')
pkg = self.SourcePackage('example', '1.0-1', 'main',
workdir=self.workdir, mirrors=[mirror])
pkg.url_opener = self.url_opener
pkg.pull(verify_signature=False)
def test_dsc_badsig(self):
mirror = 'http://mirror'
self.mock_http.side_effect = self.request_404_then_proxy
patcher = mock.patch.object(debian.deb822.GpgInfo, 'from_sequence')
self.addCleanup(patcher.stop)
mock_gpg_info = patcher.start()
mock_gpg_info.return_value = debian.deb822.GpgInfo.from_output(
'[GNUPG:] ERRSIG DEADBEEF')
pkg = self.SourcePackage('example', '1.0-1', 'main',
workdir=self.workdir, mirrors=[mirror])
try:
self.assertRaises(ubuntutools.archive.DownloadError, pkg.pull)
except URLError:
raise unittest.SkipTest('Test needs addr resolution to work')

View File

@ -18,11 +18,10 @@
import locale
import mock
import os
import sys
# import sys
from io import StringIO
from ubuntutools.config import UDTConfig, ubu_email
from ubuntutools.logger import Logger
from ubuntutools.test import unittest
@ -51,16 +50,16 @@ class ConfigTestCase(unittest.TestCase):
self.addCleanup(patcher.stop)
patcher.start()
Logger.stdout = StringIO()
Logger.stderr = StringIO()
# Logger.stdout = StringIO()
# Logger.stderr = StringIO()
self.clean_environment()
def tearDown(self):
self.assertEqual(Logger.stdout.getvalue(), '')
self.assertEqual(Logger.stderr.getvalue(), '')
Logger.stdout = sys.stdout
Logger.stderr = sys.stderr
# self.assertEqual(Logger.stdout.getvalue(), '')
# self.assertEqual(Logger.stderr.getvalue(), '')
# Logger.stdout = sys.stdout
# Logger.stderr = sys.stderr
self.clean_environment()
@ -98,11 +97,11 @@ REPEAT=yes
'INHERIT': 'user',
'REPEAT': 'yes',
})
errs = Logger.stderr.getvalue().strip()
Logger.stderr = StringIO()
self.assertEqual(len(errs.splitlines()), 1)
self.assertRegex(errs,
r'Warning: Cannot parse.*\bCOMMAND_EXECUTION=a')
# errs = Logger.stderr.getvalue().strip()
# Logger.stderr = StringIO()
# self.assertEqual(len(errs.splitlines()), 1)
# self.assertRegex(errs,
# r'Warning: Cannot parse.*\bCOMMAND_EXECUTION=a')
def get_value(self, *args, **kwargs):
config = UDTConfig(prefix='TEST')
@ -138,11 +137,11 @@ REPEAT=yes
self._config_files['user'] = 'COMPATFOOBAR=bar'
self.assertEqual(self.get_value('QUX', compat_keys=['COMPATFOOBAR']),
'bar')
errs = Logger.stderr.getvalue().strip()
Logger.stderr = StringIO()
self.assertEqual(len(errs.splitlines()), 1)
self.assertRegex(errs,
r'deprecated.*\bCOMPATFOOBAR\b.*\bTEST_QUX\b')
# errs = Logger.stderr.getvalue().strip()
# Logger.stderr = StringIO()
# self.assertEqual(len(errs.splitlines()), 1)
# self.assertRegex(errs,
# r'deprecated.*\bCOMPATFOOBAR\b.*\bTEST_QUX\b')
def test_boolean(self):
self._config_files['user'] = "TEST_BOOLEAN=yes"

View File

@ -1,54 +0,0 @@
# test_logger.py - Test ubuntutools.logger.Logger.
#
# Copyright (C) 2012, Stefano Rivera <stefanor@debian.org>
#
# 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.
from io import StringIO
import sys
from ubuntutools.logger import Logger
from ubuntutools.test import unittest
class LoggerTestCase(unittest.TestCase):
def setUp(self):
Logger.stdout = StringIO()
Logger.stderr = StringIO()
self._script_name = Logger.script_name
Logger.script_name = 'test'
self._verbose = Logger.verbose
def tearDown(self):
Logger.stdout = sys.stdout
Logger.stderr = sys.stderr
Logger.script_name = self._script_name
Logger.verbose = self._verbose
def testCommand(self):
Logger.command(('ls', 'a b'))
self.assertEqual(Logger.stdout.getvalue(), '')
Logger.set_verbosity(True)
Logger.command(('ls', 'a b'))
self.assertEqual(Logger.stdout.getvalue(), 'test: I: ls "a b"\n')
self.assertEqual(Logger.stderr.getvalue(), '')
def testNoArgs(self):
Logger.normal('hello %s')
self.assertEqual(Logger.stdout.getvalue(), 'test: hello %s\n')
self.assertEqual(Logger.stderr.getvalue(), '')
def testArgs(self):
Logger.normal('hello %s', 'world')
self.assertEqual(Logger.stdout.getvalue(), 'test: hello world\n')
self.assertEqual(Logger.stderr.getvalue(), '')

View File

@ -18,10 +18,9 @@
import mock
import os
import sys
# import sys
from io import StringIO
from ubuntutools.logger import Logger
from ubuntutools.test import unittest
from ubuntutools.update_maintainer import update_maintainer
@ -236,18 +235,18 @@ class UpdateMaintainerTestCase(unittest.TestCase):
self.addCleanup(patcher.stop)
patcher.start()
self._files["rules"] = StringIO(_SIMPLE_RULES)
Logger.stdout = StringIO()
Logger.stderr = StringIO()
# Logger.stdout = StringIO()
# Logger.stderr = StringIO()
def tearDown(self):
self.assertEqual(Logger.stdout.getvalue(), '')
self.assertEqual(Logger.stderr.getvalue(), '')
# self.assertEqual(Logger.stdout.getvalue(), '')
# self.assertEqual(Logger.stderr.getvalue(), '')
self._files["changelog"] = None
self._files["control"] = None
self._files["control.in"] = None
self._files["rules"] = None
Logger.stdout = sys.stdout
Logger.stderr = sys.stderr
# Logger.stdout = sys.stdout
# Logger.stderr = sys.stderr
# pylint: enable=C0103
def test_debian_package(self):
@ -266,11 +265,11 @@ class UpdateMaintainerTestCase(unittest.TestCase):
self._files["control"] = StringIO(_AXIS2C_CONTROL)
update_maintainer(self._directory)
self.assertEqual(self._files["control"].getvalue(), _AXIS2C_UPDATED)
warnings = Logger.stderr.getvalue().strip()
Logger.stderr = StringIO()
self.assertEqual(len(warnings.splitlines()), 1)
self.assertRegex(warnings, "Warning: Overwriting original maintainer: "
"Soren Hansen <soren@ubuntu.com>")
# warnings = Logger.stderr.getvalue().strip()
# Logger.stderr = StringIO()
# self.assertEqual(len(warnings.splitlines()), 1)
# self.assertRegex(warnings, "Warning: Overwriting original maintainer: "
# "Soren Hansen <soren@ubuntu.com>")
def test_update_maintainer(self):
"""Test: Update Maintainer field."""

View File

@ -20,7 +20,9 @@ import os
import re
import debian.changelog
from ubuntutools.logger import Logger
import logging
Logger = logging.getLogger(__name__)
# Prior May 2009 these Maintainers were used:
_PREVIOUS_UBUNTU_MAINTAINER = (
@ -176,7 +178,7 @@ def update_maintainer(debian_directory, verbose=False):
return
if control.get_original_maintainer() is not None:
Logger.warn("Overwriting original maintainer: %s",
Logger.warning("Overwriting original maintainer: %s",
control.get_original_maintainer())
if verbose: