]> git.ipfire.org Git - people/stevee/pakfire.git/blob - python/pakfire/cli.py
Add option to delete keys from keyring.
[people/stevee/pakfire.git] / python / pakfire / cli.py
1 #!/usr/bin/python
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 ###############################################################################
21
22 import argparse
23 import datetime
24 import os
25 import sys
26
27 import pakfire.api as pakfire
28
29 import client
30 import config
31 import logger
32 import packages
33 import repository
34 import server
35 import util
36
37 from system import system
38 from constants import *
39 from i18n import _
40
41 # Initialize a very simple logging that is removed when a Pakfire instance
42 # is started.
43 logger.setup_logging()
44
45 class Cli(object):
46 def __init__(self):
47 self.parser = argparse.ArgumentParser(
48 description = _("Pakfire command line interface."),
49 )
50
51 self.parse_common_arguments()
52
53 self.parser.add_argument("--root", metavar="PATH",
54 default="/",
55 help=_("The path where pakfire should operate in."))
56
57 # Add sub-commands.
58 self.sub_commands = self.parser.add_subparsers()
59
60 self.parse_command_install()
61 self.parse_command_localinstall()
62 self.parse_command_reinstall()
63 self.parse_command_remove()
64 self.parse_command_info()
65 self.parse_command_search()
66 self.parse_command_check_update()
67 self.parse_command_update()
68 self.parse_command_downgrade()
69 self.parse_command_provides()
70 self.parse_command_grouplist()
71 self.parse_command_groupinstall()
72 self.parse_command_repolist()
73 self.parse_command_clean()
74 self.parse_command_check()
75 self.parse_command_resolvdep()
76
77 # Finally parse all arguments from the command line and save them.
78 self.args = self.parser.parse_args()
79
80 self.action2func = {
81 "install" : self.handle_install,
82 "localinstall" : self.handle_localinstall,
83 "reinstall" : self.handle_reinstall,
84 "remove" : self.handle_remove,
85 "check_update" : self.handle_check_update,
86 "update" : self.handle_update,
87 "downgrade" : self.handle_downgrade,
88 "info" : self.handle_info,
89 "search" : self.handle_search,
90 "provides" : self.handle_provides,
91 "grouplist" : self.handle_grouplist,
92 "groupinstall" : self.handle_groupinstall,
93 "repolist" : self.handle_repolist,
94 "clean_all" : self.handle_clean_all,
95 "check" : self.handle_check,
96 "resolvdep" : self.handle_resolvdep,
97 }
98
99 @property
100 def pakfire_args(self):
101 ret = { "mode" : "normal" }
102
103 if hasattr(self.args, "root"):
104 ret["path"] = self.args.root
105
106 if hasattr(self.args, "disable_repo"):
107 ret["disable_repos"] = self.args.disable_repo
108
109 if hasattr(self.args, "enable_repo"):
110 ret["enable_repos"] = self.args.enable_repo
111
112 if hasattr(self.args, "offline"):
113 ret["offline"] = self.args.offline
114
115 return ret
116
117 def parse_common_arguments(self, repo_manage_switches=True, offline_switch=True):
118 self.parser.add_argument("--version", action="version",
119 version="%(prog)s " + PAKFIRE_VERSION)
120
121 self.parser.add_argument("-v", "--verbose", action="store_true",
122 help=_("Enable verbose output."))
123
124 self.parser.add_argument("-c", "--config", nargs="?",
125 help=_("Path to a configuration file to load."))
126
127 if repo_manage_switches:
128 self.parser.add_argument("--disable-repo", nargs="*", metavar="REPO",
129 help=_("Disable a repository temporarily."))
130
131 self.parser.add_argument("--enabled-repo", nargs="*", metavar="REPO",
132 help=_("Enable a repository temporarily."))
133
134 if offline_switch:
135 self.parser.add_argument("--offline", action="store_true",
136 help=_("Run pakfire in offline mode."))
137
138 def parse_command_install(self):
139 # Implement the "install" command.
140 sub_install = self.sub_commands.add_parser("install",
141 help=_("Install one or more packages to the system."))
142 sub_install.add_argument("package", nargs="+",
143 help=_("Give name of at least one package to install."))
144 sub_install.add_argument("action", action="store_const", const="install")
145
146 def parse_command_localinstall(self):
147 # Implement the "localinstall" command.
148 sub_install = self.sub_commands.add_parser("localinstall",
149 help=_("Install one or more packages from the filesystem."))
150 sub_install.add_argument("package", nargs="+",
151 help=_("Give filename of at least one package."))
152 sub_install.add_argument("action", action="store_const", const="localinstall")
153
154 def parse_command_reinstall(self):
155 # Implement the "reinstall" command.
156 sub_install = self.sub_commands.add_parser("reinstall",
157 help=_("Reinstall one or more packages."))
158 sub_install.add_argument("package", nargs="+",
159 help=_("Give name of at least one package to reinstall."))
160 sub_install.add_argument("action", action="store_const", const="reinstall")
161
162 def parse_command_remove(self):
163 # Implement the "remove" command.
164 sub_remove = self.sub_commands.add_parser("remove",
165 help=_("Remove one or more packages from the system."))
166 sub_remove.add_argument("package", nargs="+",
167 help=_("Give name of at least one package to remove."))
168 sub_remove.add_argument("action", action="store_const", const="remove")
169
170 @staticmethod
171 def _parse_command_update(parser):
172 parser.add_argument("package", nargs="*",
173 help=_("Give a name of a package to update or leave emtpy for all."))
174 parser.add_argument("--exclude", "-x", nargs="+",
175 help=_("Exclude package from update."))
176 parser.add_argument("--allow-vendorchange", action="store_true",
177 help=_("Allow changing the vendor of packages."))
178 parser.add_argument("--allow-archchange", action="store_true",
179 help=_("Allow changing the architecture of packages."))
180
181 def parse_command_update(self):
182 # Implement the "update" command.
183 sub_update = self.sub_commands.add_parser("update",
184 help=_("Update the whole system or one specific package."))
185 sub_update.add_argument("action", action="store_const", const="update")
186 self._parse_command_update(sub_update)
187
188 def parse_command_check_update(self):
189 # Implement the "check-update" command.
190 sub_check_update = self.sub_commands.add_parser("check-update",
191 help=_("Check, if there are any updates available."))
192 sub_check_update.add_argument("action", action="store_const", const="check_update")
193 self._parse_command_update(sub_check_update)
194
195 def parse_command_downgrade(self):
196 # Implement the "downgrade" command.
197 sub_downgrade = self.sub_commands.add_parser("downgrade",
198 help=_("Downgrade one or more packages."))
199 sub_downgrade.add_argument("package", nargs="*",
200 help=_("Give a name of a package to downgrade."))
201 sub_downgrade.add_argument("--allow-vendorchange", action="store_true",
202 help=_("Allow changing the vendor of packages."))
203 sub_downgrade.add_argument("--allow-archchange", action="store_true",
204 help=_("Allow changing the architecture of packages."))
205 sub_downgrade.add_argument("action", action="store_const", const="downgrade")
206
207 def parse_command_info(self):
208 # Implement the "info" command.
209 sub_info = self.sub_commands.add_parser("info",
210 help=_("Print some information about the given package(s)."))
211 sub_info.add_argument("package", nargs="+",
212 help=_("Give at least the name of one package."))
213 sub_info.add_argument("action", action="store_const", const="info")
214
215 def parse_command_search(self):
216 # Implement the "search" command.
217 sub_search = self.sub_commands.add_parser("search",
218 help=_("Search for a given pattern."))
219 sub_search.add_argument("pattern",
220 help=_("A pattern to search for."))
221 sub_search.add_argument("action", action="store_const", const="search")
222
223 def parse_command_provides(self):
224 # Implement the "provides" command
225 sub_provides = self.sub_commands.add_parser("provides",
226 help=_("Get a list of packages that provide a given file or feature."))
227 sub_provides.add_argument("pattern", nargs="+",
228 help=_("File or feature to search for."))
229 sub_provides.add_argument("action", action="store_const", const="provides")
230
231 def parse_command_grouplist(self):
232 # Implement the "grouplist" command
233 sub_grouplist = self.sub_commands.add_parser("grouplist",
234 help=_("Get list of packages that belong to the given group."))
235 sub_grouplist.add_argument("group", nargs=1,
236 help=_("Group name to search for."))
237 sub_grouplist.add_argument("action", action="store_const", const="grouplist")
238
239 def parse_command_groupinstall(self):
240 # Implement the "grouplist" command
241 sub_groupinstall = self.sub_commands.add_parser("groupinstall",
242 help=_("Install all packages that belong to the given group."))
243 sub_groupinstall.add_argument("group", nargs=1,
244 help=_("Group name."))
245 sub_groupinstall.add_argument("action", action="store_const", const="groupinstall")
246
247 def parse_command_repolist(self):
248 # Implement the "repolist" command
249 sub_repolist = self.sub_commands.add_parser("repolist",
250 help=_("List all currently enabled repositories."))
251 sub_repolist.add_argument("action", action="store_const", const="repolist")
252
253 def parse_command_clean(self):
254 sub_clean = self.sub_commands.add_parser("clean", help=_("Cleanup commands."))
255
256 sub_clean_commands = sub_clean.add_subparsers()
257
258 self.parse_command_clean_all(sub_clean_commands)
259
260 def parse_command_clean_all(self, sub_commands):
261 sub_create = sub_commands.add_parser("all",
262 help=_("Cleanup all temporary files."))
263 sub_create.add_argument("action", action="store_const", const="clean_all")
264
265 def parse_command_check(self):
266 # Implement the "check" command
267 sub_check = self.sub_commands.add_parser("check",
268 help=_("Check the system for any errors."))
269 sub_check.add_argument("action", action="store_const", const="check")
270
271 def parse_command_resolvdep(self):
272 # Implement the "resolvdep" command.
273 sub_resolvdep = self.sub_commands.add_parser("resolvdep",
274 help=_("Check the dependencies for a particular package."))
275 sub_resolvdep.add_argument("package", nargs="+",
276 help=_("Give name of at least one package to check."))
277 sub_resolvdep.add_argument("action", action="store_const", const="resolvdep")
278
279 def run(self):
280 action = self.args.action
281
282 try:
283 func = self.action2func[action]
284 except KeyError:
285 raise Exception, "Unhandled action: %s" % action
286
287 return func()
288
289 def handle_info(self, long=False):
290 pkgs = pakfire.info(self.args.package, **self.pakfire_args)
291
292 for pkg in pkgs:
293 print pkg.dump(long=long)
294
295 def handle_search(self):
296 pkgs = pakfire.search(self.args.pattern, **self.pakfire_args)
297
298 for pkg in pkgs:
299 print pkg.dump(short=True)
300
301 def handle_update(self, **args):
302 args.update(self.pakfire_args)
303
304 pakfire.update(self.args.package, excludes=self.args.exclude,
305 allow_vendorchange=self.args.allow_vendorchange,
306 allow_archchange=self.args.allow_archchange,
307 **args)
308
309 def handle_check_update(self):
310 self.handle_update(check=True)
311
312 def handle_downgrade(self, **args):
313 args.update(self.pakfire_args)
314
315 pakfire.downgrade(self.args.package,
316 allow_vendorchange=self.args.allow_vendorchange,
317 allow_archchange=self.args.allow_archchange,
318 **args)
319
320 def handle_install(self):
321 pakfire.install(self.args.package, **self.pakfire_args)
322
323 def handle_localinstall(self):
324 pakfire.localinstall(self.args.package, **self.pakfire_args)
325
326 def handle_reinstall(self):
327 pakfire.reinstall(self.args.package, **self.pakfire_args)
328
329 def handle_remove(self):
330 pakfire.remove(self.args.package, **self.pakfire_args)
331
332 def handle_provides(self):
333 pkgs = pakfire.provides(self.args.pattern, **self.pakfire_args)
334
335 for pkg in pkgs:
336 print pkg.dump()
337
338 def handle_grouplist(self):
339 pkgs = pakfire.grouplist(self.args.group[0], **self.pakfire_args)
340
341 for pkg in pkgs:
342 print " * %s" % pkg
343
344 def handle_groupinstall(self):
345 pakfire.groupinstall(self.args.group[0], **self.pakfire_args)
346
347 def handle_repolist(self):
348 repos = pakfire.repo_list(**self.pakfire_args)
349
350 FORMAT = " %-20s %8s %12s %12s "
351
352 title = FORMAT % (_("Repository"), _("Enabled"), _("Priority"), _("Packages"))
353 print title
354 print "=" * len(title) # spacing line
355
356 for repo in repos:
357 # Skip the installed repository.
358 if repo.name == "installed":
359 continue
360
361 print FORMAT % (repo.name, repo.enabled, repo.priority, len(repo))
362
363 def handle_clean_all(self):
364 print _("Cleaning up everything...")
365
366 pakfire.clean_all(**self.pakfire_args)
367
368 def handle_check(self):
369 pakfire.check(**self.pakfire_args)
370
371 def handle_resolvdep(self):
372 pakfire.resolvdep(self.args.package, **self.pakfire_args)
373
374
375 class CliBuilder(Cli):
376 def __init__(self):
377 # Check if we are already running in a pakfire container. In that
378 # case, we cannot start another pakfire-builder.
379 if os.environ.get("container", None) == "pakfire-builder":
380 raise PakfireContainerError, _("You cannot run pakfire-builder in a pakfire chroot.")
381
382 self.parser = argparse.ArgumentParser(
383 description = _("Pakfire builder command line interface."),
384 )
385
386 self.parse_common_arguments()
387
388 # Add sub-commands.
389 self.sub_commands = self.parser.add_subparsers()
390
391 self.parse_command_build()
392 self.parse_command_dist()
393 self.parse_command_info()
394 self.parse_command_search()
395 self.parse_command_shell()
396 self.parse_command_update()
397 self.parse_command_provides()
398 self.parse_command_grouplist()
399 self.parse_command_repolist()
400 self.parse_command_clean()
401 self.parse_command_resolvdep()
402 self.parse_command_cache()
403
404 # Finally parse all arguments from the command line and save them.
405 self.args = self.parser.parse_args()
406
407 self.action2func = {
408 "build" : self.handle_build,
409 "dist" : self.handle_dist,
410 "update" : self.handle_update,
411 "info" : self.handle_info,
412 "search" : self.handle_search,
413 "shell" : self.handle_shell,
414 "provides" : self.handle_provides,
415 "grouplist" : self.handle_grouplist,
416 "repolist" : self.handle_repolist,
417 "clean_all" : self.handle_clean_all,
418 "resolvdep" : self.handle_resolvdep,
419 "cache_create": self.handle_cache_create,
420 "cache_cleanup": self.handle_cache_cleanup,
421 }
422
423 @property
424 def pakfire_args(self):
425 ret = { "mode" : "builder" }
426
427 if hasattr(self.args, "disable_repo"):
428 ret["disable_repos"] = self.args.disable_repo
429
430 if hasattr(self.args, "enable_repo"):
431 ret["enable_repos"] = self.args.enable_repo
432
433 if hasattr(self.args, "offline"):
434 ret["offline"] = self.args.offline
435
436 return ret
437
438 def parse_command_update(self):
439 # Implement the "update" command.
440 sub_update = self.sub_commands.add_parser("update",
441 help=_("Update the package indexes."))
442 sub_update.add_argument("action", action="store_const", const="update")
443
444 def parse_command_build(self):
445 # Implement the "build" command.
446 sub_build = self.sub_commands.add_parser("build",
447 help=_("Build one or more packages."))
448 sub_build.add_argument("package", nargs=1,
449 help=_("Give name of at least one package to build."))
450 sub_build.add_argument("action", action="store_const", const="build")
451
452 sub_build.add_argument("-a", "--arch",
453 help=_("Build the package for the given architecture."))
454 sub_build.add_argument("--resultdir", nargs="?",
455 help=_("Path were the output files should be copied to."))
456 sub_build.add_argument("-m", "--mode", nargs="?", default="development",
457 help=_("Mode to run in. Is either 'release' or 'development' (default)."))
458 sub_build.add_argument("--after-shell", action="store_true",
459 help=_("Run a shell after a successful build."))
460
461 def parse_command_shell(self):
462 # Implement the "shell" command.
463 sub_shell = self.sub_commands.add_parser("shell",
464 help=_("Go into a shell."))
465 sub_shell.add_argument("package", nargs="?",
466 help=_("Give name of a package."))
467 sub_shell.add_argument("action", action="store_const", const="shell")
468
469 sub_shell.add_argument("-a", "--arch",
470 help=_("Emulated architecture in the shell."))
471 sub_shell.add_argument("-m", "--mode", nargs="?", default="development",
472 help=_("Mode to run in. Is either 'release' or 'development' (default)."))
473
474 def parse_command_dist(self):
475 # Implement the "dist" command.
476 sub_dist = self.sub_commands.add_parser("dist",
477 help=_("Generate a source package."))
478 sub_dist.add_argument("package", nargs="+",
479 help=_("Give name(s) of a package(s)."))
480 sub_dist.add_argument("action", action="store_const", const="dist")
481
482 sub_dist.add_argument("--resultdir", nargs="?",
483 help=_("Path were the output files should be copied to."))
484
485
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
507 def handle_info(self):
508 Cli.handle_info(self, long=True)
509
510 def handle_build(self):
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
518 else:
519 raise FileNotFoundError, pkg
520
521 # Create distribution configuration from command line.
522 distro_config = {
523 "arch" : self.args.arch,
524 }
525
526 pakfire.build(pkg, builder_mode=self.args.mode,
527 distro_config=distro_config, resultdirs=[self.args.resultdir,],
528 shell=True, after_shell=self.args.after_shell, **self.pakfire_args)
529
530 def handle_shell(self):
531 pkg = None
532
533 # Get the package descriptor from the command line options
534 if self.args.package:
535 pkg = self.args.package
536
537 # Check, if we got a regular file
538 if os.path.exists(pkg):
539 pkg = os.path.abspath(pkg)
540
541 else:
542 raise FileNotFoundError, pkg
543
544 # Create distribution configuration from command line.
545 distro_config = {
546 "arch" : self.args.arch,
547 }
548
549 pakfire.shell(pkg, builder_mode=self.args.mode,
550 distro_config=distro_config, **self.pakfire_args)
551
552 def handle_dist(self):
553 # Get the packages from the command line options
554 pkgs = []
555
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)
560 pkgs.append(pkg)
561
562 else:
563 raise FileNotFoundError, pkg
564
565 pakfire.dist(pkgs, resultdirs=[self.args.resultdir,],
566 **self.pakfire_args)
567
568 def handle_provides(self):
569 pkgs = pakfire.provides(self.args.pattern, **self.pakfire_args)
570
571 for pkg in pkgs:
572 print pkg.dump(long=True)
573
574 def handle_cache_create(self):
575 pakfire.cache_create(**self.pakfire_args)
576
577 def handle_cache_cleanup(self):
578 for env in os.listdir(CACHE_ENVIRON_DIR):
579 if not env.endswith(".cache"):
580 continue
581
582 print _("Removing environment cache file: %s..." % env)
583 env = os.path.join(CACHE_ENVIRON_DIR, env)
584
585 try:
586 os.unlink(env)
587 except OSError:
588 print _("Could not remove file: %s") % env
589
590
591 class CliServer(Cli):
592 def __init__(self):
593 self.parser = argparse.ArgumentParser(
594 description = _("Pakfire server command line interface."),
595 )
596
597 self.parse_common_arguments()
598
599 # Add sub-commands.
600 self.sub_commands = self.parser.add_subparsers()
601
602 self.parse_command_build()
603 self.parse_command_keepalive()
604 self.parse_command_repoupdate()
605 self.parse_command_repo()
606 self.parse_command_info()
607
608 # Finally parse all arguments from the command line and save them.
609 self.args = self.parser.parse_args()
610
611 self.server = server.Server(**self.pakfire_args)
612
613 self.action2func = {
614 "build" : self.handle_build,
615 "info" : self.handle_info,
616 "keepalive" : self.handle_keepalive,
617 "repoupdate" : self.handle_repoupdate,
618 "repo_create": self.handle_repo_create,
619 }
620
621 @property
622 def pakfire_args(self):
623 ret = { "mode" : "server" }
624
625 if hasattr(self.args, "offline"):
626 ret["offline"] = self.args.offline
627
628 return ret
629
630 def parse_command_build(self):
631 # Implement the "build" command.
632 sub_build = self.sub_commands.add_parser("build",
633 help=_("Send a scrach build job to the server."))
634 sub_build.add_argument("package", nargs=1,
635 help=_("Give name of at least one package to build."))
636 sub_build.add_argument("--arch", "-a",
637 help=_("Limit build to only these architecture(s)."))
638 sub_build.add_argument("action", action="store_const", const="build")
639
640 def parse_command_keepalive(self):
641 # Implement the "keepalive" command.
642 sub_keepalive = self.sub_commands.add_parser("keepalive",
643 help=_("Send a keepalive to the server."))
644 sub_keepalive.add_argument("action", action="store_const",
645 const="keepalive")
646
647 def parse_command_repoupdate(self):
648 # Implement the "repoupdate" command.
649 sub_repoupdate = self.sub_commands.add_parser("repoupdate",
650 help=_("Update all repositories."))
651 sub_repoupdate.add_argument("action", action="store_const",
652 const="repoupdate")
653
654 def parse_command_repo(self):
655 sub_repo = self.sub_commands.add_parser("repo",
656 help=_("Repository management commands."))
657
658 sub_repo_commands = sub_repo.add_subparsers()
659
660 self.parse_command_repo_create(sub_repo_commands)
661
662 def parse_command_repo_create(self, sub_commands):
663 sub_create = sub_commands.add_parser("create",
664 help=_("Create a new repository index."))
665 sub_create.add_argument("path", nargs=1,
666 help=_("Path to the packages."))
667 sub_create.add_argument("inputs", nargs="+",
668 help=_("Path to input packages."))
669 sub_create.add_argument("--key", "-k", nargs="?",
670 help=_("Key to sign the repository with."))
671 sub_create.add_argument("action", action="store_const", const="repo_create")
672
673 def parse_command_info(self):
674 sub_info = self.sub_commands.add_parser("info",
675 help=_("Dump some information about this machine."))
676 sub_info.add_argument("action", action="store_const", const="info")
677
678 def handle_keepalive(self):
679 self.server.update_info()
680
681 def handle_build(self):
682 # Arch.
683 if self.args.arch:
684 arches = self.args.arch.split()
685
686 (package,) = self.args.package
687
688 self.server.create_scratch_build({})
689 return
690
691 # Temporary folter for source package.
692 tmpdir = "/tmp/pakfire-%s" % util.random_string()
693
694 try:
695 os.makedirs(tmpdir)
696
697 pakfire.dist(package, resultdir=[tmpdir,])
698
699 for file in os.listdir(tmpdir):
700 file = os.path.join(tmpdir, file)
701
702 print file
703
704 finally:
705 if os.path.exists(tmpdir):
706 util.rm(tmpdir)
707
708 def handle_repoupdate(self):
709 self.server.update_repositories()
710
711 def handle_repo_create(self):
712 path = self.args.path[0]
713
714 pakfire.repo_create(path, self.args.inputs, key_id=self.args.key,
715 **self.pakfire_args)
716
717 def handle_info(self):
718 info = self.server.info()
719
720 print "\n".join(info)
721
722
723 class CliBuilderIntern(Cli):
724 def __init__(self):
725 self.parser = argparse.ArgumentParser(
726 description = _("Pakfire builder command line interface."),
727 )
728
729 self.parse_common_arguments()
730
731 # Add sub-commands.
732 self.sub_commands = self.parser.add_subparsers()
733
734 self.parse_command_build()
735
736 # Finally parse all arguments from the command line and save them.
737 self.args = self.parser.parse_args()
738
739 self.action2func = {
740 "build" : self.handle_build,
741 }
742
743 def parse_command_build(self):
744 # Implement the "build" command.
745 sub_build = self.sub_commands.add_parser("build",
746 help=_("Build one or more packages."))
747 sub_build.add_argument("package", nargs=1,
748 help=_("Give name of at least one package to build."))
749 sub_build.add_argument("action", action="store_const", const="build")
750
751 sub_build.add_argument("-a", "--arch",
752 help=_("Build the package for the given architecture."))
753 sub_build.add_argument("--resultdir", nargs="?",
754 help=_("Path were the output files should be copied to."))
755 sub_build.add_argument("-m", "--mode", nargs="?", default="development",
756 help=_("Mode to run in. Is either 'release' or 'development' (default)."))
757 sub_build.add_argument("--nodeps", action="store_true",
758 help=_("Do not verify build dependencies."))
759
760 def handle_build(self):
761 # Get the package descriptor from the command line options
762 pkg = self.args.package[0]
763
764 # Check, if we got a regular file
765 if os.path.exists(pkg):
766 pkg = os.path.abspath(pkg)
767 else:
768 raise FileNotFoundError, pkg
769
770 # Create distribution configuration from command line.
771 distro_config = {
772 "arch" : self.args.arch,
773 }
774
775 pakfire._build(pkg, builder_mode=self.args.mode,
776 distro_config=distro_config, resultdir=self.args.resultdir,)
777
778
779 class CliClient(Cli):
780 def __init__(self):
781 self.parser = argparse.ArgumentParser(
782 description = _("Pakfire client command line interface."),
783 )
784
785 self.parse_common_arguments(repo_manage_switches=True, offline_switch=True)
786
787 # Add sub-commands.
788 self.sub_commands = self.parser.add_subparsers()
789
790 self.parse_command_build()
791 self.parse_command_connection_check()
792 self.parse_command_info()
793
794 # Finally parse all arguments from the command line and save them.
795 self.args = self.parser.parse_args()
796
797 self.action2func = {
798 "build" : self.handle_build,
799 "conn-check" : self.handle_connection_check,
800 "info" : self.handle_info,
801 }
802
803 # Read configuration for the pakfire client.
804 self.conf = conf = config.ConfigClient()
805
806 # Create connection to pakfire hub.
807 self.client = client.PakfireUserClient(
808 conf.get("client", "server"),
809 conf.get("client", "username"),
810 conf.get("client", "password"),
811 )
812
813 def parse_command_build(self):
814 # Parse "build" command.
815 sub_build = self.sub_commands.add_parser("build",
816 help=_("Build a package remotely."))
817 sub_build.add_argument("package", nargs=1,
818 help=_("Give name of a package to build."))
819 sub_build.add_argument("action", action="store_const", const="build")
820
821 sub_build.add_argument("-a", "--arch",
822 help=_("Build the package for the given architecture."))
823
824 def parse_command_info(self):
825 # Implement the "info" command.
826 sub_info = self.sub_commands.add_parser("info",
827 help=_("Print some information about this host."))
828 sub_info.add_argument("action", action="store_const", const="info")
829
830 def parse_command_connection_check(self):
831 # Implement the "conn-check" command.
832 sub_conn_check = self.sub_commands.add_parser("conn-check",
833 help=_("Check the connection to the hub."))
834 sub_conn_check.add_argument("action", action="store_const", const="conn-check")
835
836 def handle_build(self):
837 (package,) = self.args.package
838
839 # XXX just for now, we do only upload source pfm files.
840 assert os.path.exists(package)
841
842 # Format arches.
843 if self.args.arch:
844 arches = self.args.arch.replace(",", " ")
845 else:
846 arches = None
847
848 # Create a new build on the server.
849 build = self.client.build_create(package, arches=arches)
850
851 # XXX Print the resulting build.
852 print build
853
854 def handle_info(self):
855 ret = []
856
857 ret.append("")
858 ret.append(" PAKFIRE %s" % PAKFIRE_VERSION)
859 ret.append("")
860 ret.append(" %-20s: %s" % (_("Hostname"), system.hostname))
861 ret.append(" %-20s: %s" % (_("Pakfire hub"), self.conf.get("client", "server")))
862 if self.conf.get("client", "username") and self.conf.get("client", "password"):
863 ret.append(" %-20s: %s" % \
864 (_("Username"), self.conf.get("client", "username")))
865 ret.append("")
866
867 # Hardware information
868 ret.append(" %s:" % _("Hardware information"))
869 ret.append(" %-16s: %s" % (_("CPU model"), system.cpu_model))
870 ret.append(" %-16s: %s" % (_("Memory"), util.format_size(system.memory)))
871 ret.append("")
872 ret.append(" %-16s: %s" % (_("Native arch"), system.native_arch))
873 if not system.arch == system.native_arch:
874 ret.append(" %-16s: %s" % (_("Default arch"), system.arch))
875
876 header = _("Supported arches")
877 for arch in system.supported_arches:
878 ret.append(" %-16s: %s" % (header, arch))
879 header = ""
880 ret.append("")
881
882 for line in ret:
883 print line
884
885 def handle_connection_check(self):
886 ret = []
887
888 address = self.client.get_my_address()
889 ret.append(" %-20s: %s" % (_("Your IP address"), address))
890 ret.append("")
891
892 authenticated = self.client.check_auth()
893 if authenticated:
894 ret.append(" %s" % _("You are authenticated to the build service:"))
895
896 user = self.client.get_user_profile()
897 assert user, "Could not fetch user infomation"
898
899 keys = [
900 ("name", _("User name")),
901 ("realname", _("Real name")),
902 ("email", _("Email address")),
903 ("registered", _("Registered")),
904 ]
905
906 for key, desc in keys:
907 ret.append(" %-18s: %s" % (desc, user.get(key)))
908
909 else:
910 ret.append(_("You could not be authenticated to the build service."))
911
912 for line in ret:
913 print line
914
915
916 class CliDaemon(Cli):
917 def __init__(self):
918 self.parser = argparse.ArgumentParser(
919 description = _("Pakfire daemon command line interface."),
920 )
921
922 self.parse_common_arguments(repo_manage_switches=True, offline_switch=True)
923
924 # Finally parse all arguments from the command line and save them.
925 self.args = self.parser.parse_args()
926
927 def run(self):
928 """
929 Runs the pakfire daemon with provided settings.
930 """
931 # Read the configuration file for the daemon.
932 conf = config.ConfigDaemon()
933
934 # Create daemon instance.
935 d = pakfire.client.PakfireDaemon(
936 server = conf.get("daemon", "server"),
937 hostname = conf.get("daemon", "hostname"),
938 secret = conf.get("daemon", "secret"),
939 )
940
941 try:
942 d.run()
943
944 # We cannot just kill the daemon, it needs a smooth shutdown.
945 except (SystemExit, KeyboardInterrupt):
946 d.shutdown()
947
948
949 class CliKey(Cli):
950 def __init__(self):
951 self.parser = argparse.ArgumentParser(
952 description = _("Pakfire key command line interface."),
953 )
954
955 self.parse_common_arguments(repo_manage_switches=False,
956 offline_switch=True)
957
958 # Add sub-commands.
959 self.sub_commands = self.parser.add_subparsers()
960
961 self.parse_command_init()
962 self.parse_command_generate()
963 self.parse_command_import()
964 self.parse_command_export()
965 self.parse_command_delete()
966 self.parse_command_list()
967 self.parse_command_sign()
968 self.parse_command_verify()
969
970 # Finally parse all arguments from the command line and save them.
971 self.args = self.parser.parse_args()
972
973 # Create a pakfire instance.
974 self.pakfire = pakfire.Pakfire(**self.pakfire_args)
975
976 self.action2func = {
977 "init" : self.handle_init,
978 "generate" : self.handle_generate,
979 "import" : self.handle_import,
980 "export" : self.handle_export,
981 "delete" : self.handle_delete,
982 "list" : self.handle_list,
983 "sign" : self.handle_sign,
984 "verify" : self.handle_verify,
985 }
986
987 @property
988 def pakfire_args(self):
989 ret = {
990 "mode" : "server",
991 }
992
993 return ret
994
995 def parse_command_init(self):
996 # Parse "init" command.
997 sub_init = self.sub_commands.add_parser("init",
998 help=_("Initialize the local keyring."))
999 sub_init.add_argument("action", action="store_const", const="init")
1000
1001 def parse_command_generate(self):
1002 # Parse "generate" command.
1003 sub_gen = self.sub_commands.add_parser("generate",
1004 help=_("Import a key from file."))
1005 sub_gen.add_argument("--realname", nargs=1,
1006 help=_("The real name of the owner of this key."))
1007 sub_gen.add_argument("--email", nargs=1,
1008 help=_("The email address of the owner of this key."))
1009 sub_gen.add_argument("action", action="store_const", const="generate")
1010
1011 def parse_command_import(self):
1012 # Parse "import" command.
1013 sub_import = self.sub_commands.add_parser("import",
1014 help=_("Import a key from file."))
1015 sub_import.add_argument("filename", nargs=1,
1016 help=_("Filename of that key to import."))
1017 sub_import.add_argument("action", action="store_const", const="import")
1018
1019 def parse_command_export(self):
1020 # Parse "export" command.
1021 sub_export = self.sub_commands.add_parser("export",
1022 help=_("Export a key to a file."))
1023 sub_export.add_argument("keyid", nargs=1,
1024 help=_("The ID of the key to export."))
1025 sub_export.add_argument("filename", nargs=1,
1026 help=_("Write the key to this file."))
1027 sub_export.add_argument("action", action="store_const", const="export")
1028
1029 def parse_command_delete(self):
1030 # Parse "delete" command.
1031 sub_del = self.sub_commands.add_parser("delete",
1032 help=_("Delete a key from the local keyring."))
1033 sub_del.add_argument("keyid", nargs=1,
1034 help=_("The ID of the key to delete."))
1035 sub_del.add_argument("action", action="store_const", const="delete")
1036
1037 def parse_command_list(self):
1038 # Parse "list" command.
1039 sub_list = self.sub_commands.add_parser("list",
1040 help=_("List all imported keys."))
1041 sub_list.add_argument("action", action="store_const", const="list")
1042
1043 def parse_command_sign(self):
1044 # Implement the "sign" command.
1045 sub_sign = self.sub_commands.add_parser("sign",
1046 help=_("Sign one or more packages."))
1047 sub_sign.add_argument("--key", "-k", nargs=1,
1048 help=_("Key that is used sign the package(s)."))
1049 sub_sign.add_argument("package", nargs="+",
1050 help=_("Package(s) to sign."))
1051 sub_sign.add_argument("action", action="store_const", const="sign")
1052
1053 def parse_command_verify(self):
1054 # Implement the "verify" command.
1055 sub_verify = self.sub_commands.add_parser("verify",
1056 help=_("Verify one or more packages."))
1057 #sub_verify.add_argument("--key", "-k", nargs=1,
1058 # help=_("Key that is used verify the package(s)."))
1059 sub_verify.add_argument("package", nargs="+",
1060 help=_("Package(s) to verify."))
1061 sub_verify.add_argument("action", action="store_const", const="verify")
1062
1063 def handle_init(self):
1064 # Initialize the keyring...
1065 pakfire.key_init(**self.pakfire_args)
1066
1067 def handle_generate(self):
1068 realname = self.args.realname[0]
1069 email = self.args.email[0]
1070
1071 print _("Generating the key may take a moment...")
1072 print
1073
1074 # Generate the key.
1075 fpr = pakfire.key_generate(realname, email, **self.pakfire_args)
1076
1077 # Dump all information about the new key.
1078 for line in self.dump_key(fpr):
1079 print line
1080
1081 def handle_import(self):
1082 filename = self.args.filename[0]
1083
1084 # Simply import the file.
1085 pakfire.key_import(filename, **self.pakfire_args)
1086
1087 def handle_export(self):
1088 keyid = self.args.keyid[0]
1089 filename = self.args.filename[0]
1090
1091 pakfire.key_export(keyid, filename, **self.pakfire_args)
1092
1093 def handle_delete(self):
1094 keyid = self.args.keyid[0]
1095
1096 pakfire.key_delete(keyid, **self.pakfire_args)
1097
1098 def handle_list(self):
1099 lines = pakfire.key_list(**self.pakfire_args)
1100
1101 for line in lines:
1102 print line
1103
1104 def handle_sign(self):
1105 # Get the files from the command line options
1106 files = []
1107
1108 for file in self.args.package:
1109 # Check, if we got a regular file
1110 if os.path.exists(file):
1111 file = os.path.abspath(file)
1112 files.append(file)
1113
1114 else:
1115 raise FileNotFoundError, file
1116
1117 key = self.args.key[0]
1118
1119 for file in files:
1120 # Open the package.
1121 pkg = packages.open(self.pakfire, None, file)
1122
1123 print _("Signing %s...") % pkg.friendly_name
1124 pkg.sign(key)
1125
1126 def handle_verify(self):
1127 # Get the files from the command line options
1128 files = []
1129
1130 for file in self.args.package:
1131 # Check, if we got a regular file
1132 if os.path.exists(file) and not os.path.isdir(file):
1133 file = os.path.abspath(file)
1134 files.append(file)
1135
1136 for file in files:
1137 # Open the package.
1138 pkg = packages.open(self.pakfire, None, file)
1139
1140 print _("Verifying %s...") % pkg.friendly_name
1141 sigs = pkg.verify()
1142
1143 for sig in sigs:
1144 key = self.pakfire.keyring.get_key(sig.fpr)
1145 if key:
1146 subkey = key.subkeys[0]
1147
1148 print " %s %s" % (subkey.fpr[-16:], key.uids[0].uid)
1149 if sig.validity:
1150 print " %s" % _("This signature is valid.")
1151
1152 else:
1153 print " %s <%s>" % (sig.fpr, _("Unknown key"))
1154 print " %s" % _("Could not check if this signature is valid.")
1155
1156 created = datetime.datetime.fromtimestamp(sig.timestamp)
1157 print " %s" % _("Created: %s") % created
1158
1159 if sig.exp_timestamp:
1160 expires = datetime.datetime.fromtimestamp(sig.exp_timestamp)
1161 print " %s" % _("Expires: %s") % expires
1162
1163 print # Empty line