1
2
3 """
4 Function actually doing the work of calling the API and handling the
5 output.
6 """
7
8 import ConfigParser
9 import datetime
10 import json
11 import os
12 import re
13 import requests
14 import sys
15 import time
16
17 import copr_exceptions
18
19
21 """ Wrapper around response from server
22
23 check data and print nice error in case of some error (and return None)
24 otherwise return json object.
25 """
26 if "<title>Sign in Coprs</title>" in req.text:
27 sys.stderr.write("Invalid API token\n")
28 return
29
30 if req.status_code == 404:
31 if copr is None:
32 sys.stderr.write("User {0} is unknown.\n".format(user["username"]))
33 else:
34 sys.stderr.write("Project {0}/{1} not found.\n".format(
35 (user["username"], copr)))
36 return
37 try:
38 output = json.loads(req.text)
39 except ValueError:
40 sys.stderr.write("Unknown response from server.\n")
41 return
42 if req.status_code != 200:
43 sys.stderr.write(
44 "Something went wrong:\n {0}\n".format(output["error"]))
45 return
46 return output
47
48
50 """ Retrieve the user information from the config file. """
51 config = ConfigParser.ConfigParser()
52 if not config.read(
53 os.path.join(os.path.expanduser("~"), ".config", "copr")):
54 raise copr_exceptions.CoprCliNoConfException(
55 "No configuration file '~/.config/copr' found. "
56 "See man copr-cli for more information")
57 try:
58 username = config.get("copr-cli", "username", None)
59 login = config.get("copr-cli", "login", None)
60 token = config.get("copr-cli", "token", None)
61 except ConfigParser.Error as err:
62 raise copr_exceptions.CoprCliConfigException(
63 "Bad configuration file: {0}".format(err))
64 return {"username": username, "token": token, "login": login}
65
66
68 """ Retrieve the user information from the config file. """
69 config = ConfigParser.ConfigParser()
70 config.read(
71 os.path.join(os.path.expanduser("~"), ".config", "copr")
72 )
73
74
75 copr_url = "http://copr.fedoraproject.org/"
76 if (config.has_section("copr-cli") and
77 config.has_option("copr-cli", "copr_url")):
78
79 copr_url = config.get("copr-cli", "copr_url")
80 return "{0}/api".format(copr_url)
81
82
84 """ List all the copr of a user. """
85 user = {}
86 if not username:
87 user = get_user()
88 del(user["token"])
89
90 if username:
91 user["username"] = username
92
93 copr_api_url = get_api_url()
94 url = "{0}/coprs/{1}/".format(copr_api_url, user["username"])
95
96 req = requests.get(url)
97 output = _get_data(req, user)
98 if output is None:
99 return
100 elif "repos" in output:
101 PAD = " " * 2
102 if output["repos"]:
103 for repo in output["repos"]:
104 print("Name: {0}".format(repo["name"]))
105
106 if "description" in repo:
107 desc = repo["description"]
108 print(PAD + "Description: {0}".format(desc))
109
110 if "yum_repos" in repo:
111 yum_repos = repo["yum_repos"]
112 print(PAD + "Yum repo(s):")
113 for k in sorted(yum_repos.keys()):
114 print(PAD * 2 + "{0}: {1}".format(k, yum_repos[k]))
115
116 if "additional_repos" in repo:
117 add_repos = repo["additional_repos"]
118 print(PAD + "Additional repos: {0}".format(add_repos))
119
120 if "instructions" in repo:
121 instructions = repo["instructions"]
122 print(PAD + "Instructions: {0}".format(instructions))
123 else:
124 print("No copr retrieved for user: '{0}'".format(
125 user["username"]))
126 else:
127 print("Un-expected data returned, please report this issue")
128
129
130 -def create(name, chroots=[], description=None, instructions=None,
131 repos=None, initial_pkgs=None):
132 """ Create a new copr. """
133 if chroots is None:
134 sys.stderr.write("Error: At least one chroot must be selected\n")
135 sys.exit(1)
136
137 user = get_user()
138 copr_api_url = get_api_url()
139 URL = "{0}/coprs/{1}/new/".format(copr_api_url, user["username"])
140
141 if type(repos) == list():
142 repos = " ".join(repos)
143
144 if type(initial_pkgs) == list():
145 initial_pkgs = " ".join(initial_pkgs)
146
147 data = {"name": name,
148 "repos": repos,
149 "initial_pkgs": initial_pkgs,
150 "description": description,
151 "instructions": instructions
152 }
153 for chroot in chroots:
154 data[chroot] = "y"
155
156 req = requests.post(URL,
157 auth=(user["login"], user["token"]),
158 data=data)
159 output = _get_data(req, user)
160 if output is not None:
161 print(output["message"])
162
163
165 user = get_user()
166 copr_api_url = get_api_url()
167 URL = "{0}/coprs/build_status/{1}/".format(
168 copr_api_url,
169 build_id)
170
171 req = requests.get(URL, auth=(user["login"], user["token"]))
172 output = _get_data(req, user)
173 if output is None:
174 return (False, "Error occurred.")
175 elif "status" in output:
176 return (True, output["status"])
177 else:
178 return (False, output["error"])
179
180
182 """ Return status of build """
183 (ret, value) = _fetch_status(build_id)
184 print(value)
185
187 """ Cancel specified build_id """
188 user = get_user()
189 copr_api_url = get_api_url()
190
191 URL = "{0}/coprs/cancel_build/{1}/".format(
192 copr_api_url,
193 build_id)
194 req = requests.get(URL, auth=(user["login"], user["token"]))
195 output = _get_data(req, user)
196 if output is None:
197 return (False, "Error occurred.")
198 elif "status" in output:
199 return (True, output["status"])
200 else:
201 return (False, output["error"])
202
203 -def build(copr, pkgs, memory, timeout, wait=True, result=None, chroots=None):
204 """ Build a new package into a given copr.
205
206 Result is dictionary where is returned "errmsg" in case of error.
207 And "id" and "status" otherwise.
208 """
209 user = get_user()
210 username = user["username"]
211
212
213 m = re.match(r"(.+)/(.+)", copr)
214 if m:
215 username = m.group(1)
216 copr = m.group(2)
217
218 copr_api_url = get_api_url()
219 URL = "{0}/coprs/{1}/{2}/new_build/".format(
220 copr_api_url,
221 username,
222 copr)
223
224 data = {"pkgs": " ".join(pkgs),
225 "memory": memory,
226 "timeout": timeout
227 }
228
229 if chroots is not None:
230 for chroot in chroots:
231 data[chroot] = "y"
232
233 req = requests.post(URL,
234 auth=(user["login"], user["token"]),
235 data=data)
236 output = _get_data(req, user, copr)
237 if output is None:
238 return
239 else:
240 print(output["message"])
241
242 if wait:
243 print("{0} builds were added.".format(len(output["ids"])))
244 print("Watching builds (this may be safely interrupted)...")
245 prevstatus = {}
246 for id in output["ids"]:
247 prevstatus[id] = None
248 if result is not None:
249 result[id] = {}
250 try:
251 while True:
252 for id in output["ids"]:
253 (ret, status) = _fetch_status(id)
254 if not ret:
255 errmsg = "Build {1}: Unable to get build status: {0}".format(status,id)
256 print errmsg
257 if result is not None:
258 result[id]['errmsg'] = errmsg
259 return False
260
261 now = datetime.datetime.now()
262 if prevstatus[id] != status:
263 print("{0} Build {2}: {1}".format(now.strftime("%H:%M:%S"), status, id))
264 prevstatus[id] = status
265
266 if status in ["succeeded", "failed", "canceled"]:
267 if result is not None:
268 result[id]['status'] = status
269 output["ids"].remove(id)
270
271 if not output["ids"]:
272 return True
273
274 time.sleep(60)
275
276 except KeyboardInterrupt:
277 pass
278
279 return True
280