Merge lp:~james-w/ubuntu-archive-tools/improved-sync-helper into lp:ubuntu-archive-tools

Proposed by James Westby
Status: Merged
Approved by: Steve Kowalik
Approved revision: not available
Merge reported by: Steve Kowalik
Merged at revision: not available
Proposed branch: lp:~james-w/ubuntu-archive-tools/improved-sync-helper
Merge into: lp:ubuntu-archive-tools
Diff against target: 221 lines (+160/-31)
1 file modified
sync-helper.py (+160/-31)
To merge this branch: bzr merge lp:~james-w/ubuntu-archive-tools/improved-sync-helper
Reviewer Review Type Date Requested Status
Steve Kowalik (community) Approve
Review via email: mp+16779@code.launchpad.net
To post a comment you must log in.
Revision history for this message
James Westby (james-w) wrote :

Hi Steven,

Please review my changes to sync-helper.py and see if you like
them. I didn't want to unilaterally make them to your script,
but I think these improvements make it a lot more usable.

Thanks for writing the initial version. Processing syncs is much
quicker with this script now.

Thanks,

James

91. By James Westby

Allow changing suite back to unstable.

92. By James Westby

Mark commenters that can upload the package with (*).

This makes it easier to see if sponsorship is still needed.

93. By James Westby

Get all the info up-front to speed up processing.

94. By James Westby

Add progress output.

Also avoid another call to rmadison by re-using the info that we have.

95. By James Westby

Fix a thinko that caused crashes when looking up the component

96. By James Westby

Also consider package sets when looking for uploaders.

Revision history for this message
Steve Kowalik (stevenk) wrote :

Hi James,

