OLD | NEW |
| (Empty) |
1 #!/usr/bin/python | |
2 | |
3 # Copyright (c) 2010 The Chromium OS Authors. All rights reserved. | |
4 # Use of this source code is governed by a BSD-style license that can be | |
5 # found in the LICENSE file. | |
6 | |
7 """Helper functions for accessing the issue tracker in a pythonic way.""" | |
8 | |
9 import os.path | |
10 import pprint | |
11 import sys | |
12 | |
13 # import the GData libraries | |
14 import gdata.client | |
15 import gdata.projecthosting.client | |
16 | |
17 DEFAULT_TRACKER_SOURCE = "chromite-tracker-access-1.0" | |
18 VERBOSE = True # Set to True to get extra debug info... | |
19 | |
20 class TrackerAccess(object): | |
21 """Class for accessing the tracker on code.google.com.""" | |
22 | |
23 def __init__(self, email="", password="", | |
24 tracker_source=DEFAULT_TRACKER_SOURCE): | |
25 """TrackerAccess constructor. | |
26 | |
27 Args: | |
28 email: The email address to Login with; may be "" for anonymous access. | |
29 password: The password that goes with the email address; may be "" if | |
30 the email is "". | |
31 tracker_source: A string describing this program. This can be anything | |
32 you like but should should give some indication of which | |
33 app is making the request. | |
34 """ | |
35 # Save parameters... | |
36 self._email = email | |
37 self._password = password | |
38 self._tracker_source = tracker_source | |
39 | |
40 # This will be initted on first login... | |
41 self._tracker_client = None | |
42 | |
43 def Login(self): | |
44 """Login, if needed. This may be safely called more than once. | |
45 | |
46 Commands will call this function as their first line, so the client | |
47 of this class need not call it themselves unless trying to debug login | |
48 problems. | |
49 | |
50 This function should be called even if we're accessing anonymously. | |
51 """ | |
52 # Bail immediately if we've already logged in... | |
53 if self._tracker_client is not None: | |
54 return | |
55 | |
56 self._tracker_client = gdata.projecthosting.client.ProjectHostingClient() | |
57 if self._email and self._password: | |
58 self._tracker_client.client_login(self._email, self._password, | |
59 source=self._tracker_source, | |
60 service="code", account_type='GOOGLE') | |
61 | |
62 def GetKeyedLabels(self, project_name, issue_id): | |
63 """Get labels of the form "Key-Value" attached to the given issue. | |
64 | |
65 Any labels that don't have a dash in them are ignored. | |
66 | |
67 Args: | |
68 project_name: The tracker project to query. | |
69 issue_id: The ID of the issue to query; should be an int but a string | |
70 will probably work too. | |
71 | |
72 Returns: | |
73 A dictionary mapping key/value pairs from the issue's labels, like: | |
74 | |
75 {'Area': 'Build', | |
76 'Iteration': '15', | |
77 'Mstone': 'R9.x', | |
78 'Pri': '1', | |
79 'Type': 'Bug'} | |
80 """ | |
81 # Login if needed... | |
82 self.Login() | |
83 | |
84 # Construct the query... | |
85 query = gdata.projecthosting.client.Query(issue_id=issue_id) | |
86 try: | |
87 feed = self._tracker_client.get_issues(project_name, query=query) | |
88 except gdata.client.RequestError, e: | |
89 if VERBOSE: | |
90 print >>sys.stderr, "ERROR: Unable to access bug %s:%s: %s" % ( | |
91 project_name, issue_id, str(e)) | |
92 return {} | |
93 | |
94 # There should be exactly one result... | |
95 assert len(feed.entry) == 1, "Expected exactly 1 result" | |
96 (entry,) = feed.entry | |
97 | |
98 # We only care about labels that look like: Key-Value | |
99 # We'll return a dictionary of those. | |
100 keyed_labels = {} | |
101 for label in entry.label: | |
102 if "-" in label.text: | |
103 label_key, label_val = label.text.split("-", 1) | |
104 keyed_labels[label_key] = label_val | |
105 | |
106 return keyed_labels | |
107 | |
108 | |
109 def _TestGetKeyedLabels(project_name, email, passwordFile, *bug_ids): | |
110 """Test code for GetKeyedLabels(). | |
111 | |
112 Args: | |
113 project_name: The name of the project we're looking at. | |
114 email: The email address to use to login. May be "" | |
115 passwordFile: A file containing the password for the email address. | |
116 May be "" if email is "" for anon access. | |
117 bug_ids: A list of bug IDs to query. | |
118 """ | |
119 # If password was specified as a file, read it. | |
120 if passwordFile: | |
121 password = open(passwordFile, "r").read().strip() | |
122 else: | |
123 password = "" | |
124 | |
125 ta = TrackerAccess(email, password) | |
126 | |
127 if not bug_ids: | |
128 print "No bugs were specified" | |
129 else: | |
130 for bug_id in bug_ids: | |
131 print bug_id, ta.GetKeyedLabels(project_name, int(bug_id)) | |
132 | |
133 | |
134 def _DoHelp(commands, *args): | |
135 """Print help for the script.""" | |
136 | |
137 if len(args) >= 2 and args[0] == "help" and args[1] in commands: | |
138 # If called with arguments 'help' and 'command', show that commands's doc. | |
139 command_name = args[1] | |
140 print commands[command_name].__doc__ | |
141 else: | |
142 # Something else: show generic help... | |
143 print ( | |
144 "Usage %s <command> <command args>\n" | |
145 "\n" | |
146 "Known commands: \n" | |
147 " %s\n" | |
148 ) % (sys.argv[0], pprint.pformat(["help"] + sorted(commands))) | |
149 | |
150 | |
151 def main(): | |
152 """Main function of the script.""" | |
153 | |
154 commands = { | |
155 "TestGetKeyedLabels": _TestGetKeyedLabels, | |
156 } | |
157 | |
158 if len(sys.argv) <= 1 or sys.argv[1] not in commands: | |
159 # Argument 1 isn't in list of commands; show help and pass all arguments... | |
160 _DoHelp(commands, *sys.argv[1:]) | |
161 else: | |
162 command_name = sys.argv[1] | |
163 commands[command_name](*sys.argv[2:]) | |
164 | |
165 if __name__ == "__main__": | |
166 main() | |
OLD | NEW |