mirror of
https://git.launchpad.net/ubuntu-dev-tools
synced 2025-03-13 08:01:09 +00:00
Merge
This commit is contained in:
commit
0e291144a4
3
buildd
3
buildd
@ -31,8 +31,7 @@ from optparse import OptionParser
|
||||
from urllib import urlencode
|
||||
|
||||
# ubuntu-dev-tools modules.
|
||||
sys.path.append("/usr/share/ubuntu-dev-tools/")
|
||||
import common
|
||||
from ubuntutools import common
|
||||
|
||||
# Usage.
|
||||
usage = "%prog <srcpackage> <release> <operation>\n\n"
|
||||
|
79
debian/changelog
vendored
79
debian/changelog
vendored
@ -1,4 +1,64 @@
|
||||
ubuntu-dev-tools (0.52) UNRELEASED; urgency=low
|
||||
ubuntu-dev-tools (0.58) UNRELEASED; urgency=low
|
||||
|
||||
* Changes go here.
|
||||
|
||||
-- Jonathan Davies <jpds@ubuntu.com> Sat, 17 Jan 2009 21:04:55 +0000
|
||||
|
||||
ubuntu-dev-tools (0.57) jaunty; urgency=low
|
||||
|
||||
* requestsync: Skip existing bug check if no credentials are
|
||||
found (LP: #318120).
|
||||
|
||||
-- Jonathan Davies <jpds@ubuntu.com> Sat, 17 Jan 2009 22:02:39 +0000
|
||||
|
||||
ubuntu-dev-tools (0.56) jaunty; urgency=low
|
||||
|
||||
* manage-credentials: Tighted security by making credentials files and
|
||||
folder world unreadable.
|
||||
* common.py: Improved no credentials found error message to show which
|
||||
consumer token is needed.
|
||||
* requestsync: Catch credentials error to hide traceback.
|
||||
* Moved common.py to ubuntutools/ subdirectory to avoid possible conflicts
|
||||
in Python packaging and fixed all imports as necessary.
|
||||
* debian/ubuntu-dev-tools.install: Removed common.py entry.
|
||||
|
||||
-- Jonathan Davies <jpds@ubuntu.com> Sat, 17 Jan 2009 11:32:33 +0000
|
||||
|
||||
ubuntu-dev-tools (0.55) jaunty; urgency=low
|
||||
|
||||
* manage-credentials: Use common.py's mkdir function to create as many
|
||||
subdirectories as necessary for the credentials directory (LP: #317317).
|
||||
|
||||
-- Jonathan Davies <jpds@ubuntu.com> Thu, 15 Jan 2009 12:33:31 +0000
|
||||
|
||||
ubuntu-dev-tools (0.54) jaunty; urgency=low
|
||||
|
||||
* manage-credentials:
|
||||
- Save credentials to ~/.cache/lp_credentials/ by
|
||||
default.
|
||||
- Set service option default to edge.
|
||||
* doc/manage-credentials.1: Update as necessary for the above.
|
||||
* common.py:
|
||||
- When credentials are not found, ask user to see
|
||||
manage-credentials manpage.
|
||||
- Load all token files for the consumer specified in the above
|
||||
directory as necessary.
|
||||
|
||||
-- Jonathan Davies <jpds@ubuntu.com> Wed, 14 Jan 2009 19:39:35 +0000
|
||||
|
||||
ubuntu-dev-tools (0.53) jaunty; urgency=low
|
||||
|
||||
[ Siegfried-Angel Gevatter Pujals ]
|
||||
* debian/copyright:
|
||||
- Add information about manage-credentials.
|
||||
|
||||
[ Daniel Holbach ]
|
||||
* debian/control: replace 'sb-release' with lsb-release, make package
|
||||
installable again.
|
||||
|
||||
-- Daniel Holbach <daniel.holbach@ubuntu.com> Wed, 14 Jan 2009 16:27:34 +0100
|
||||
|
||||
ubuntu-dev-tools (0.52) jaunty; urgency=low
|
||||
|
||||
[ Siegfried-Angel Gevatter Pujals ]
|
||||
* pbuilder-dist.new:
|
||||
@ -32,8 +92,23 @@ ubuntu-dev-tools (0.52) UNRELEASED; urgency=low
|
||||
'status'.
|
||||
* requestsync: If package is new, check the Ubuntu Archive team's bug list
|
||||
for possible duplicate requests.
|
||||
* doc/manage-credentials.1: Written up.
|
||||
* doc/requestsync.1: Changed documentation to launchpadlib related-stuff.
|
||||
|
||||
-- Siegfried-Angel Gevatter Pujals <rainct@ubuntu.com> Sat, 10 Jan 2009 14:35:14 +0100
|
||||
[ Luca Falavigna ]
|
||||
* requestsync:
|
||||
- Catch AssertionError exception if rmadison returns with an error.
|
||||
|
||||
[ Markus Korn ]
|
||||
* Added manage-credentials, a tool to create (and manage) credentials
|
||||
which are used to access launchpad via the API.
|
||||
* Ported: hugdaylist, massfile, grab-attachment and requestsync to
|
||||
launchpadlib.
|
||||
* Other misc. fixes and tweaks.
|
||||
* Install common.py to correct location with py_modules and remove
|
||||
hardcoded path from files.
|
||||
|
||||
-- Jonathan Davies <jpds@ubuntu.com> Wed, 14 Jan 2009 13:21:35 +0000
|
||||
|
||||
ubuntu-dev-tools (0.51) jaunty; urgency=low
|
||||
|
||||
|
4
debian/control
vendored
4
debian/control
vendored
@ -14,8 +14,8 @@ Package: ubuntu-dev-tools
|
||||
Architecture: all
|
||||
Section: devel
|
||||
Depends: ${python:Depends}, binutils, devscripts, sudo, python-debian,
|
||||
python-launchpad-bugs (>= 0.2.25), dctrl-tools, lsb-release, diffstat,
|
||||
dpkg-dev, ${misc:Depends}
|
||||
python-launchpad-bugs (>= 0.2.25), python-launchpadlib, dctrl-tools,
|
||||
lsb-release, diffstat, dpkg-dev, ${misc:Depends}
|
||||
Recommends: bzr, pbuilder | cowdancer | sbuild, reportbug (>= 3.39ubuntu1),
|
||||
ca-certificates, genisoimage, perl-modules, libwww-perl
|
||||
Conflicts: devscripts (<< 2.10.7ubuntu5)
|
||||
|
18
debian/copyright
vendored
18
debian/copyright
vendored
@ -13,6 +13,7 @@ Upstream Authors:
|
||||
Jordan Mantha <mantha@ubuntu.com>
|
||||
Kees Cook <kees@ubuntu.com>
|
||||
Luke Yelavich <themuso@ubuntu.com>
|
||||
Markus Korn <thekorn@gmx.de>
|
||||
Martin Pitt <martin.pitt@ubuntu.com>
|
||||
Matt Zimmerman <mdz@ubuntu.com>
|
||||
Michael Bienia <geser@ubuntu.com>
|
||||
@ -30,14 +31,15 @@ Copyright:
|
||||
(C) 2006-2007, Albin Tonnerre <lut1n.tne@gmail.com>
|
||||
(C) 2006-2007, Daniel Holbach <daniel.holbach@ubuntu.com>
|
||||
(C) 2006-2007, Luke Yelavich <themuso@ubuntu.com>
|
||||
(C) 2009, Markus Korn <thekorn@gmx.de>
|
||||
(C) 2007, Martin Pitt <martin.pitt@ubuntu.com>
|
||||
(C) 2006-2007, Michael Bienia <geser@ubuntu.com>
|
||||
(C) 2006-2008, Kees Cook <kees@ubuntu.com>
|
||||
(C) 2006-2007, Pete Savage <petesavage@ubuntu.com>
|
||||
(C) 2007-2008, Siegfried-A. Gevatter <rainct@ubuntu.com>
|
||||
(C) 2007-2009, Siegfried-A. Gevatter <rainct@ubuntu.com>
|
||||
(C) 2007, Terence Simpson <stdin@stdin.me.uk>
|
||||
(C) 2008, Iain Lane <iain@orangesquash.org.uk>
|
||||
(C) 2008, Jonathan Davies <jpds@ubuntu.com>
|
||||
(C) 2008-2009, Jonathan Davies <jpds@ubuntu.com>
|
||||
(C) 2008, Nathan handler <nhandler@ubuntu.com>
|
||||
|
||||
Licenses:
|
||||
@ -58,9 +60,10 @@ licensed under the GNU General Public License, version 2:
|
||||
On Debian and Ubuntu systems, the complete text of the GNU General Public
|
||||
License v2 can be found in `/usr/share/common-licenses/GPL-2'.
|
||||
|
||||
dch-repeat, get-branches, get-build-deps, massfile, mk-sbuild-lv, ppaput,
|
||||
pull-debian-debdiff, pull-debian-source, pull-lp-source, suspicious-source and what-patch are
|
||||
licensed under the GNU General Public License, version 3:
|
||||
dch-repeat, get-branches, get-build-deps, manage-credentials, massfile,
|
||||
mk-sbuild-lv, ppaput, pull-debian-debdiff, pull-debian-source, pull-lp-source,
|
||||
suspicious-source and what-patch are licensed under the GNU General Public
|
||||
License, version 3:
|
||||
|
||||
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
|
||||
@ -76,5 +79,6 @@ License v3 can be found in `/usr/share/common-licenses/GPL-3'.
|
||||
|
||||
The following of the scripts can be used, at your option, regarding any
|
||||
later version of the previously specified license: 404main, dch-repeat, dgetlp,
|
||||
get-build-deps, mk-sbuild-lv, pull-debian-debdiff, pull-debian-source, pull-lp-source,
|
||||
reverse-build-depends, suspicious-source, what-patch.
|
||||
get-build-deps, manage-credentials, mk-sbuild-lv, pull-debian-debdiff,
|
||||
pull-debian-source, pull-lp-source, reverse-build-depends, suspicious-source,
|
||||
what-patch.
|
||||
|
1
debian/ubuntu-dev-tools.install
vendored
1
debian/ubuntu-dev-tools.install
vendored
@ -1,2 +1 @@
|
||||
bash_completion/* etc/bash_completion.d/
|
||||
common.py usr/share/ubuntu-dev-tools/
|
||||
|
76
doc/manage-credentials.1
Normal file
76
doc/manage-credentials.1
Normal file
@ -0,0 +1,76 @@
|
||||
.TH MANAGE-CREDENTIALS "1" "13 January 2009" "ubuntu-dev-tools"
|
||||
.SH NAME
|
||||
manage-credentials \- a tool to create (and manage) credentials which
|
||||
are used to access launchpad via the API.
|
||||
.SH SYNOPSIS
|
||||
.B manage-credentials create -c <consumer> [--email <email> --password <password>] [--service <staging|edge>]
|
||||
.br
|
||||
.B manage-credentials \-h
|
||||
.SH DESCRIPTION
|
||||
\fBmanage-credentials\fR is a tool to create (and manage) credentials which
|
||||
are used to access Launchpad via the API.
|
||||
|
||||
.PP
|
||||
Currently this tool can be used
|
||||
to create a token with or without using the web UI. In the future, once
|
||||
related methods are available through the API, this tool can also be used
|
||||
to manage tokens in launchpad and on the users local machine.
|
||||
|
||||
.SH OPTIONS
|
||||
Listed below are the command line options for requestsync:
|
||||
.TP
|
||||
.B \-h
|
||||
Display a help message and exit.
|
||||
.TP
|
||||
.B \-c \-\-consumer
|
||||
.TP
|
||||
.B \-e \-\-email <email>
|
||||
Your email address as registered on Launchpad.
|
||||
.TP
|
||||
.B \-p \-\-password <password>
|
||||
Your Launchpad password.
|
||||
.TP
|
||||
.B \-s \-\-service <edge|staging>
|
||||
If we should use the edge or staging root of the Launchpad API.
|
||||
.TP
|
||||
.B \-\-cache
|
||||
Where to store the cache.
|
||||
.TP
|
||||
.B \-o
|
||||
Which file we should save the credentials to. By default
|
||||
\fBmanage-credentials\fR writes the credentials tokens to the
|
||||
~/.cache/lp_credentials/ directory.
|
||||
.TP
|
||||
.B \-l \-\-level <number>
|
||||
A number representing the access-level you wish to give to the new
|
||||
Launchpad token. 0 is unauthorized, 1 is read public data, 2; write public data,
|
||||
3; read private data and 4; write private data.
|
||||
|
||||
.SH EXAMPLE USAGE
|
||||
There are currently two ways of using \fBmanage-credentials\fR to get
|
||||
Launchpad tokens.
|
||||
.TP
|
||||
1) manage-credentials create -c CONSUMER --level 2
|
||||
|
||||
.TP
|
||||
This way shall open your webbrowser with a Launchpad login page.
|
||||
|
||||
.TP
|
||||
2) manage-credentials create -c CONSUMER --level 2 --password BOO --email me@example.com
|
||||
|
||||
.TP
|
||||
This is a hack, but it works and does not require a webbrowser .
|
||||
|
||||
.TP
|
||||
If you intend to use manage-credentials for Ubuntu development (such as
|
||||
the ubuntu-dev-tools package). Please by sure to run the following:
|
||||
|
||||
.TP
|
||||
manage-credentials create -c ubuntu-dev-tools -l 2
|
||||
|
||||
.SH AUTHOR
|
||||
.B manage-credentials
|
||||
was written by Markus Korn <thekorn@gmx.de> and this manual page was written by
|
||||
Jonathan Davies <jpds@ubuntu.com>.
|
||||
.PP
|
||||
Both are released under the GNU General Public License, version 3.
|
@ -15,10 +15,10 @@ The changelog entry is then downloaded from packages.debian.org.
|
||||
If the sync request is being filed per email (default), a prompt for your
|
||||
GPG passphrase follows so that it can sign the mail and send it off to
|
||||
Launchpad.
|
||||
Alternatively a sync request can be filed directly using the launchpadbugs
|
||||
python module (option \fB\-\-lp\fR).
|
||||
Alternatively a sync request can be filed directly using the launchpadlib
|
||||
Python module (option \fB\-\-lp\fR).
|
||||
\fBrequestsync\fR falls back to mail the sync request if submitting using
|
||||
the launchpadbugs module fails.
|
||||
the launchpadlib module fails.
|
||||
|
||||
.PP
|
||||
\fBrequestsync\fR checks if you have the permissions to request the sync from
|
||||
@ -29,10 +29,8 @@ If you are not a member of the appropriate team, the script will subscribe
|
||||
the necessary team with approval rights to the bug report for you.
|
||||
|
||||
.PP
|
||||
\fBrequestsync\fR uses a cookie file stored at \fI~/.lpcookie.txt\fR to
|
||||
authenticate with Launchpad.
|
||||
This cookie is created on run from the Mozilla Firefox cookie file at
|
||||
\fI~/.mozilla/*/*/cookies.sqlite\fR.
|
||||
\fBrequestsync\fR uses launchpadlib authentication to file its requests. Please
|
||||
see manage-credentials(1) for more information.
|
||||
|
||||
.SH OPTIONS
|
||||
Listed below are the command line options for requestsync:
|
||||
@ -55,7 +53,7 @@ configuration (for example: \fI$HOME/.bashrc\fR).
|
||||
This is only used if the sync request is mailed to Launchpad.
|
||||
.TP
|
||||
.B \-\-lp
|
||||
Use the launchpadbugs python module (packaged as python\-launchpad\-bugs) to
|
||||
Use the launchpadlib Python module (packaged as python\-launchpadlib) to
|
||||
file the sync request in Launchpad.
|
||||
.TP
|
||||
.B \-s
|
||||
|
@ -20,8 +20,7 @@
|
||||
|
||||
import os
|
||||
import sys
|
||||
import urllib
|
||||
import launchpadbugs.connector as Connector
|
||||
from ubuntutools.common import get_launchpad
|
||||
|
||||
USAGE = "grab-attachments <bug numbers>"
|
||||
|
||||
@ -33,17 +32,21 @@ def main():
|
||||
if sys.argv[1] in ["--help", "-h"]:
|
||||
print USAGE
|
||||
sys.exit(0)
|
||||
Bug = Connector.ConnectBug(method="Text")
|
||||
launchpad = get_launchpad("ubuntu-dev-tools")
|
||||
for arg in sys.argv[1:]:
|
||||
try:
|
||||
number = int(arg)
|
||||
except:
|
||||
print >> sys.stderr, "'%s' is not a valid bug number." % arg
|
||||
sys.exit(1)
|
||||
b = Bug(number)
|
||||
b = launchpad.bugs[number]
|
||||
for a in b.attachments:
|
||||
filename = os.path.join(os.getcwd(), a.url.split("/")[-1])
|
||||
urllib.urlretrieve(a.url, filename)
|
||||
f = a.data.open()
|
||||
filename = os.path.join(os.getcwd(), f.filename)
|
||||
local_file = open(filename, "w")
|
||||
local_file.write(f.read())
|
||||
f.close()
|
||||
local_file.close()
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
|
54
hugdaylist
54
hugdaylist
@ -35,14 +35,7 @@ import string
|
||||
import sys
|
||||
from optparse import OptionParser
|
||||
|
||||
try:
|
||||
import launchpadbugs.connector as Connector
|
||||
BugList = Connector.ConnectBugList()
|
||||
Bug = Connector.ConnectBug(method="Text")
|
||||
except ImportError:
|
||||
print >> sys.stderr, \
|
||||
"python-launchpad-bugs (>= 0.2.25) needs to be installed to use hugdaylist."
|
||||
sys.exit(1)
|
||||
from ubuntutools.common import get_launchpad, translate_web_api, translate_api_web
|
||||
|
||||
def check_args():
|
||||
howmany = -1
|
||||
@ -74,27 +67,41 @@ def check_args():
|
||||
|
||||
return (howmany, url)
|
||||
|
||||
def filter_unsolved(b):
|
||||
bug = Bug(int(b))
|
||||
def filter_unsolved(task):
|
||||
# TODO: don't use this filter here, only check status and assignee of
|
||||
# the given task
|
||||
# Filter out special types of bugs:
|
||||
# - https://wiki.ubuntu.com/Bugs/HowToTriage#Special%20types%20of%20bugs
|
||||
return filter(lambda a: a.status != 'Fix Committed' and \
|
||||
(a.assignee in ['motu','desktop-bugs'] or \
|
||||
not a.assignee), bug.infotable) and \
|
||||
'ubuntu-main-sponsors' not in [str(s) for s in bug.subscribers] and \
|
||||
'ubuntu-universe-sponsors' not in [str(s) for s in bug.subscribers] and \
|
||||
'ubuntu-archive' not in [str(s) for s in bug.subscribers]
|
||||
subscriptions = set(s.person.name for s in task.bug.subscriptions) #this is expensive, parse name out of self_link instead?
|
||||
if (task.status != "Fix Committed" and
|
||||
(not task.assignee or task.assignee.name in ['motu','desktop-bugs']) and
|
||||
'ubuntu-main-sponsors' not in subscriptions and
|
||||
'ubuntu-universe-sponsors' not in subscriptions and
|
||||
'ubuntu-archive' not in subscriptions):
|
||||
return True
|
||||
return False
|
||||
|
||||
def main():
|
||||
(howmany, url) = check_args()
|
||||
|
||||
try:
|
||||
bl = BugList(url)
|
||||
except:
|
||||
print >> sys.stderr, "The URL at '%s' does not appear to have a bug " \
|
||||
"list." % url
|
||||
if len(url.split("?", 1)) == 2:
|
||||
# search options not supported, because there is no mapping web ui options <-> API options
|
||||
print >> sys.stderr, "Options in url are not supported, url: %s" %url
|
||||
sys.exit(1)
|
||||
|
||||
launchpad = get_launchpad("ubuntu-dev-tools")
|
||||
api_url = translate_web_api(url, launchpad)
|
||||
try:
|
||||
product = launchpad.load(api_url)
|
||||
except Exception, e:
|
||||
x = getattr(e, "response", {})
|
||||
if response.get("status", None) == "404":
|
||||
print >> sys.stderr, "The URL at '%s' does not appear to be a valid url to a product" %url
|
||||
sys.exit(1)
|
||||
else:
|
||||
raise
|
||||
|
||||
bl = product.searchTasks()
|
||||
|
||||
l = filter(filter_unsolved, bl)
|
||||
|
||||
if not l:
|
||||
@ -112,8 +119,9 @@ def main():
|
||||
|| Bug || Subject || Triager ||"""
|
||||
|
||||
for i in list(l)[:howmany]:
|
||||
bug = i.bug
|
||||
print '||<rowbgcolor="#FFEBBB"> [%s %s] || %s || ||' % \
|
||||
(i.url, i.bugnumber, i.summary)
|
||||
(translate_api_web(bug.self_link), bug.id, bug.title)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
137
manage-credentials
Executable file
137
manage-credentials
Executable file
@ -0,0 +1,137 @@
|
||||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Copyright (C) 2009 Markus Korn <thekorn@gmx.de>
|
||||
#
|
||||
# ##################################################################
|
||||
#
|
||||
# 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 os
|
||||
import sys
|
||||
from optparse import OptionParser, make_option
|
||||
from ubuntutools.common import Credentials, Launchpad, translate_service
|
||||
from ubuntutools.common import LEVEL, translate_api_web, approve_application
|
||||
from ubuntutools.common import mkdir
|
||||
|
||||
class CmdOptions(OptionParser):
|
||||
|
||||
USAGE = (
|
||||
"\t%prog create -c <consumer> [--email <email> --password <password>] [--service <staging|edge>]\n"
|
||||
)
|
||||
|
||||
OPTIONS = (
|
||||
make_option("-c", "--consumer", action="store", type="string",
|
||||
dest="consumer", default=None),
|
||||
make_option("-e", "--email", action="store", type="string",
|
||||
dest="email", default=None),
|
||||
make_option("-p", "--password", action="store", type="string",
|
||||
dest="password", default=None),
|
||||
make_option("-s", "--service", action="store", type="string",
|
||||
dest="service", default="edge"),
|
||||
make_option("--cache", action="store", type="string",
|
||||
dest="cache", default=None),
|
||||
make_option("-o", action="store", type="string",
|
||||
dest="output", default=None),
|
||||
make_option("-l", "--level", action="store", type="int",
|
||||
dest="level", default=0,
|
||||
help="integer representing the access-level (default: 0), mapping: %s" %LEVEL),
|
||||
)
|
||||
|
||||
TOOLS = {
|
||||
"create": ( ("consumer",),
|
||||
("email", "password", "service", "cache", "output",
|
||||
"level")),
|
||||
"list": (tuple(), ("service", )),
|
||||
}
|
||||
|
||||
def __init__(self):
|
||||
OptionParser.__init__(self, option_list=self.OPTIONS)
|
||||
self.set_usage(self.USAGE)
|
||||
|
||||
def parse_args(self, args=None, values=None):
|
||||
options, args = OptionParser.parse_args(self, args, values)
|
||||
given_options = set(i for i, k in self.defaults.iteritems() if not getattr(options, i) == k)
|
||||
|
||||
if not args:
|
||||
self.error("Please define a sub-tool you would like to use")
|
||||
if not len(args) == 1:
|
||||
self.error("Only one sub-tool allowed")
|
||||
else:
|
||||
tool = args.pop()
|
||||
if not tool in self.TOOLS:
|
||||
self.error("Unknown tool '%s'" %tool)
|
||||
needed_options = set(self.TOOLS[tool][0]) - given_options
|
||||
if needed_options:
|
||||
self.error("Please define the following options: %s" %", ".join(needed_options))
|
||||
optional_options = given_options - set(sum(self.TOOLS[tool], ()))
|
||||
if optional_options:
|
||||
self.error("The following options are not allowed for this tool: %s" %", ".join(optional_options))
|
||||
options.service = translate_service(options.service)
|
||||
if options.level in LEVEL:
|
||||
options.level = LEVEL[options.level]
|
||||
elif options.level.upper() in LEVEL.values():
|
||||
options.level = options.level.upper()
|
||||
else:
|
||||
self.error("Unknown access-level '%s', level must be in %s" %(options.level, self.LEVEL))
|
||||
return tool, options
|
||||
|
||||
def create_credentials(options):
|
||||
if options.password and options.email:
|
||||
# use hack
|
||||
credentials = Credentials(options.consumer)
|
||||
credentials = approve_application(credentials, options.email,
|
||||
options.password, options.level,
|
||||
translate_api_web(options.service), None)
|
||||
else:
|
||||
launchpad = Launchpad.get_token_and_login(options.consumer,
|
||||
options.service, options.cache)
|
||||
credentials = launchpad.credentials
|
||||
|
||||
if options.output:
|
||||
filepath = options.output
|
||||
else:
|
||||
credentialsDir = os.path.expanduser("~/.cache/lp_credentials")
|
||||
if not os.path.isdir(credentialsDir):
|
||||
mkdir(credentialsDir)
|
||||
os.chmod(credentialsDir, 0700)
|
||||
filepath = os.path.expanduser("%s/%s-%s.txt" % \
|
||||
(credentialsDir, options.consumer, str(options.level).lower()))
|
||||
|
||||
f = open(filepath, "w")
|
||||
# Make credentials file non-world readable.
|
||||
os.chmod(filepath, 0600)
|
||||
credentials.save(f)
|
||||
f.close()
|
||||
|
||||
print "Credentials sucessfully written to %s." % filepath
|
||||
|
||||
return
|
||||
|
||||
def list_tokens(options):
|
||||
print "Not implemented yet."
|
||||
print "To get a list of your tokens, please visit %speople/+me/+oauth-tokens" %translate_api_web(options.service)
|
||||
return 1
|
||||
|
||||
def main():
|
||||
cmdoptions = CmdOptions()
|
||||
tool, options = cmdoptions.parse_args()
|
||||
if tool == "create":
|
||||
return create_credentials(options)
|
||||
elif tool == "list":
|
||||
return list_tokens(options)
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(main())
|
78
massfile
78
massfile
@ -27,12 +27,7 @@ import email
|
||||
import subprocess
|
||||
import glob
|
||||
|
||||
import launchpadbugs.connector as Connector
|
||||
|
||||
sys.path.append('/usr/share/ubuntu-dev-tools/')
|
||||
import common
|
||||
|
||||
cookie = common.prepareLaunchpadCookie()
|
||||
from ubuntutools.common import get_launchpad, translate_api_web, translate_web_api
|
||||
|
||||
def read_config():
|
||||
instructions_file = open("instructions")
|
||||
@ -57,10 +52,6 @@ def read_list():
|
||||
listfile.close()
|
||||
return pack_list
|
||||
|
||||
def file_bug():
|
||||
Bug = Connector.ConnectBug()
|
||||
Bug.authentication = cookie
|
||||
|
||||
def check_configfiles():
|
||||
result = True
|
||||
|
||||
@ -87,43 +78,62 @@ def check_configfiles():
|
||||
|
||||
|
||||
def file_bug(config):
|
||||
Bug = Connector.ConnectBug()
|
||||
|
||||
Bug.authentication = cookie
|
||||
launchpad = get_launchpad("ubuntu-dev-tools")
|
||||
|
||||
try:
|
||||
summary = config["subject"].replace("$pack", config["sourcepackage"])
|
||||
description = config["text"].replace("$pack", config["sourcepackage"])
|
||||
|
||||
bug = Bug.New(product={"name": config["sourcepackage"],
|
||||
"target": "ubuntu"},
|
||||
summary=summary,
|
||||
description=description)
|
||||
print "Successfully filed bug %s: https://launchpad.net/bugs/%s" % \
|
||||
(bug.bugnumber, bug.bugnumber)
|
||||
for sub in config["subscribers"].split(","):
|
||||
if sub.strip("\n").strip():
|
||||
bug.subscribers.add(sub.strip("\n").strip())
|
||||
for tag in config["tags"].split(","):
|
||||
if tag.strip("\n").strip():
|
||||
bug.tags.append(tag.strip("\n").strip())
|
||||
bug.assignee = config["assignee"]
|
||||
|
||||
product_url = "%subuntu/+source/%s" %(launchpad._root_uri, config["sourcepackage"])
|
||||
tags = filter(None, map(lambda t: t.strip("\n").strip(), config["tags"].split(",")))
|
||||
bug = launchpad.bugs.createBug(description=description, title=summary,
|
||||
target=product_url, tags=tags)
|
||||
|
||||
print "Successfully filed bug %i: %s" %(bug.id, translate_api_web(bug.self_link))
|
||||
|
||||
subscribers = filter(None, map(lambda t: t.strip("\n").strip(), config["subscribers"].split(",")))
|
||||
for sub in subscribers:
|
||||
subscribe_url = "%s~%s" %(launchpad._root_uri, sub)
|
||||
bug.subscribe(person=subscribe_url)
|
||||
|
||||
#newly created bugreports have one task
|
||||
task = bug.bug_tasks[0]
|
||||
|
||||
if config["status"]:
|
||||
bug.status = config["status"].capitalize()
|
||||
status = config["status"].capitalize()
|
||||
else:
|
||||
bug.status = "Confirmed"
|
||||
bug.commit()
|
||||
status = "Confirmed"
|
||||
task.transitionToStatus(status=status)
|
||||
|
||||
assignee = config["assignee"]
|
||||
if assignee:
|
||||
assignee_url = "%s~%s" %(launchpad._root_uri, assignee)
|
||||
bug.transitionToAssignee(assignee=assignee_url)
|
||||
except:
|
||||
"Bug for '%s' was not filed." % config["sourcepackage"]
|
||||
|
||||
def read_buglist(url):
|
||||
BugList = Connector.ConnectBugList()
|
||||
if not url:
|
||||
return set()
|
||||
|
||||
if len(url.split("?", 1)) == 2:
|
||||
# search options not supported, because there is no mapping web ui options <-> API options
|
||||
print >> sys.stderr, "Options in url are not supported, url: %s" %url
|
||||
sys.exit(1)
|
||||
|
||||
launchpad = get_launchpad("ubuntu-dev-tools")
|
||||
packages = set()
|
||||
|
||||
if url:
|
||||
buglist = BugList(url)
|
||||
for bug in buglist.bugs:
|
||||
packages.add(bug.sourcepackage)
|
||||
api_url = translate_web_api(url, launchpad)
|
||||
# workaround LP #303414
|
||||
# if this is fixed it should simply be: buglist = launchpad.load(api_url)
|
||||
api_url = api_url.split("?", 1)[0]
|
||||
project = launchpad.load(api_url)
|
||||
buglist = project.searchTasks()
|
||||
|
||||
for bug in buglist:
|
||||
packages.add(bug.bug_target_name)
|
||||
|
||||
return packages
|
||||
|
||||
|
@ -33,8 +33,7 @@ import urllib2
|
||||
from optparse import OptionParser
|
||||
|
||||
# Ubuntu-dev-tools modules.
|
||||
sys.path.append("/usr/share/ubuntu-dev-tools")
|
||||
import common
|
||||
from ubuntutools import common
|
||||
|
||||
class BackportFromLP:
|
||||
|
||||
|
117
requestsync
117
requestsync
@ -9,6 +9,7 @@
|
||||
# Daniel Hahler <ubuntu@thequod.de>
|
||||
# Iain Lane <iain@orangesquash.org.uk>
|
||||
# Jonathan Davies <jpds@ubuntu.com>
|
||||
# Markus Korn <thekorn@gmx.de> (python-launchpadlib support)
|
||||
#
|
||||
# ##################################################################
|
||||
#
|
||||
@ -34,9 +35,7 @@ from debian_bundle.changelog import Version
|
||||
from optparse import OptionParser
|
||||
from time import sleep
|
||||
|
||||
# Use functions from ubuntu-dev-tools to create Launchpad cookie file.
|
||||
sys.path.append('/usr/share/ubuntu-dev-tools/')
|
||||
import common
|
||||
from ubuntutools import common
|
||||
|
||||
launchpad_cookiefile = common.prepareLaunchpadCookie()
|
||||
|
||||
@ -54,6 +53,11 @@ def checkNeedsSponsorship(component):
|
||||
The prepareLaunchpadCookie function above shall ensure that a cookie
|
||||
file exists first.
|
||||
"""
|
||||
# TODO: use launchpadlib here
|
||||
# Once LP: #313233 has been fixed this can be implemented by either:
|
||||
# >>> me = launchpad.me
|
||||
# >>> me.inTeam(<TEAM>) #or
|
||||
# >>> me in <TEAM>
|
||||
urlopener = common.setupLaunchpadUrlOpener(launchpad_cookiefile)
|
||||
|
||||
# Check where the package is and assign the appropriate variables.
|
||||
@ -85,52 +89,47 @@ def checkNeedsSponsorship(component):
|
||||
# Is a team member, no sponsorship required.
|
||||
return False
|
||||
|
||||
def checkExistingReports(package, isNewPackage):
|
||||
def checkExistingReports(package):
|
||||
""" Check existing bug reports on Launchpad for a possible sync request.
|
||||
|
||||
If found ask for confirmation on filing a request.
|
||||
"""
|
||||
# Determine if the package is new or not.
|
||||
if isNewPackage:
|
||||
# Package not in Ubuntu, check Ubuntu Archive Team's bug page for
|
||||
# possible duplicate reports.
|
||||
bugListUrl = "https://bugs.launchpad.net/~ubuntu-archive"
|
||||
else:
|
||||
# Package in Ubuntu, check the package's bug list for duplicate reports.
|
||||
bugListUrl = "https://bugs.launchpad.net/ubuntu/+source/%s" % package
|
||||
|
||||
launchpad = None
|
||||
|
||||
try:
|
||||
import launchpadbugs.connector as Connector
|
||||
except:
|
||||
# Failed to import launchpadbugs - skip check.
|
||||
print >> sys.stderr, "Unable to import launchpadbugs. Is " \
|
||||
"python-launchpad-bugs installed?"
|
||||
launchpad = common.get_launchpad("ubuntu-dev-tools")
|
||||
except ImportError:
|
||||
print >> sys.stderr, 'Importing launchpadlib failed. Is ' \
|
||||
'python-launchpadlib installed?'
|
||||
except IOError, msg:
|
||||
# No credentials found.
|
||||
print msg
|
||||
|
||||
# Failed to get Launchpad credentials.
|
||||
if launchpad is None:
|
||||
print >> sys.stderr, "Skipping existing report check, you should "\
|
||||
"manually check at:"
|
||||
print "-", bugListUrl
|
||||
return
|
||||
"manually see if there are any at:"
|
||||
print "- https://bugs.launchpad.net/ubuntu/+source/%s" % package
|
||||
print ""
|
||||
return False
|
||||
|
||||
# Connect to the bug list.
|
||||
bugList = Connector.ConnectBugList()
|
||||
|
||||
# Fetch data from Launchpad.
|
||||
pkgBugList = bugList(bugListUrl)
|
||||
|
||||
if len(pkgBugList) == 0:
|
||||
return # No bugs found.
|
||||
# Fetch the package's bug list from Launchpad.
|
||||
pkg = launchpad.distributions["ubuntu"].getSourcePackage(name=package)
|
||||
pkgBugList = pkg.searchTasks()
|
||||
|
||||
# Search bug list for other sync requests.
|
||||
matchingBugs = [bug for bug in pkgBugList if "Please sync %s" %
|
||||
package in bug.summary]
|
||||
package in bug.title]
|
||||
|
||||
if len(matchingBugs) == 0:
|
||||
return # No sync bugs found.
|
||||
|
||||
print "The following bugs could possibly be duplicate sync request(s) on Launchpad:"
|
||||
print "The following bugs could be possible duplicate sync bug(s) on Launchpad:"
|
||||
|
||||
for bug in matchingBugs:
|
||||
print " *", bug.summary
|
||||
print " -", bug.url
|
||||
print " *", bug.title
|
||||
print " -", common.translate_api_web(bug.self_link)
|
||||
|
||||
print "Please check the above URLs to verify this before filing a " \
|
||||
"possible duplicate report."
|
||||
@ -317,7 +316,7 @@ def mail_bug(source_package, subscribe, status, bugtitle, bugtext, keyid = None)
|
||||
(mailserver, mailserver_port, s[1], s[0])
|
||||
print "The port %s may be firewalled. Please try using requestsync with" \
|
||||
% mailserver_port
|
||||
print "the '--lp' flag to file a sync request with the launchpadbugs " \
|
||||
print "the '--lp' flag to file a sync request with the launchpadlib " \
|
||||
"module."
|
||||
return False
|
||||
|
||||
@ -343,23 +342,26 @@ def mail_bug(source_package, subscribe, status, bugtitle, bugtext, keyid = None)
|
||||
return True
|
||||
|
||||
def post_bug(source_package, subscribe, status, bugtitle, bugtext):
|
||||
'''Use python-launchpad-bugs to submit the sync request.
|
||||
'''Use python-launchpadlib to submit the sync request.
|
||||
Return True if successfully posted, otherwise False.'''
|
||||
|
||||
import glob, os.path
|
||||
|
||||
try:
|
||||
import launchpadbugs.connector
|
||||
from launchpadbugs.lpconstants import HTTPCONNECTION
|
||||
launchpad = common.get_launchpad("ubuntu-dev-tools")
|
||||
except ImportError:
|
||||
print >> sys.stderr, 'Importing launchpadbugs failed. Is python-launchpad-bugs installed?'
|
||||
print >> sys.stderr, 'Importing launchpadlib failed. Is python-launchpadlib installed?'
|
||||
return False
|
||||
except IOError, msg:
|
||||
# No credentials found.
|
||||
print msg
|
||||
sys.exit(1)
|
||||
|
||||
if source_package:
|
||||
product = {'name': source_package, 'target': 'ubuntu'}
|
||||
product_url = "%subuntu/+source/%s" %(launchpad._root_uri, source_package)
|
||||
else:
|
||||
# new source package
|
||||
product = {'name': 'ubuntu'}
|
||||
product_url = "%subuntu" %launchpad._root_uri
|
||||
|
||||
in_confirm_loop = True
|
||||
while in_confirm_loop:
|
||||
@ -379,32 +381,17 @@ def post_bug(source_package, subscribe, status, bugtitle, bugtext):
|
||||
print "Invalid answer."
|
||||
|
||||
# Create bug
|
||||
Bug = launchpadbugs.connector.ConnectBug()
|
||||
# Force the usage of stable Launchpad.
|
||||
Bug.set_connection_mode(HTTPCONNECTION.MODE.STABLE)
|
||||
bug = launchpad.bugs.createBug(description=bugtext, title=bugtitle, target=product_url)
|
||||
|
||||
# Use our cookie file for authentication.
|
||||
Bug.authentication = launchpad_cookiefile
|
||||
print "Using LP cookie at: %s for authentication." % launchpad_cookiefile
|
||||
#newly created bugreports have one task
|
||||
task = bug.bug_tasks[0]
|
||||
task.transitionToImportance(importance='Wishlist')
|
||||
task.transitionToStatus(status=status)
|
||||
|
||||
# Submit bug report.
|
||||
bug = Bug.New(product = product, summary = bugtitle, description = bugtext)
|
||||
sleep(2) # Wait in case of slow Launchpad.
|
||||
|
||||
try:
|
||||
bug.importance = 'Wishlist'
|
||||
except IOError, s:
|
||||
print "Warning: setting importance failed: %s" % s
|
||||
|
||||
bug.status = status
|
||||
bug.subscriptions.add(subscribe)
|
||||
sleep(1) # Wait.
|
||||
|
||||
bug.commit()
|
||||
sleep(1) # Wait.
|
||||
|
||||
print 'Sync request filed as bug #%i: https://launchpad.net/bugs/%i' % (bug.bugnumber, bug.bugnumber)
|
||||
subscribe_url = "%s~%s" %(launchpad._root_uri, subscribe)
|
||||
bug.subscribe(person=subscribe_url)
|
||||
|
||||
print 'Sync request filed as bug #%i: %s' % (bug.id, common.translate_api_web(bug.self_link))
|
||||
return True
|
||||
|
||||
def edit_report(subject, body, changes_required=False):
|
||||
@ -477,7 +464,7 @@ if __name__ == '__main__':
|
||||
help = "Whether package to sync is a new package in Ubuntu.")
|
||||
optParser.add_option("--lp", action = "store_true",
|
||||
dest = "lpbugs", default = False,
|
||||
help = "Specify whether to use the launchpadbugs module for filing " \
|
||||
help = "Specify whether to use the launchpadlib module for filing " \
|
||||
"report.")
|
||||
optParser.add_option("-s", action = "store_true",
|
||||
dest = "sponsor", default = False,
|
||||
@ -524,8 +511,8 @@ if __name__ == '__main__':
|
||||
# -s flag not specified - check if we do need sponsorship.
|
||||
if not sponsorship: sponsorship = checkNeedsSponsorship(component)
|
||||
|
||||
# Check for existing sync requests.
|
||||
checkExistingReports(srcpkg, newsource)
|
||||
# Check for existing package reports.
|
||||
if not newsource: checkExistingReports(srcpkg)
|
||||
|
||||
# Generate bug report.
|
||||
subscribe = 'ubuntu-archive'
|
||||
|
1
setup.py
1
setup.py
@ -24,6 +24,7 @@ setup(name='ubuntu-dev-tools',
|
||||
'get-build-deps',
|
||||
'grab-attachments',
|
||||
'hugdaylist',
|
||||
'manage-credentials',
|
||||
'massfile',
|
||||
'mk-sbuild-lv',
|
||||
'pbuilder-dist',
|
||||
|
@ -31,6 +31,16 @@ import re
|
||||
import subprocess
|
||||
import sys
|
||||
import urllib2
|
||||
import urlparse
|
||||
import urllib
|
||||
try:
|
||||
import httplib2
|
||||
from launchpadlib.credentials import Credentials
|
||||
from launchpadlib.launchpad import Launchpad, STAGING_SERVICE_ROOT, EDGE_SERVICE_ROOT
|
||||
from launchpadlib.errors import HTTPError
|
||||
except ImportError:
|
||||
Credentials = None
|
||||
Launchpad = None
|
||||
|
||||
# Clear https_proxy env var as it's not supported in urllib/urllib2; see
|
||||
# LP #122551
|
||||
@ -265,3 +275,120 @@ def packageComponent(package, release):
|
||||
component = rel.split('/')[1]
|
||||
|
||||
return component.strip()
|
||||
|
||||
|
||||
def find_credentials(consumer, files, level=None):
|
||||
""" search for credentials matching 'consumer' in path for given access level. """
|
||||
if Credentials is None:
|
||||
raise ImportError
|
||||
|
||||
for f in files:
|
||||
cred = Credentials()
|
||||
try:
|
||||
cred.load(open(f))
|
||||
except:
|
||||
continue
|
||||
if cred.consumer.key == consumer:
|
||||
return cred
|
||||
|
||||
raise IOError("No credentials found for '%s', please see the " \
|
||||
"manage-credentials manpage for help on how to create " \
|
||||
"one for this consumer." % consumer)
|
||||
|
||||
def get_credentials(consumer, cred_file=None, level=None):
|
||||
files = list()
|
||||
|
||||
if cred_file:
|
||||
files.append(cred_file)
|
||||
|
||||
if "LPCREDENTIALS" in os.environ:
|
||||
files.append(os.environ["LPCREDENTIALS"])
|
||||
|
||||
files.append(os.path.join(os.getcwd(), "lp_credentials.txt"))
|
||||
|
||||
# Add all files which have our consumer name to file listing.
|
||||
for x in glob.glob(os.path.expanduser("~/.cache/lp_credentials/%s*.txt" % \
|
||||
consumer)):
|
||||
files.append(x)
|
||||
|
||||
return find_credentials(consumer, files, level)
|
||||
|
||||
def get_launchpad(consumer, server=EDGE_SERVICE_ROOT, cache=None,
|
||||
cred_file=None, level=None):
|
||||
credentials = get_credentials(consumer, cred_file, level)
|
||||
cache = cache or os.environ.get("LPCACHE", None)
|
||||
return Launchpad(credentials, server, cache)
|
||||
|
||||
def query_to_dict(query_string):
|
||||
result = dict()
|
||||
options = filter(None, query_string.split("&"))
|
||||
for opt in options:
|
||||
key, value = opt.split("=")
|
||||
result.setdefault(key, set()).add(value)
|
||||
return result
|
||||
|
||||
def translate_web_api(url, launchpad):
|
||||
scheme, netloc, path, query, fragment = urlparse.urlsplit(url)
|
||||
query = query_to_dict(query)
|
||||
if not (("edge" in netloc and "edge" in str(launchpad._root_uri))
|
||||
or ("staging" in netloc and "staging" in str(launchpad._root_uri))):
|
||||
raise ValueError("url conflict (url: %s, root: %s" %(url, launchpad._root_uri))
|
||||
if path.endswith("/+bugs"):
|
||||
path = path[:-6]
|
||||
if "ws.op" in query:
|
||||
raise ValueError("Invalid web url, url: %s" %url)
|
||||
query["ws.op"] = "searchTasks"
|
||||
scheme, netloc, api_path, _, _ = urlparse.urlsplit(str(launchpad._root_uri))
|
||||
query = urllib.urlencode(query)
|
||||
url = urlparse.urlunsplit((scheme, netloc, api_path + path.lstrip("/"), query, fragment))
|
||||
return url
|
||||
|
||||
def translate_api_web(self_url):
|
||||
return self_url.replace("api.", "").replace("beta/", "")
|
||||
|
||||
LEVEL = {
|
||||
0: "UNAUTHORIZED",
|
||||
1: "READ_PUBLIC",
|
||||
2: "WRITE_PUBLIC",
|
||||
3: "READ_PRIVATE",
|
||||
4: "WRITE_PRIVATE"
|
||||
}
|
||||
|
||||
def approve_application(credentials, email, password, level, web_root,
|
||||
context):
|
||||
authorization_url = credentials.get_request_token(context, web_root)
|
||||
if level in LEVEL:
|
||||
level = 'field.actions.%s' %LEVEL[level]
|
||||
elif level in LEVEL.values():
|
||||
level = 'field.actions.%s' %level
|
||||
elif str(level).startswith("field.actions") and str(level).split(".")[-1] in LEVEL:
|
||||
pass
|
||||
else:
|
||||
raise ValueError("Unknown access level '%s'" %level)
|
||||
|
||||
params = {level: 1,
|
||||
"oauth_token": credentials._request_token.key,
|
||||
"lp.context": context or ""}
|
||||
|
||||
lp_creds = ":".join((email, password))
|
||||
basic_auth = "Basic %s" %(lp_creds.encode('base64'))
|
||||
headers = {'Authorization': basic_auth}
|
||||
response, content = httplib2.Http().request(authorization_url,
|
||||
method="POST", body=urllib.urlencode(params), headers=headers)
|
||||
if int(response["status"]) != 200:
|
||||
if not 300 <= int(response["status"]) <= 400: # this means redirection
|
||||
raise HTTPError(response, content)
|
||||
credentials.exchange_request_token_for_access_token(web_root)
|
||||
return credentials
|
||||
|
||||
def translate_service(service):
|
||||
_service = service.lower()
|
||||
if _service in (STAGING_SERVICE_ROOT, EDGE_SERVICE_ROOT):
|
||||
return _service
|
||||
elif _service == "edge":
|
||||
return EDGE_SERVICE_ROOT
|
||||
elif _service == "staging":
|
||||
return STAGING_SERVICE_ROOT
|
||||
else:
|
||||
raise ValueError("unknown service '%s'" %service)
|
||||
|
Loading…
x
Reference in New Issue
Block a user