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