This all looks totally awesome! Thanks for the great changes, I'll merge them into trunk soonish.

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'sync-helper.py'
2--- sync-helper.py 2009-11-20 20:29:12 +0000
3+++ sync-helper.py 2010-01-04 19:09:12 +0000
4@@ -3,22 +3,108 @@
5 # Copyright 2009 Canonical Ltd.
6
7 import os, sys
8-from launchpadlib.launchpad import Launchpad, STAGING_SERVICE_ROOT
9+import subprocess
10+from launchpadlib.launchpad import Launchpad, EDGE_SERVICE_ROOT, STAGING_SERVICE_ROOT
11+import webbrowser
12
13 APP_NAME = 'sync-helper'
14 CACHE_DIR = os.path.expanduser('~/.launchpadlib/cache')
15-SERVICE_ROOT = STAGING_SERVICE_ROOT
16+SERVICE_ROOT = EDGE_SERVICE_ROOT
17+
18+
19+class Bug(object):
20+
21+ def __init__(self, number):
22+ self.number = number
23+ self.title = None
24+ self.package = None
25+ self.reporter = None
26+ self.content = None
27+
28
29 def length(collection):
30 # XXX: Workaround bug 274074. Thanks wgrant.
31 return int(collection._wadl_resource.representation['total_size'])
32
33-def prompt(text):
34- print "%s [Show/sKip/sYnc] " % text
35- return sys.stdin.readline().rstrip()
36-
37-def sync(bug, syncfile):
38- syncfile.write("sync %s -f\n" % bug)
39+def rmadison(distro, package):
40+ proc = subprocess.Popen(["/usr/bin/rmadison", "-u", distro, package],
41+ stdout=subprocess.PIPE)
42+ (output, _) = proc.communicate()
43+ return output.splitlines()
44+
45+def get_components(package, debian_details):
46+ components = {}
47+ for line in debian_details.splitlines():
48+ if line.strip() == "":
49+ continue
50+ series_component = line.split("|")[2].strip()
51+ archs = line.split("|")[3].strip().split(", ")
52+ if "source" in archs:
53+ if "/" in series_component:
54+ series, component = series_component.split("/")
55+ components[series] = component
56+ else:
57+ components[series_component] = "main"
58+ return components
59+
60+def ubuntu_details(package, current_series):
61+ output = rmadison("ubuntu", package)
62+ new_output = []
63+ for line in output:
64+ parts = line.split("|")
65+ if current_series in parts[2]:
66+ new_output.append(line)
67+ return new_output
68+
69+def debian_details(package):
70+ return rmadison("debian", package)
71+
72+def canUpload(distribution, person, package_name):
73+ if distribution.main_archive.isSourceUploadAllowed(
74+ distroseries=distribution.current_series, person=person,
75+ sourcepackagename=package_name):
76+ return True
77+ pubs = distribution.main_archive.getPublishedSources(
78+ distro_series=distribution.current_series, exact_match=True,
79+ pocket="Release", status="Published", source_name=package_name)
80+ pubs = [pub for pub in pubs]
81+ if len(pubs) < 1:
82+ return False
83+ component = pubs[0].component_name
84+ for perm in distribution.main_archive.getPermissionsForPerson(person=person):
85+ if perm.permission != 'Archive Upload Rights':
86+ continue
87+ if perm.component_name == component:
88+ return True
89+ if perm.source_package_name == package_name:
90+ return True
91+ return False
92+
93+def prompt(bug, suite, full=True):
94+ sys.stdout.write("%s: %s\n" % (bug.number, bug.title))
95+ if full:
96+ sys.stdout.write(bug.ubuntu_details + "\n")
97+ sys.stdout.write(bug.debian_details + "\n")
98+ msg = "[Show/sKip/sYnc from %s/" % (suite,)
99+ if suite == "unstable" or suite == "experimental":
100+ msg += "switch to Testing/"
101+ elif suite == "testing":
102+ msg += "switch to Unstable/"
103+ if suite == "testing" or suite == "unstable":
104+ msg += "switch to Experimental/"
105+ elif suite == "experimental":
106+ msg += "switch to Unstable/"
107+ msg += "Open bug]: "
108+ sys.stdout.write(msg)
109+ sys.stdout.flush()
110+ return sys.stdin.readline().rstrip().upper()
111+
112+def sync(bug, syncfile, suite="unstable", component="main"):
113+ params = {"bug": bug.number,
114+ "suite": suite,
115+ "component": component,
116+ }
117+ syncfile.write("sync %(bug)s -f -S %(suite)s -C %(component)s\n" % params)
118
119 def main(args):
120 f = None
121@@ -27,35 +113,78 @@
122 except:
123 print "%s: Require a filename to write to!" % args[0]
124 sys.exit(1)
125- print "Connecting to LP ... "
126+ sys.stdout.write("Connecting to LP ... ")
127+ sys.stdout.flush()
128 launchpad = Launchpad.login_with(APP_NAME, SERVICE_ROOT, CACHE_DIR)
129 pillar = launchpad.projects['ubuntu']
130 subscriber = launchpad.people['ubuntu-archive']
131- print "Done"
132- print "Loading bugs ... "
133- bugs = pillar.searchTasks(bug_subscriber = subscriber, search_text = 'sync')
134- bugs_cache = {}
135- bug_numbers = {}
136+ ubuntu_series = pillar.current_series.name
137+ sys.stdout.write("Done\n")
138+ sys.stdout.write("Loading bugs (this may take some time, go get a "
139+ "cup of tea) ... \n")
140+ sync_bugs = []
141+ bugs = pillar.searchTasks(bug_subscriber=subscriber, search_text='qcad')
142+ num_bugs = length(bugs)
143+ bugs_processed = 0
144+ prev_line = ""
145 for bugtask in bugs:
146- bugs_cache[bugtask.bug.title] = bugtask.bug.description
147- for i in reversed(bugtask.bug.messages_collection):
148- bugs_cache[bugtask.bug.title] += i.content
149- bug_numbers[bugtask.bug.title] = bugtask.bug.id
150- print "Done"
151+ bugs_processed += 1
152+ sys.stdout.write("\r" + " "*len(prev_line) + "\r")
153+ prev_line = "%d/%d" % (bugs_processed, num_bugs)
154+ sys.stdout.write(prev_line)
155+ sys.stdout.flush()
156+ if " (Ubuntu)" not in bugtask.bug_target_name:
157+ continue
158+ bug = Bug(bugtask.bug.id)
159+ bug.title = bugtask.bug.title
160+ bug.package = bugtask.bug_target_name.rsplit(" ", 1)[0]
161+ next_line_part = ": %s" % (bug.package,)
162+ sys.stdout.write(next_line_part)
163+ prev_line += next_line_part
164+ sys.stdout.flush()
165+ bug.content = bugtask.bug.description
166+ bug.reporter = bugtask.bug.owner
167+ for i in reversed(bugtask.bug.messages):
168+ bug.content += "\n=============================================\n"
169+ star = ""
170+ if canUpload(pillar, i.owner, bug.package):
171+ star = "(*)"
172+ bug.content += "%s%s said %s on %s:\n\n" % (i.owner.name, star,
173+ i.subject, str(i.date_created))
174+ bug.content += i.content
175+ bug.ubuntu_details = "\n".join(ubuntu_details(bug.package, ubuntu_series))
176+ bug.debian_details = "\n".join(debian_details(bug.package))
177+ bug.components = get_components(bug.package, bug.debian_details)
178+ sync_bugs.append(bug)
179+ sys.stdout.write("\r" + " "*len(prev_line) + "\r")
180+ sys.stdout.write("Done, %d packages to consider.\n" % (len(sync_bugs),))
181
182- for title in bugs_cache.keys():
183- ret = prompt(title)
184- if ret == 'S':
185- print bugs_cache[title]
186- ret = prompt(title)
187- if ret == 'Y':
188- sync(bug_numbers[title], f)
189+ for bug in sync_bugs:
190+ sys.stdout.write("\n==========================\n")
191+ finished = False
192+ suite = "unstable"
193+ component = "main"
194+ if suite in bug.components:
195+ component = bug.components[suite]
196+ full = True
197+ while not finished:
198+ ret = prompt(bug, suite, full=full)
199+ if ret == 'S':
200+ print bug.content
201 elif ret == 'K':
202- continue
203- elif ret == 'K':
204- continue
205- elif ret == 'Y':
206- sync(bug_numbers[title], f)
207+ finished = True
208+ elif ret == 'Y':
209+ sync(bug, f, suite=suite, component=component)
210+ finished = True
211+ elif ret == 'T':
212+ suite = "testing"
213+ elif ret == 'U':
214+ suite = "unstable"
215+ elif ret == 'E':
216+ suite = "experimental"
217+ elif ret == 'O':
218+ webbrowser.open("https://bugs.launchpad.net/bugs/%s" % bug.number)
219+ full = False
220 f.close()
221 return 0
222

Subscribers

People subscribed via source and target branches