]>
Commit | Line | Data |
---|---|---|
47a4cb89 | 1 | #!/usr/bin/python |
b792d887 MT |
2 | ############################################################################### |
3 | # # | |
4 | # Pakfire - The IPFire package management system # | |
5 | # Copyright (C) 2011 Pakfire development team # | |
6 | # # | |
7 | # This program is free software: you can redistribute it and/or modify # | |
8 | # it under the terms of the GNU General Public License as published by # | |
9 | # the Free Software Foundation, either version 3 of the License, or # | |
10 | # (at your option) any later version. # | |
11 | # # | |
12 | # This program is distributed in the hope that it will be useful, # | |
13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of # | |
14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # | |
15 | # GNU General Public License for more details. # | |
16 | # # | |
17 | # You should have received a copy of the GNU General Public License # | |
18 | # along with this program. If not, see <http://www.gnu.org/licenses/>. # | |
19 | # # | |
20 | ############################################################################### | |
47a4cb89 MT |
21 | |
22 | import argparse | |
936f6b37 | 23 | import os |
b913e798 | 24 | import shutil |
47a4cb89 | 25 | import sys |
b913e798 | 26 | import tempfile |
47a4cb89 | 27 | |
c62d93f1 MT |
28 | import pakfire.api as pakfire |
29 | ||
30 | import client | |
31 | import config | |
60845a36 | 32 | import logger |
47a4cb89 | 33 | import packages |
fa6d335b | 34 | import repository |
677ff42a | 35 | import server |
e9c20259 | 36 | import util |
47a4cb89 | 37 | |
c62d93f1 | 38 | from system import system |
47a4cb89 MT |
39 | from constants import * |
40 | from i18n import _ | |
41 | ||
60845a36 MT |
42 | # Initialize a very simple logging that is removed when a Pakfire instance |
43 | # is started. | |
44 | logger.setup_logging() | |
45 | ||
47a4cb89 | 46 | class Cli(object): |
47a4cb89 MT |
47 | def __init__(self): |
48 | self.parser = argparse.ArgumentParser( | |
49 | description = _("Pakfire command line interface."), | |
50 | ) | |
51 | ||
52 | self.parse_common_arguments() | |
53 | ||
2ba449f0 | 54 | self.parser.add_argument("--root", metavar="PATH", |
d2e26956 | 55 | default="/", |
47a4cb89 MT |
56 | help=_("The path where pakfire should operate in.")) |
57 | ||
58 | # Add sub-commands. | |
59 | self.sub_commands = self.parser.add_subparsers() | |
60 | ||
61 | self.parse_command_install() | |
5e87fa4f | 62 | self.parse_command_localinstall() |
0ca71090 | 63 | self.parse_command_reinstall() |
a39fd08b | 64 | self.parse_command_remove() |
47a4cb89 MT |
65 | self.parse_command_info() |
66 | self.parse_command_search() | |
e38914be | 67 | self.parse_command_check_update() |
47a4cb89 | 68 | self.parse_command_update() |
67d1ddbd | 69 | self.parse_command_downgrade() |
fa6d335b | 70 | self.parse_command_provides() |
c1962d40 | 71 | self.parse_command_grouplist() |
ce2764c1 | 72 | self.parse_command_groupinstall() |
67bc4528 | 73 | self.parse_command_repolist() |
31267a64 | 74 | self.parse_command_clean() |
35d89fd7 | 75 | self.parse_command_check() |
b25a3d84 | 76 | self.parse_command_resolvdep() |
47a4cb89 MT |
77 | |
78 | # Finally parse all arguments from the command line and save them. | |
79 | self.args = self.parser.parse_args() | |
80 | ||
47a4cb89 | 81 | self.action2func = { |
5e87fa4f MT |
82 | "install" : self.handle_install, |
83 | "localinstall" : self.handle_localinstall, | |
0ca71090 | 84 | "reinstall" : self.handle_reinstall, |
a39fd08b | 85 | "remove" : self.handle_remove, |
e38914be | 86 | "check_update" : self.handle_check_update, |
5e87fa4f | 87 | "update" : self.handle_update, |
67d1ddbd | 88 | "downgrade" : self.handle_downgrade, |
5e87fa4f MT |
89 | "info" : self.handle_info, |
90 | "search" : self.handle_search, | |
fa6d335b | 91 | "provides" : self.handle_provides, |
c1962d40 | 92 | "grouplist" : self.handle_grouplist, |
ce2764c1 | 93 | "groupinstall" : self.handle_groupinstall, |
67bc4528 | 94 | "repolist" : self.handle_repolist, |
31267a64 | 95 | "clean_all" : self.handle_clean_all, |
35d89fd7 | 96 | "check" : self.handle_check, |
b25a3d84 | 97 | "resolvdep" : self.handle_resolvdep, |
47a4cb89 MT |
98 | } |
99 | ||
7c8f2953 MT |
100 | @property |
101 | def pakfire_args(self): | |
6557ff4c MT |
102 | ret = { "mode" : "normal" } |
103 | ||
2ba449f0 MT |
104 | if hasattr(self.args, "root"): |
105 | ret["path"] = self.args.root | |
f9a012a8 MT |
106 | |
107 | if hasattr(self.args, "disable_repo"): | |
108 | ret["disable_repos"] = self.args.disable_repo | |
109 | ||
110 | if hasattr(self.args, "enable_repo"): | |
111 | ret["enable_repos"] = self.args.enable_repo | |
112 | ||
6a509182 MT |
113 | if hasattr(self.args, "offline"): |
114 | ret["offline"] = self.args.offline | |
115 | ||
f9a012a8 | 116 | return ret |
7c8f2953 | 117 | |
c62d93f1 | 118 | def parse_common_arguments(self, repo_manage_switches=True, offline_switch=True): |
50381f5c MT |
119 | self.parser.add_argument("--version", action="version", |
120 | version="%(prog)s " + PAKFIRE_VERSION) | |
121 | ||
47a4cb89 MT |
122 | self.parser.add_argument("-v", "--verbose", action="store_true", |
123 | help=_("Enable verbose output.")) | |
124 | ||
125 | self.parser.add_argument("-c", "--config", nargs="?", | |
126 | help=_("Path to a configuration file to load.")) | |
127 | ||
c62d93f1 MT |
128 | if repo_manage_switches: |
129 | self.parser.add_argument("--disable-repo", nargs="*", metavar="REPO", | |
130 | help=_("Disable a repository temporarily.")) | |
f781b1ab | 131 | |
c62d93f1 MT |
132 | self.parser.add_argument("--enabled-repo", nargs="*", metavar="REPO", |
133 | help=_("Enable a repository temporarily.")) | |
f9a012a8 | 134 | |
c62d93f1 MT |
135 | if offline_switch: |
136 | self.parser.add_argument("--offline", action="store_true", | |
137 | help=_("Run pakfire in offline mode.")) | |
6a509182 | 138 | |
47a4cb89 MT |
139 | def parse_command_install(self): |
140 | # Implement the "install" command. | |
141 | sub_install = self.sub_commands.add_parser("install", | |
142 | help=_("Install one or more packages to the system.")) | |
143 | sub_install.add_argument("package", nargs="+", | |
144 | help=_("Give name of at least one package to install.")) | |
145 | sub_install.add_argument("action", action="store_const", const="install") | |
146 | ||
5e87fa4f MT |
147 | def parse_command_localinstall(self): |
148 | # Implement the "localinstall" command. | |
149 | sub_install = self.sub_commands.add_parser("localinstall", | |
150 | help=_("Install one or more packages from the filesystem.")) | |
151 | sub_install.add_argument("package", nargs="+", | |
152 | help=_("Give filename of at least one package.")) | |
153 | sub_install.add_argument("action", action="store_const", const="localinstall") | |
154 | ||
0ca71090 MT |
155 | def parse_command_reinstall(self): |
156 | # Implement the "reinstall" command. | |
157 | sub_install = self.sub_commands.add_parser("reinstall", | |
158 | help=_("Reinstall one or more packages.")) | |
159 | sub_install.add_argument("package", nargs="+", | |
160 | help=_("Give name of at least one package to reinstall.")) | |
161 | sub_install.add_argument("action", action="store_const", const="reinstall") | |
162 | ||
a39fd08b MT |
163 | def parse_command_remove(self): |
164 | # Implement the "remove" command. | |
165 | sub_remove = self.sub_commands.add_parser("remove", | |
166 | help=_("Remove one or more packages from the system.")) | |
167 | sub_remove.add_argument("package", nargs="+", | |
168 | help=_("Give name of at least one package to remove.")) | |
169 | sub_remove.add_argument("action", action="store_const", const="remove") | |
170 | ||
05fb1da0 MT |
171 | @staticmethod |
172 | def _parse_command_update(parser): | |
173 | parser.add_argument("package", nargs="*", | |
174 | help=_("Give a name of a package to update or leave emtpy for all.")) | |
175 | parser.add_argument("--exclude", "-x", nargs="+", | |
176 | help=_("Exclude package from update.")) | |
177 | parser.add_argument("--allow-vendorchange", action="store_true", | |
178 | help=_("Allow changing the vendor of packages.")) | |
179 | parser.add_argument("--allow-archchange", action="store_true", | |
180 | help=_("Allow changing the architecture of packages.")) | |
181 | ||
47a4cb89 MT |
182 | def parse_command_update(self): |
183 | # Implement the "update" command. | |
184 | sub_update = self.sub_commands.add_parser("update", | |
185 | help=_("Update the whole system or one specific package.")) | |
47a4cb89 | 186 | sub_update.add_argument("action", action="store_const", const="update") |
05fb1da0 | 187 | self._parse_command_update(sub_update) |
47a4cb89 | 188 | |
e38914be MT |
189 | def parse_command_check_update(self): |
190 | # Implement the "check-update" command. | |
191 | sub_check_update = self.sub_commands.add_parser("check-update", | |
192 | help=_("Check, if there are any updates available.")) | |
e38914be | 193 | sub_check_update.add_argument("action", action="store_const", const="check_update") |
05fb1da0 | 194 | self._parse_command_update(sub_check_update) |
e38914be | 195 | |
67d1ddbd MT |
196 | def parse_command_downgrade(self): |
197 | # Implement the "downgrade" command. | |
198 | sub_downgrade = self.sub_commands.add_parser("downgrade", | |
199 | help=_("Downgrade one or more packages.")) | |
200 | sub_downgrade.add_argument("package", nargs="*", | |
201 | help=_("Give a name of a package to downgrade.")) | |
202 | sub_downgrade.add_argument("--allow-vendorchange", action="store_true", | |
203 | help=_("Allow changing the vendor of packages.")) | |
204 | sub_downgrade.add_argument("--allow-archchange", action="store_true", | |
205 | help=_("Allow changing the architecture of packages.")) | |
206 | sub_downgrade.add_argument("action", action="store_const", const="downgrade") | |
207 | ||
47a4cb89 MT |
208 | def parse_command_info(self): |
209 | # Implement the "info" command. | |
210 | sub_info = self.sub_commands.add_parser("info", | |
211 | help=_("Print some information about the given package(s).")) | |
212 | sub_info.add_argument("package", nargs="+", | |
213 | help=_("Give at least the name of one package.")) | |
214 | sub_info.add_argument("action", action="store_const", const="info") | |
215 | ||
216 | def parse_command_search(self): | |
217 | # Implement the "search" command. | |
218 | sub_search = self.sub_commands.add_parser("search", | |
219 | help=_("Search for a given pattern.")) | |
220 | sub_search.add_argument("pattern", | |
221 | help=_("A pattern to search for.")) | |
222 | sub_search.add_argument("action", action="store_const", const="search") | |
223 | ||
fa6d335b MT |
224 | def parse_command_provides(self): |
225 | # Implement the "provides" command | |
226 | sub_provides = self.sub_commands.add_parser("provides", | |
227 | help=_("Get a list of packages that provide a given file or feature.")) | |
228 | sub_provides.add_argument("pattern", nargs="+", | |
229 | help=_("File or feature to search for.")) | |
230 | sub_provides.add_argument("action", action="store_const", const="provides") | |
231 | ||
c1962d40 MT |
232 | def parse_command_grouplist(self): |
233 | # Implement the "grouplist" command | |
234 | sub_grouplist = self.sub_commands.add_parser("grouplist", | |
235 | help=_("Get list of packages that belong to the given group.")) | |
236 | sub_grouplist.add_argument("group", nargs=1, | |
237 | help=_("Group name to search for.")) | |
238 | sub_grouplist.add_argument("action", action="store_const", const="grouplist") | |
239 | ||
ce2764c1 MT |
240 | def parse_command_groupinstall(self): |
241 | # Implement the "grouplist" command | |
242 | sub_groupinstall = self.sub_commands.add_parser("groupinstall", | |
243 | help=_("Install all packages that belong to the given group.")) | |
244 | sub_groupinstall.add_argument("group", nargs=1, | |
245 | help=_("Group name.")) | |
246 | sub_groupinstall.add_argument("action", action="store_const", const="groupinstall") | |
247 | ||
67bc4528 MT |
248 | def parse_command_repolist(self): |
249 | # Implement the "repolist" command | |
250 | sub_repolist = self.sub_commands.add_parser("repolist", | |
251 | help=_("List all currently enabled repositories.")) | |
252 | sub_repolist.add_argument("action", action="store_const", const="repolist") | |
ce2764c1 | 253 | |
31267a64 MT |
254 | def parse_command_clean(self): |
255 | sub_clean = self.sub_commands.add_parser("clean", help=_("Cleanup commands.")) | |
256 | ||
257 | sub_clean_commands = sub_clean.add_subparsers() | |
258 | ||
259 | self.parse_command_clean_all(sub_clean_commands) | |
260 | ||
261 | def parse_command_clean_all(self, sub_commands): | |
262 | sub_create = sub_commands.add_parser("all", | |
263 | help=_("Cleanup all temporary files.")) | |
264 | sub_create.add_argument("action", action="store_const", const="clean_all") | |
265 | ||
35d89fd7 MT |
266 | def parse_command_check(self): |
267 | # Implement the "check" command | |
268 | sub_check = self.sub_commands.add_parser("check", | |
269 | help=_("Check the system for any errors.")) | |
270 | sub_check.add_argument("action", action="store_const", const="check") | |
271 | ||
b25a3d84 MT |
272 | def parse_command_resolvdep(self): |
273 | # Implement the "resolvdep" command. | |
274 | sub_resolvdep = self.sub_commands.add_parser("resolvdep", | |
275 | help=_("Check the dependencies for a particular package.")) | |
276 | sub_resolvdep.add_argument("package", nargs="+", | |
277 | help=_("Give name of at least one package to check.")) | |
278 | sub_resolvdep.add_argument("action", action="store_const", const="resolvdep") | |
279 | ||
47a4cb89 MT |
280 | def run(self): |
281 | action = self.args.action | |
282 | ||
47a4cb89 MT |
283 | try: |
284 | func = self.action2func[action] | |
285 | except KeyError: | |
c62d93f1 | 286 | raise Exception, "Unhandled action: %s" % action |
47a4cb89 MT |
287 | |
288 | return func() | |
289 | ||
9afa5620 | 290 | def handle_info(self, long=False): |
7c8f2953 | 291 | pkgs = pakfire.info(self.args.package, **self.pakfire_args) |
47a4cb89 | 292 | |
7c8f2953 MT |
293 | for pkg in pkgs: |
294 | print pkg.dump(long=long) | |
47a4cb89 MT |
295 | |
296 | def handle_search(self): | |
7c8f2953 | 297 | pkgs = pakfire.search(self.args.pattern, **self.pakfire_args) |
47a4cb89 MT |
298 | |
299 | for pkg in pkgs: | |
300 | print pkg.dump(short=True) | |
301 | ||
05fb1da0 MT |
302 | def handle_update(self, **args): |
303 | args.update(self.pakfire_args) | |
304 | ||
305 | pakfire.update(self.args.package, excludes=self.args.exclude, | |
306 | allow_vendorchange=self.args.allow_vendorchange, | |
307 | allow_archchange=self.args.allow_archchange, | |
308 | **args) | |
47a4cb89 | 309 | |
e38914be | 310 | def handle_check_update(self): |
05fb1da0 | 311 | self.handle_update(check=True) |
e38914be | 312 | |
67d1ddbd MT |
313 | def handle_downgrade(self, **args): |
314 | args.update(self.pakfire_args) | |
315 | ||
316 | pakfire.downgrade(self.args.package, | |
317 | allow_vendorchange=self.args.allow_vendorchange, | |
318 | allow_archchange=self.args.allow_archchange, | |
319 | **args) | |
320 | ||
e0b99370 MT |
321 | def handle_install(self): |
322 | pakfire.install(self.args.package, **self.pakfire_args) | |
5e87fa4f MT |
323 | |
324 | def handle_localinstall(self): | |
e0b99370 | 325 | pakfire.localinstall(self.args.package, **self.pakfire_args) |
5e87fa4f | 326 | |
0ca71090 MT |
327 | def handle_reinstall(self): |
328 | pakfire.reinstall(self.args.package, **self.pakfire_args) | |
329 | ||
a39fd08b MT |
330 | def handle_remove(self): |
331 | pakfire.remove(self.args.package, **self.pakfire_args) | |
332 | ||
fa6d335b | 333 | def handle_provides(self): |
7c8f2953 | 334 | pkgs = pakfire.provides(self.args.pattern, **self.pakfire_args) |
fa6d335b MT |
335 | |
336 | for pkg in pkgs: | |
337 | print pkg.dump() | |
338 | ||
c1962d40 | 339 | def handle_grouplist(self): |
7c8f2953 | 340 | pkgs = pakfire.grouplist(self.args.group[0], **self.pakfire_args) |
c1962d40 MT |
341 | |
342 | for pkg in pkgs: | |
343 | print " * %s" % pkg | |
344 | ||
ce2764c1 | 345 | def handle_groupinstall(self): |
7c8f2953 | 346 | pakfire.groupinstall(self.args.group[0], **self.pakfire_args) |
ce2764c1 | 347 | |
67bc4528 | 348 | def handle_repolist(self): |
7c8f2953 | 349 | repos = pakfire.repo_list(**self.pakfire_args) |
67bc4528 | 350 | |
c605d735 | 351 | FORMAT = " %-20s %8s %12s %12s " |
67bc4528 | 352 | |
c605d735 | 353 | title = FORMAT % (_("Repository"), _("Enabled"), _("Priority"), _("Packages")) |
67bc4528 MT |
354 | print title |
355 | print "=" * len(title) # spacing line | |
356 | ||
357 | for repo in repos: | |
358 | # Skip the installed repository. | |
359 | if repo.name == "installed": | |
360 | continue | |
361 | ||
c605d735 | 362 | print FORMAT % (repo.name, repo.enabled, repo.priority, len(repo)) |
67bc4528 | 363 | |
31267a64 MT |
364 | def handle_clean_all(self): |
365 | print _("Cleaning up everything...") | |
366 | ||
367 | pakfire.clean_all(**self.pakfire_args) | |
368 | ||
35d89fd7 MT |
369 | def handle_check(self): |
370 | pakfire.check(**self.pakfire_args) | |
371 | ||
b25a3d84 MT |
372 | def handle_resolvdep(self): |
373 | pakfire.resolvdep(self.args.package, **self.pakfire_args) | |
374 | ||
47a4cb89 MT |
375 | |
376 | class CliBuilder(Cli): | |
377 | def __init__(self): | |
936f6b37 MT |
378 | # Check if we are already running in a pakfire container. In that |
379 | # case, we cannot start another pakfire-builder. | |
380 | if os.environ.get("container", None) == "pakfire-builder": | |
381 | raise PakfireContainerError, _("You cannot run pakfire-builder in a pakfire chroot.") | |
382 | ||
47a4cb89 MT |
383 | self.parser = argparse.ArgumentParser( |
384 | description = _("Pakfire builder command line interface."), | |
385 | ) | |
386 | ||
387 | self.parse_common_arguments() | |
388 | ||
389 | # Add sub-commands. | |
390 | self.sub_commands = self.parser.add_subparsers() | |
391 | ||
392 | self.parse_command_build() | |
393 | self.parse_command_dist() | |
394 | self.parse_command_info() | |
395 | self.parse_command_search() | |
396 | self.parse_command_shell() | |
397 | self.parse_command_update() | |
4fbd4216 | 398 | self.parse_command_provides() |
2c84aceb | 399 | self.parse_command_grouplist() |
67bc4528 | 400 | self.parse_command_repolist() |
31267a64 | 401 | self.parse_command_clean() |
b25a3d84 | 402 | self.parse_command_resolvdep() |
3817ae8e | 403 | self.parse_command_cache() |
47a4cb89 MT |
404 | |
405 | # Finally parse all arguments from the command line and save them. | |
406 | self.args = self.parser.parse_args() | |
407 | ||
47a4cb89 | 408 | self.action2func = { |
fa6d335b MT |
409 | "build" : self.handle_build, |
410 | "dist" : self.handle_dist, | |
411 | "update" : self.handle_update, | |
412 | "info" : self.handle_info, | |
413 | "search" : self.handle_search, | |
414 | "shell" : self.handle_shell, | |
4fbd4216 | 415 | "provides" : self.handle_provides, |
2c84aceb | 416 | "grouplist" : self.handle_grouplist, |
67bc4528 | 417 | "repolist" : self.handle_repolist, |
31267a64 | 418 | "clean_all" : self.handle_clean_all, |
b25a3d84 | 419 | "resolvdep" : self.handle_resolvdep, |
3817ae8e MT |
420 | "cache_create": self.handle_cache_create, |
421 | "cache_cleanup": self.handle_cache_cleanup, | |
47a4cb89 MT |
422 | } |
423 | ||
7c8f2953 MT |
424 | @property |
425 | def pakfire_args(self): | |
6557ff4c | 426 | ret = { "mode" : "builder" } |
f9a012a8 MT |
427 | |
428 | if hasattr(self.args, "disable_repo"): | |
429 | ret["disable_repos"] = self.args.disable_repo | |
430 | ||
431 | if hasattr(self.args, "enable_repo"): | |
432 | ret["enable_repos"] = self.args.enable_repo | |
433 | ||
6a509182 MT |
434 | if hasattr(self.args, "offline"): |
435 | ret["offline"] = self.args.offline | |
436 | ||
f9a012a8 | 437 | return ret |
7c8f2953 | 438 | |
47a4cb89 MT |
439 | def parse_command_update(self): |
440 | # Implement the "update" command. | |
441 | sub_update = self.sub_commands.add_parser("update", | |
442 | help=_("Update the package indexes.")) | |
443 | sub_update.add_argument("action", action="store_const", const="update") | |
444 | ||
445 | def parse_command_build(self): | |
446 | # Implement the "build" command. | |
447 | sub_build = self.sub_commands.add_parser("build", | |
448 | help=_("Build one or more packages.")) | |
449 | sub_build.add_argument("package", nargs=1, | |
450 | help=_("Give name of at least one package to build.")) | |
451 | sub_build.add_argument("action", action="store_const", const="build") | |
452 | ||
453 | sub_build.add_argument("-a", "--arch", | |
454 | help=_("Build the package for the given architecture.")) | |
455 | sub_build.add_argument("--resultdir", nargs="?", | |
456 | help=_("Path were the output files should be copied to.")) | |
f22069bb MT |
457 | sub_build.add_argument("-m", "--mode", nargs="?", default="development", |
458 | help=_("Mode to run in. Is either 'release' or 'development' (default).")) | |
1710ccec MT |
459 | sub_build.add_argument("--after-shell", action="store_true", |
460 | help=_("Run a shell after a successful build.")) | |
47a4cb89 MT |
461 | |
462 | def parse_command_shell(self): | |
463 | # Implement the "shell" command. | |
464 | sub_shell = self.sub_commands.add_parser("shell", | |
465 | help=_("Go into a shell.")) | |
042266f3 | 466 | sub_shell.add_argument("package", nargs="?", |
47a4cb89 MT |
467 | help=_("Give name of a package.")) |
468 | sub_shell.add_argument("action", action="store_const", const="shell") | |
469 | ||
470 | sub_shell.add_argument("-a", "--arch", | |
471 | help=_("Emulated architecture in the shell.")) | |
6ee3d6b9 MT |
472 | sub_shell.add_argument("-m", "--mode", nargs="?", default="development", |
473 | help=_("Mode to run in. Is either 'release' or 'development' (default).")) | |
47a4cb89 MT |
474 | |
475 | def parse_command_dist(self): | |
476 | # Implement the "dist" command. | |
477 | sub_dist = self.sub_commands.add_parser("dist", | |
478 | help=_("Generate a source package.")) | |
e412b8dc MT |
479 | sub_dist.add_argument("package", nargs="+", |
480 | help=_("Give name(s) of a package(s).")) | |
47a4cb89 MT |
481 | sub_dist.add_argument("action", action="store_const", const="dist") |
482 | ||
483 | sub_dist.add_argument("--resultdir", nargs="?", | |
484 | help=_("Path were the output files should be copied to.")) | |
485 | ||
3817ae8e MT |
486 | def parse_command_cache(self): |
487 | # Implement the "cache" command. | |
488 | sub_cache = self.sub_commands.add_parser("cache", | |
489 | help=_("Create a build environment cache.")) | |
490 | ||
491 | # Implement subcommands. | |
492 | sub_cache_commands = sub_cache.add_subparsers() | |
493 | ||
494 | self.parse_command_cache_create(sub_cache_commands) | |
495 | self.parse_command_cache_cleanup(sub_cache_commands) | |
496 | ||
497 | def parse_command_cache_create(self, sub_commands): | |
498 | sub_create = sub_commands.add_parser("create", | |
499 | help=_("Create a new build environment cache.")) | |
500 | sub_create.add_argument("action", action="store_const", const="cache_create") | |
501 | ||
502 | def parse_command_cache_cleanup(self, sub_commands): | |
503 | sub_cleanup = sub_commands.add_parser("cleanup", | |
504 | help=_("Remove all cached build environments.")) | |
505 | sub_cleanup.add_argument("action", action="store_const", const="cache_cleanup") | |
506 | ||
9afa5620 MT |
507 | def handle_info(self): |
508 | Cli.handle_info(self, long=True) | |
509 | ||
47a4cb89 | 510 | def handle_build(self): |
47a4cb89 MT |
511 | # Get the package descriptor from the command line options |
512 | pkg = self.args.package[0] | |
513 | ||
514 | # Check, if we got a regular file | |
515 | if os.path.exists(pkg): | |
516 | pkg = os.path.abspath(pkg) | |
517 | ||
47a4cb89 | 518 | else: |
7c8f2953 | 519 | raise FileNotFoundError, pkg |
47a4cb89 | 520 | |
7c8f2953 MT |
521 | # Create distribution configuration from command line. |
522 | distro_config = { | |
523 | "arch" : self.args.arch, | |
524 | } | |
525 | ||
c07a3ca7 MT |
526 | pakfire.build(pkg, builder_mode=self.args.mode, |
527 | distro_config=distro_config, resultdirs=[self.args.resultdir,], | |
1710ccec | 528 | shell=True, after_shell=self.args.after_shell, **self.pakfire_args) |
47a4cb89 MT |
529 | |
530 | def handle_shell(self): | |
042266f3 MT |
531 | pkg = None |
532 | ||
47a4cb89 | 533 | # Get the package descriptor from the command line options |
042266f3 | 534 | if self.args.package: |
ad1b844f | 535 | pkg = self.args.package |
47a4cb89 | 536 | |
7c8f2953 MT |
537 | # Check, if we got a regular file |
538 | if os.path.exists(pkg): | |
539 | pkg = os.path.abspath(pkg) | |
47a4cb89 | 540 | |
7c8f2953 MT |
541 | else: |
542 | raise FileNotFoundError, pkg | |
47a4cb89 | 543 | |
7c8f2953 MT |
544 | # Create distribution configuration from command line. |
545 | distro_config = { | |
546 | "arch" : self.args.arch, | |
547 | } | |
47a4cb89 | 548 | |
6ee3d6b9 MT |
549 | pakfire.shell(pkg, builder_mode=self.args.mode, |
550 | distro_config=distro_config, **self.pakfire_args) | |
47a4cb89 MT |
551 | |
552 | def handle_dist(self): | |
e412b8dc MT |
553 | # Get the packages from the command line options |
554 | pkgs = [] | |
47a4cb89 | 555 | |
e412b8dc MT |
556 | for pkg in self.args.package: |
557 | # Check, if we got a regular file | |
558 | if os.path.exists(pkg): | |
559 | pkg = os.path.abspath(pkg) | |
7c8f2953 | 560 | pkgs.append(pkg) |
47a4cb89 | 561 | |
e412b8dc | 562 | else: |
7c8f2953 MT |
563 | raise FileNotFoundError, pkg |
564 | ||
7d40ac70 MT |
565 | # Put packages to where the user said or our |
566 | # current working directory. | |
567 | resultdir = self.args.resultdir or os.getcwd() | |
568 | ||
569 | # Change the default pakfire configuration, because | |
570 | # packaging source packages can be done in server mode. | |
571 | pakfire_args = self.pakfire_args | |
572 | pakfire_args["mode"] = "server" | |
573 | ||
574 | for pkg in pkgs: | |
575 | pakfire.dist(pkg, resultdir=resultdir, **pakfire_args) | |
47a4cb89 | 576 | |
c605d735 MT |
577 | def handle_provides(self): |
578 | pkgs = pakfire.provides(self.args.pattern, **self.pakfire_args) | |
579 | ||
580 | for pkg in pkgs: | |
581 | print pkg.dump(long=True) | |
582 | ||
3817ae8e MT |
583 | def handle_cache_create(self): |
584 | pakfire.cache_create(**self.pakfire_args) | |
585 | ||
586 | def handle_cache_cleanup(self): | |
587 | for env in os.listdir(CACHE_ENVIRON_DIR): | |
588 | if not env.endswith(".cache"): | |
589 | continue | |
590 | ||
591 | print _("Removing environment cache file: %s..." % env) | |
592 | env = os.path.join(CACHE_ENVIRON_DIR, env) | |
593 | ||
594 | try: | |
595 | os.unlink(env) | |
596 | except OSError: | |
597 | print _("Could not remove file: %s") % env | |
598 | ||
47a4cb89 | 599 | |
3ad4bb5a | 600 | class CliServer(Cli): |
677ff42a MT |
601 | def __init__(self): |
602 | self.parser = argparse.ArgumentParser( | |
3ad4bb5a | 603 | description = _("Pakfire server command line interface."), |
677ff42a MT |
604 | ) |
605 | ||
606 | self.parse_common_arguments() | |
607 | ||
608 | # Add sub-commands. | |
609 | self.sub_commands = self.parser.add_subparsers() | |
610 | ||
a52f536c | 611 | self.parse_command_build() |
677ff42a | 612 | self.parse_command_keepalive() |
8276111d | 613 | self.parse_command_repoupdate() |
df9c4f62 | 614 | self.parse_command_repo() |
aad6f600 | 615 | self.parse_command_info() |
677ff42a MT |
616 | |
617 | # Finally parse all arguments from the command line and save them. | |
618 | self.args = self.parser.parse_args() | |
619 | ||
269c59f3 | 620 | self.server = server.Server(**self.pakfire_args) |
677ff42a MT |
621 | |
622 | self.action2func = { | |
8276111d | 623 | "build" : self.handle_build, |
aad6f600 | 624 | "info" : self.handle_info, |
8276111d MT |
625 | "keepalive" : self.handle_keepalive, |
626 | "repoupdate" : self.handle_repoupdate, | |
df9c4f62 | 627 | "repo_create": self.handle_repo_create, |
677ff42a MT |
628 | } |
629 | ||
6557ff4c MT |
630 | @property |
631 | def pakfire_args(self): | |
632 | ret = { "mode" : "server" } | |
633 | ||
6a509182 MT |
634 | if hasattr(self.args, "offline"): |
635 | ret["offline"] = self.args.offline | |
636 | ||
6557ff4c MT |
637 | return ret |
638 | ||
a52f536c MT |
639 | def parse_command_build(self): |
640 | # Implement the "build" command. | |
c62d93f1 MT |
641 | sub_build = self.sub_commands.add_parser("build", |
642 | help=_("Send a scrach build job to the server.")) | |
643 | sub_build.add_argument("package", nargs=1, | |
644 | help=_("Give name of at least one package to build.")) | |
645 | sub_build.add_argument("--arch", "-a", | |
646 | help=_("Limit build to only these architecture(s).")) | |
647 | sub_build.add_argument("action", action="store_const", const="build") | |
a52f536c | 648 | |
677ff42a MT |
649 | def parse_command_keepalive(self): |
650 | # Implement the "keepalive" command. | |
651 | sub_keepalive = self.sub_commands.add_parser("keepalive", | |
652 | help=_("Send a keepalive to the server.")) | |
653 | sub_keepalive.add_argument("action", action="store_const", | |
654 | const="keepalive") | |
655 | ||
8276111d MT |
656 | def parse_command_repoupdate(self): |
657 | # Implement the "repoupdate" command. | |
658 | sub_repoupdate = self.sub_commands.add_parser("repoupdate", | |
659 | help=_("Update all repositories.")) | |
660 | sub_repoupdate.add_argument("action", action="store_const", | |
661 | const="repoupdate") | |
662 | ||
df9c4f62 MT |
663 | def parse_command_repo(self): |
664 | sub_repo = self.sub_commands.add_parser("repo", | |
665 | help=_("Repository management commands.")) | |
666 | ||
667 | sub_repo_commands = sub_repo.add_subparsers() | |
668 | ||
669 | self.parse_command_repo_create(sub_repo_commands) | |
670 | ||
671 | def parse_command_repo_create(self, sub_commands): | |
672 | sub_create = sub_commands.add_parser("create", | |
673 | help=_("Create a new repository index.")) | |
674 | sub_create.add_argument("path", nargs=1, help=_("Path to the packages.")) | |
675 | sub_create.add_argument("inputs", nargs="+", help=_("Path to input packages.")) | |
676 | sub_create.add_argument("action", action="store_const", const="repo_create") | |
677 | ||
aad6f600 MT |
678 | def parse_command_info(self): |
679 | sub_info = self.sub_commands.add_parser("info", | |
680 | help=_("Dump some information about this machine.")) | |
681 | sub_info.add_argument("action", action="store_const", const="info") | |
682 | ||
677ff42a | 683 | def handle_keepalive(self): |
3ad4bb5a | 684 | self.server.update_info() |
9613a111 | 685 | |
a52f536c | 686 | def handle_build(self): |
c62d93f1 MT |
687 | # Arch. |
688 | if self.args.arch: | |
689 | arches = self.args.arch.split() | |
690 | ||
691 | (package,) = self.args.package | |
692 | ||
693 | self.server.create_scratch_build({}) | |
694 | return | |
695 | ||
696 | # Temporary folter for source package. | |
697 | tmpdir = "/tmp/pakfire-%s" % util.random_string() | |
698 | ||
699 | try: | |
700 | os.makedirs(tmpdir) | |
701 | ||
702 | pakfire.dist(package, resultdir=[tmpdir,]) | |
703 | ||
704 | for file in os.listdir(tmpdir): | |
705 | file = os.path.join(tmpdir, file) | |
706 | ||
707 | print file | |
708 | ||
709 | finally: | |
710 | if os.path.exists(tmpdir): | |
711 | util.rm(tmpdir) | |
8276111d MT |
712 | |
713 | def handle_repoupdate(self): | |
714 | self.server.update_repositories() | |
df9c4f62 MT |
715 | |
716 | def handle_repo_create(self): | |
717 | path = self.args.path[0] | |
718 | ||
719 | pakfire.repo_create(path, self.args.inputs, **self.pakfire_args) | |
c07a3ca7 | 720 | |
aad6f600 MT |
721 | def handle_info(self): |
722 | info = self.server.info() | |
723 | ||
724 | print "\n".join(info) | |
725 | ||
c07a3ca7 | 726 | |
9b875540 | 727 | class CliBuilderIntern(Cli): |
c07a3ca7 MT |
728 | def __init__(self): |
729 | self.parser = argparse.ArgumentParser( | |
730 | description = _("Pakfire builder command line interface."), | |
731 | ) | |
732 | ||
733 | self.parse_common_arguments() | |
734 | ||
735 | # Add sub-commands. | |
736 | self.sub_commands = self.parser.add_subparsers() | |
737 | ||
738 | self.parse_command_build() | |
739 | ||
740 | # Finally parse all arguments from the command line and save them. | |
741 | self.args = self.parser.parse_args() | |
742 | ||
743 | self.action2func = { | |
744 | "build" : self.handle_build, | |
745 | } | |
746 | ||
747 | def parse_command_build(self): | |
748 | # Implement the "build" command. | |
749 | sub_build = self.sub_commands.add_parser("build", | |
750 | help=_("Build one or more packages.")) | |
751 | sub_build.add_argument("package", nargs=1, | |
752 | help=_("Give name of at least one package to build.")) | |
753 | sub_build.add_argument("action", action="store_const", const="build") | |
754 | ||
755 | sub_build.add_argument("-a", "--arch", | |
756 | help=_("Build the package for the given architecture.")) | |
757 | sub_build.add_argument("--resultdir", nargs="?", | |
758 | help=_("Path were the output files should be copied to.")) | |
759 | sub_build.add_argument("-m", "--mode", nargs="?", default="development", | |
760 | help=_("Mode to run in. Is either 'release' or 'development' (default).")) | |
761 | sub_build.add_argument("--nodeps", action="store_true", | |
762 | help=_("Do not verify build dependencies.")) | |
763 | ||
764 | def handle_build(self): | |
765 | # Get the package descriptor from the command line options | |
766 | pkg = self.args.package[0] | |
767 | ||
768 | # Check, if we got a regular file | |
769 | if os.path.exists(pkg): | |
770 | pkg = os.path.abspath(pkg) | |
771 | else: | |
772 | raise FileNotFoundError, pkg | |
773 | ||
774 | # Create distribution configuration from command line. | |
775 | distro_config = { | |
776 | "arch" : self.args.arch, | |
777 | } | |
778 | ||
779 | pakfire._build(pkg, builder_mode=self.args.mode, | |
c62d93f1 MT |
780 | distro_config=distro_config, resultdir=self.args.resultdir,) |
781 | ||
782 | ||
783 | class CliClient(Cli): | |
784 | def __init__(self): | |
785 | self.parser = argparse.ArgumentParser( | |
786 | description = _("Pakfire client command line interface."), | |
787 | ) | |
788 | ||
789 | self.parse_common_arguments(repo_manage_switches=True, offline_switch=True) | |
790 | ||
791 | # Add sub-commands. | |
792 | self.sub_commands = self.parser.add_subparsers() | |
793 | ||
794 | self.parse_command_build() | |
795 | self.parse_command_connection_check() | |
796 | self.parse_command_info() | |
797 | ||
798 | # Finally parse all arguments from the command line and save them. | |
799 | self.args = self.parser.parse_args() | |
800 | ||
801 | self.action2func = { | |
802 | "build" : self.handle_build, | |
803 | "conn-check" : self.handle_connection_check, | |
804 | "info" : self.handle_info, | |
805 | } | |
806 | ||
807 | # Read configuration for the pakfire client. | |
808 | self.conf = conf = config.ConfigClient() | |
809 | ||
810 | # Create connection to pakfire hub. | |
811 | self.client = client.PakfireUserClient( | |
812 | conf.get("client", "server"), | |
813 | conf.get("client", "username"), | |
814 | conf.get("client", "password"), | |
815 | ) | |
816 | ||
817 | def parse_command_build(self): | |
818 | # Parse "build" command. | |
819 | sub_build = self.sub_commands.add_parser("build", | |
820 | help=_("Build a package remotely.")) | |
821 | sub_build.add_argument("package", nargs=1, | |
822 | help=_("Give name of a package to build.")) | |
823 | sub_build.add_argument("action", action="store_const", const="build") | |
824 | ||
825 | sub_build.add_argument("-a", "--arch", | |
826 | help=_("Build the package for the given architecture.")) | |
827 | ||
828 | def parse_command_info(self): | |
829 | # Implement the "info" command. | |
830 | sub_info = self.sub_commands.add_parser("info", | |
831 | help=_("Print some information about this host.")) | |
832 | sub_info.add_argument("action", action="store_const", const="info") | |
833 | ||
834 | def parse_command_connection_check(self): | |
835 | # Implement the "conn-check" command. | |
836 | sub_conn_check = self.sub_commands.add_parser("conn-check", | |
837 | help=_("Check the connection to the hub.")) | |
838 | sub_conn_check.add_argument("action", action="store_const", const="conn-check") | |
839 | ||
840 | def handle_build(self): | |
841 | (package,) = self.args.package | |
842 | ||
843 | # XXX just for now, we do only upload source pfm files. | |
844 | assert os.path.exists(package) | |
845 | ||
b913e798 MT |
846 | # Create a temporary directory. |
847 | temp_dir = tempfile.mkdtemp() | |
848 | ||
849 | try: | |
850 | if package.endswith(".%s" % MAKEFILE_EXTENSION): | |
851 | pakfire_args = { "mode" : "server" } | |
852 | ||
853 | # Create a source package from the makefile. | |
854 | package = pakfire.dist(package, temp_dir, **pakfire_args) | |
855 | ||
856 | elif package.endswith(".%s" % PACKAGE_EXTENSION): | |
857 | pass | |
c62d93f1 | 858 | |
b913e798 MT |
859 | else: |
860 | raise Exception, "Unknown filetype: %s" % package | |
861 | ||
862 | # Format arches. | |
863 | if self.args.arch: | |
864 | arches = self.args.arch.replace(",", " ") | |
865 | else: | |
866 | arches = None | |
c62d93f1 | 867 | |
b913e798 MT |
868 | # Create a new build on the server. |
869 | build = self.client.build_create(package, arches=arches) | |
870 | ||
871 | # XXX Print the resulting build. | |
872 | print build | |
873 | ||
874 | finally: | |
875 | # Cleanup the temporary directory and all files. | |
876 | if os.path.exists(temp_dir): | |
877 | shutil.rmtree(temp_dir, ignore_errors=True) | |
c62d93f1 MT |
878 | |
879 | def handle_info(self): | |
880 | ret = [] | |
881 | ||
882 | ret.append("") | |
883 | ret.append(" PAKFIRE %s" % PAKFIRE_VERSION) | |
884 | ret.append("") | |
885 | ret.append(" %-20s: %s" % (_("Hostname"), system.hostname)) | |
886 | ret.append(" %-20s: %s" % (_("Pakfire hub"), self.conf.get("client", "server"))) | |
887 | if self.conf.get("client", "username") and self.conf.get("client", "password"): | |
888 | ret.append(" %-20s: %s" % \ | |
889 | (_("Username"), self.conf.get("client", "username"))) | |
890 | ret.append("") | |
891 | ||
892 | # Hardware information | |
893 | ret.append(" %s:" % _("Hardware information")) | |
894 | ret.append(" %-16s: %s" % (_("CPU model"), system.cpu_model)) | |
895 | ret.append(" %-16s: %s" % (_("Memory"), util.format_size(system.memory))) | |
896 | ret.append("") | |
790a44cc MT |
897 | ret.append(" %-16s: %s" % (_("Native arch"), system.native_arch)) |
898 | if not system.arch == system.native_arch: | |
899 | ret.append(" %-16s: %s" % (_("Default arch"), system.arch)) | |
c62d93f1 MT |
900 | |
901 | header = _("Supported arches") | |
902 | for arch in system.supported_arches: | |
903 | ret.append(" %-16s: %s" % (header, arch)) | |
904 | header = "" | |
905 | ret.append("") | |
906 | ||
907 | for line in ret: | |
908 | print line | |
909 | ||
910 | def handle_connection_check(self): | |
911 | ret = [] | |
912 | ||
913 | address = self.client.get_my_address() | |
914 | ret.append(" %-20s: %s" % (_("Your IP address"), address)) | |
915 | ret.append("") | |
916 | ||
917 | authenticated = self.client.check_auth() | |
918 | if authenticated: | |
919 | ret.append(" %s" % _("You are authenticated to the build service:")) | |
920 | ||
921 | user = self.client.get_user_profile() | |
922 | assert user, "Could not fetch user infomation" | |
923 | ||
924 | keys = [ | |
925 | ("name", _("User name")), | |
926 | ("realname", _("Real name")), | |
927 | ("email", _("Email address")), | |
928 | ("registered", _("Registered")), | |
929 | ] | |
930 | ||
931 | for key, desc in keys: | |
932 | ret.append(" %-18s: %s" % (desc, user.get(key))) | |
933 | ||
934 | else: | |
935 | ret.append(_("You could not be authenticated to the build service.")) | |
936 | ||
937 | for line in ret: | |
938 | print line | |
939 | ||
940 | ||
941 | class CliDaemon(Cli): | |
942 | def __init__(self): | |
943 | self.parser = argparse.ArgumentParser( | |
944 | description = _("Pakfire daemon command line interface."), | |
945 | ) | |
946 | ||
947 | self.parse_common_arguments(repo_manage_switches=True, offline_switch=True) | |
948 | ||
949 | # Finally parse all arguments from the command line and save them. | |
950 | self.args = self.parser.parse_args() | |
951 | ||
952 | def run(self): | |
953 | """ | |
954 | Runs the pakfire daemon with provided settings. | |
955 | """ | |
956 | # Read the configuration file for the daemon. | |
957 | conf = config.ConfigDaemon() | |
958 | ||
959 | # Create daemon instance. | |
960 | d = pakfire.client.PakfireDaemon( | |
961 | server = conf.get("daemon", "server"), | |
962 | hostname = conf.get("daemon", "hostname"), | |
963 | secret = conf.get("daemon", "secret"), | |
964 | ) | |
965 | ||
966 | try: | |
967 | d.run() | |
968 | ||
969 | # We cannot just kill the daemon, it needs a smooth shutdown. | |
970 | except (SystemExit, KeyboardInterrupt): | |
971 | d.shutdown() |