]>
git.ipfire.org Git - people/stevee/pakfire.git/blob - python/pakfire/cli.py
2275ded31fd33a23355c2a2842bcbff07ea6665e
2 ###############################################################################
4 # Pakfire - The IPFire package management system #
5 # Copyright (C) 2011 Pakfire development team #
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. #
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. #
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/>. #
20 ###############################################################################
29 import pakfire
.api
as pakfire
39 from system
import system
40 from constants
import *
43 # Initialize a very simple logging that is removed when a Pakfire instance
45 logger
.setup_logging()
49 self
.parser
= argparse
.ArgumentParser(
50 description
= _("Pakfire command line interface."),
53 self
.parse_common_arguments()
55 self
.parser
.add_argument("--root", metavar
="PATH",
57 help=_("The path where pakfire should operate in."))
60 self
.sub_commands
= self
.parser
.add_subparsers()
62 self
.parse_command_install()
63 self
.parse_command_reinstall()
64 self
.parse_command_remove()
65 self
.parse_command_info()
66 self
.parse_command_search()
67 self
.parse_command_check_update()
68 self
.parse_command_update()
69 self
.parse_command_downgrade()
70 self
.parse_command_provides()
71 self
.parse_command_grouplist()
72 self
.parse_command_groupinstall()
73 self
.parse_command_repolist()
74 self
.parse_command_clean()
75 self
.parse_command_check()
76 self
.parse_command_resolvdep()
78 # Finally parse all arguments from the command line and save them.
79 self
.args
= self
.parser
.parse_args()
82 "install" : self
.handle_install
,
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
,
100 def pakfire_args(self
):
101 ret
= { "mode" : "normal" }
103 if hasattr(self
.args
, "root"):
104 ret
["path"] = self
.args
.root
106 if hasattr(self
.args
, "disable_repo"):
107 ret
["disable_repos"] = self
.args
.disable_repo
109 if hasattr(self
.args
, "enable_repo"):
110 ret
["enable_repos"] = self
.args
.enable_repo
112 if hasattr(self
.args
, "offline") and self
.args
.offline
:
113 ret
["downloader"] = {
114 "offline" : self
.args
.offline
,
117 if hasattr(self
.args
, "config"):
118 ret
["configs"] = self
.args
.config
120 ret
["configs"] = None
124 def parse_common_arguments(self
, repo_manage_switches
=True, offline_switch
=True):
125 self
.parser
.add_argument("--version", action
="version",
126 version
="%(prog)s " + PAKFIRE_VERSION
)
128 self
.parser
.add_argument("-v", "--verbose", action
="store_true",
129 help=_("Enable verbose output."))
131 self
.parser
.add_argument("-c", "--config", nargs
="?",
132 help=_("Path to a configuration file to load."))
134 if repo_manage_switches
:
135 self
.parser
.add_argument("--disable-repo", nargs
="*", metavar
="REPO",
136 help=_("Disable a repository temporarily."))
138 self
.parser
.add_argument("--enabled-repo", nargs
="*", metavar
="REPO",
139 help=_("Enable a repository temporarily."))
142 self
.parser
.add_argument("--offline", action
="store_true",
143 help=_("Run pakfire in offline mode."))
145 def parse_command_install(self
):
146 # Implement the "install" command.
147 sub_install
= self
.sub_commands
.add_parser("install",
148 help=_("Install one or more packages to the system."))
149 sub_install
.add_argument("package", nargs
="+",
150 help=_("Give name of at least one package to install."))
151 sub_install
.add_argument("action", action
="store_const", const
="install")
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")
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")
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."))
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."))
184 sub_update
.add_argument("action", action
="store_const", const
="update")
185 self
._parse
_command
_update
(sub_update
)
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."))
191 sub_check_update
.add_argument("action", action
="store_const", const
="check_update")
192 self
._parse
_command
_update
(sub_check_update
)
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")
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")
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")
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")
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")
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")
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")
252 def parse_command_clean(self
):
253 sub_clean
= self
.sub_commands
.add_parser("clean", help=_("Cleanup commands."))
255 sub_clean_commands
= sub_clean
.add_subparsers()
257 self
.parse_command_clean_all(sub_clean_commands
)
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")
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")
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
=1,
275 help=_("Give name of at least one package to check."))
276 sub_resolvdep
.add_argument("action", action
="store_const", const
="resolvdep")
279 action
= self
.args
.action
282 func
= self
.action2func
[action
]
284 raise Exception, "Unhandled action: %s" % action
288 def handle_info(self
, long=False):
289 pkgs
= pakfire
.info(self
.args
.package
, **self
.pakfire_args
)
292 print pkg
.dump(long=long)
294 def handle_search(self
):
295 pkgs
= pakfire
.search(self
.args
.pattern
, **self
.pakfire_args
)
298 print pkg
.dump(short
=True)
300 def handle_update(self
, **args
):
301 args
.update(self
.pakfire_args
)
303 pakfire
.update(self
.args
.package
, excludes
=self
.args
.exclude
,
304 allow_vendorchange
=self
.args
.allow_vendorchange
,
305 allow_archchange
=self
.args
.allow_archchange
,
308 def handle_check_update(self
):
309 self
.handle_update(check
=True)
311 def handle_downgrade(self
, **args
):
312 args
.update(self
.pakfire_args
)
314 pakfire
.downgrade(self
.args
.package
,
315 allow_vendorchange
=self
.args
.allow_vendorchange
,
316 allow_archchange
=self
.args
.allow_archchange
,
319 def handle_install(self
):
320 pakfire
.install(self
.args
.package
, **self
.pakfire_args
)
322 def handle_reinstall(self
):
323 pakfire
.reinstall(self
.args
.package
, **self
.pakfire_args
)
325 def handle_remove(self
):
326 pakfire
.remove(self
.args
.package
, **self
.pakfire_args
)
328 def handle_provides(self
):
329 pkgs
= pakfire
.provides(self
.args
.pattern
, **self
.pakfire_args
)
334 def handle_grouplist(self
):
335 pkgs
= pakfire
.grouplist(self
.args
.group
[0], **self
.pakfire_args
)
340 def handle_groupinstall(self
):
341 pakfire
.groupinstall(self
.args
.group
[0], **self
.pakfire_args
)
343 def handle_repolist(self
):
344 repos
= pakfire
.repo_list(**self
.pakfire_args
)
346 FORMAT
= " %-20s %8s %12s %12s "
348 title
= FORMAT
% (_("Repository"), _("Enabled"), _("Priority"), _("Packages"))
350 print "=" * len(title
) # spacing line
353 # Skip the installed repository.
354 if repo
.name
== "installed":
357 print FORMAT
% (repo
.name
, repo
.enabled
, repo
.priority
, len(repo
))
359 def handle_clean_all(self
):
360 print _("Cleaning up everything...")
362 pakfire
.clean_all(**self
.pakfire_args
)
364 def handle_check(self
):
365 pakfire
.check(**self
.pakfire_args
)
367 def handle_resolvdep(self
):
368 (pkg
,) = self
.args
.package
370 solver
= pakfire
.resolvdep(pkg
, **self
.pakfire_args
)
373 solver
.transaction
.dump()
376 class CliBuilder(Cli
):
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.")
383 self
.parser
= argparse
.ArgumentParser(
384 description
= _("Pakfire builder command line interface."),
387 self
.parse_common_arguments()
390 self
.sub_commands
= self
.parser
.add_subparsers()
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()
398 self
.parse_command_provides()
399 self
.parse_command_grouplist()
400 self
.parse_command_repolist()
401 self
.parse_command_clean()
402 self
.parse_command_resolvdep()
403 self
.parse_command_cache()
405 # Finally parse all arguments from the command line and save them.
406 self
.args
= self
.parser
.parse_args()
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
,
415 "provides" : self
.handle_provides
,
416 "grouplist" : self
.handle_grouplist
,
417 "repolist" : self
.handle_repolist
,
418 "clean_all" : self
.handle_clean_all
,
419 "resolvdep" : self
.handle_resolvdep
,
420 "cache_create": self
.handle_cache_create
,
421 "cache_cleanup": self
.handle_cache_cleanup
,
425 def pakfire_args(self
):
426 ret
= { "mode" : "builder" }
428 if hasattr(self
.args
, "disable_repo"):
429 ret
["disable_repos"] = self
.args
.disable_repo
431 if hasattr(self
.args
, "enable_repo"):
432 ret
["enable_repos"] = self
.args
.enable_repo
434 if hasattr(self
.args
, "offline") and self
.args
.offline
:
435 ret
["downloader"] = {
436 "offline" : self
.args
.offline
,
441 def parse_command_update(self
):
442 # Implement the "update" command.
443 sub_update
= self
.sub_commands
.add_parser("update",
444 help=_("Update the package indexes."))
445 sub_update
.add_argument("action", action
="store_const", const
="update")
447 def parse_command_build(self
):
448 # Implement the "build" command.
449 sub_build
= self
.sub_commands
.add_parser("build",
450 help=_("Build one or more packages."))
451 sub_build
.add_argument("package", nargs
=1,
452 help=_("Give name of at least one package to build."))
453 sub_build
.add_argument("action", action
="store_const", const
="build")
455 sub_build
.add_argument("-a", "--arch",
456 help=_("Build the package for the given architecture."))
457 sub_build
.add_argument("--resultdir", nargs
="?",
458 help=_("Path were the output files should be copied to."))
459 sub_build
.add_argument("-m", "--mode", nargs
="?", default
="development",
460 help=_("Mode to run in. Is either 'release' or 'development' (default)."))
461 sub_build
.add_argument("--after-shell", action
="store_true",
462 help=_("Run a shell after a successful build."))
463 sub_build
.add_argument("--no-install-test", action
="store_true",
464 help=_("Do not perform the install test."))
466 def parse_command_shell(self
):
467 # Implement the "shell" command.
468 sub_shell
= self
.sub_commands
.add_parser("shell",
469 help=_("Go into a shell."))
470 sub_shell
.add_argument("package", nargs
="?",
471 help=_("Give name of a package."))
472 sub_shell
.add_argument("action", action
="store_const", const
="shell")
474 sub_shell
.add_argument("-a", "--arch",
475 help=_("Emulated architecture in the shell."))
476 sub_shell
.add_argument("-m", "--mode", nargs
="?", default
="development",
477 help=_("Mode to run in. Is either 'release' or 'development' (default)."))
479 def parse_command_dist(self
):
480 # Implement the "dist" command.
481 sub_dist
= self
.sub_commands
.add_parser("dist",
482 help=_("Generate a source package."))
483 sub_dist
.add_argument("package", nargs
="+",
484 help=_("Give name(s) of a package(s)."))
485 sub_dist
.add_argument("action", action
="store_const", const
="dist")
487 sub_dist
.add_argument("--resultdir", nargs
="?",
488 help=_("Path were the output files should be copied to."))
490 def parse_command_cache(self
):
491 # Implement the "cache" command.
492 sub_cache
= self
.sub_commands
.add_parser("cache",
493 help=_("Create a build environment cache."))
495 # Implement subcommands.
496 sub_cache_commands
= sub_cache
.add_subparsers()
498 self
.parse_command_cache_create(sub_cache_commands
)
499 self
.parse_command_cache_cleanup(sub_cache_commands
)
501 def parse_command_cache_create(self
, sub_commands
):
502 sub_create
= sub_commands
.add_parser("create",
503 help=_("Create a new build environment cache."))
504 sub_create
.add_argument("action", action
="store_const", const
="cache_create")
506 def parse_command_cache_cleanup(self
, sub_commands
):
507 sub_cleanup
= sub_commands
.add_parser("cleanup",
508 help=_("Remove all cached build environments."))
509 sub_cleanup
.add_argument("action", action
="store_const", const
="cache_cleanup")
511 def handle_info(self
):
512 Cli
.handle_info(self
, long=True)
514 def handle_build(self
):
515 # Get the package descriptor from the command line options
516 pkg
= self
.args
.package
[0]
518 # Check, if we got a regular file
519 if os
.path
.exists(pkg
):
520 pkg
= os
.path
.abspath(pkg
)
523 raise FileNotFoundError
, pkg
525 # Check whether to enable the install test.
526 install_test
= not self
.args
.no_install_test
528 pakfire
.build(pkg
, builder_mode
=self
.args
.mode
, install_test
=install_test
,
529 arch
=self
.args
.arch
, resultdirs
=[self
.args
.resultdir
,],
530 shell
=True, after_shell
=self
.args
.after_shell
, **self
.pakfire_args
)
532 def handle_shell(self
):
535 # Get the package descriptor from the command line options
536 if self
.args
.package
:
537 pkg
= self
.args
.package
539 # Check, if we got a regular file
540 if os
.path
.exists(pkg
):
541 pkg
= os
.path
.abspath(pkg
)
544 raise FileNotFoundError
, pkg
546 pakfire
.shell(pkg
, builder_mode
=self
.args
.mode
,
547 arch
=self
.args
.arch
, **self
.pakfire_args
)
549 def handle_dist(self
):
550 # Get the packages from the command line options
553 for pkg
in self
.args
.package
:
554 # Check, if we got a regular file
555 if os
.path
.exists(pkg
):
556 pkg
= os
.path
.abspath(pkg
)
560 raise FileNotFoundError
, pkg
562 # Put packages to where the user said or our
563 # current working directory.
564 resultdir
= self
.args
.resultdir
or os
.getcwd()
566 # Change the default pakfire configuration, because
567 # packaging source packages can be done in server mode.
568 pakfire_args
= self
.pakfire_args
569 pakfire_args
["mode"] = "server"
572 pakfire
.dist(pkg
, resultdir
=resultdir
, **pakfire_args
)
574 def handle_provides(self
):
575 pkgs
= pakfire
.provides(self
.args
.pattern
, **self
.pakfire_args
)
578 print pkg
.dump(long=True)
580 def handle_cache_create(self
):
581 pakfire
.cache_create(**self
.pakfire_args
)
583 def handle_cache_cleanup(self
):
584 for env
in os
.listdir(CACHE_ENVIRON_DIR
):
585 if not env
.endswith(".cache"):
588 print _("Removing environment cache file: %s..." % env
)
589 env
= os
.path
.join(CACHE_ENVIRON_DIR
, env
)
594 print _("Could not remove file: %s") % env
597 class CliServer(Cli
):
599 self
.parser
= argparse
.ArgumentParser(
600 description
= _("Pakfire server command line interface."),
603 self
.parse_common_arguments()
606 self
.sub_commands
= self
.parser
.add_subparsers()
608 self
.parse_command_build()
609 self
.parse_command_keepalive()
610 self
.parse_command_repoupdate()
611 self
.parse_command_repo()
612 self
.parse_command_info()
614 # Finally parse all arguments from the command line and save them.
615 self
.args
= self
.parser
.parse_args()
617 self
.server
= server
.Server(**self
.pakfire_args
)
620 "build" : self
.handle_build
,
621 "info" : self
.handle_info
,
622 "keepalive" : self
.handle_keepalive
,
623 "repoupdate" : self
.handle_repoupdate
,
624 "repo_create": self
.handle_repo_create
,
628 def pakfire_args(self
):
629 ret
= { "mode" : "server" }
631 if hasattr(self
.args
, "offline") and self
.args
.offline
:
632 ret
["downloader"] = {
633 "offline" : self
.args
.offline
,
638 def parse_command_build(self
):
639 # Implement the "build" command.
640 sub_build
= self
.sub_commands
.add_parser("build",
641 help=_("Send a scrach build job to the server."))
642 sub_build
.add_argument("package", nargs
=1,
643 help=_("Give name of at least one package to build."))
644 sub_build
.add_argument("--arch", "-a",
645 help=_("Limit build to only these architecture(s)."))
646 sub_build
.add_argument("action", action
="store_const", const
="build")
648 def parse_command_keepalive(self
):
649 # Implement the "keepalive" command.
650 sub_keepalive
= self
.sub_commands
.add_parser("keepalive",
651 help=_("Send a keepalive to the server."))
652 sub_keepalive
.add_argument("action", action
="store_const",
655 def parse_command_repoupdate(self
):
656 # Implement the "repoupdate" command.
657 sub_repoupdate
= self
.sub_commands
.add_parser("repoupdate",
658 help=_("Update all repositories."))
659 sub_repoupdate
.add_argument("action", action
="store_const",
662 def parse_command_repo(self
):
663 sub_repo
= self
.sub_commands
.add_parser("repo",
664 help=_("Repository management commands."))
666 sub_repo_commands
= sub_repo
.add_subparsers()
668 self
.parse_command_repo_create(sub_repo_commands
)
670 def parse_command_repo_create(self
, sub_commands
):
671 sub_create
= sub_commands
.add_parser("create",
672 help=_("Create a new repository index."))
673 sub_create
.add_argument("path", nargs
=1,
674 help=_("Path to the packages."))
675 sub_create
.add_argument("inputs", nargs
="+",
676 help=_("Path to input packages."))
677 sub_create
.add_argument("--key", "-k", nargs
="?",
678 help=_("Key to sign the repository with."))
679 sub_create
.add_argument("action", action
="store_const", const
="repo_create")
681 def parse_command_info(self
):
682 sub_info
= self
.sub_commands
.add_parser("info",
683 help=_("Dump some information about this machine."))
684 sub_info
.add_argument("action", action
="store_const", const
="info")
686 def handle_keepalive(self
):
687 self
.server
.update_info()
689 def handle_build(self
):
692 arches
= self
.args
.arch
.split()
694 (package
,) = self
.args
.package
696 self
.server
.create_scratch_build({})
699 # Temporary folter for source package.
700 tmpdir
= "/tmp/pakfire-%s" % util
.random_string()
705 pakfire
.dist(package
, resultdir
=[tmpdir
,])
707 for file in os
.listdir(tmpdir
):
708 file = os
.path
.join(tmpdir
, file)
713 if os
.path
.exists(tmpdir
):
716 def handle_repoupdate(self
):
717 self
.server
.update_repositories()
719 def handle_repo_create(self
):
720 path
= self
.args
.path
[0]
722 pakfire
.repo_create(path
, self
.args
.inputs
, key_id
=self
.args
.key
,
725 def handle_info(self
):
726 info
= self
.server
.info()
728 print "\n".join(info
)
731 class CliBuilderIntern(Cli
):
733 self
.parser
= argparse
.ArgumentParser(
734 description
= _("Pakfire builder command line interface."),
737 self
.parse_common_arguments()
740 self
.sub_commands
= self
.parser
.add_subparsers()
742 self
.parse_command_build()
744 # Finally parse all arguments from the command line and save them.
745 self
.args
= self
.parser
.parse_args()
748 "build" : self
.handle_build
,
751 def parse_command_build(self
):
752 # Implement the "build" command.
753 sub_build
= self
.sub_commands
.add_parser("build",
754 help=_("Build one or more packages."))
755 sub_build
.add_argument("package", nargs
=1,
756 help=_("Give name of at least one package to build."))
757 sub_build
.add_argument("action", action
="store_const", const
="build")
759 sub_build
.add_argument("-a", "--arch",
760 help=_("Build the package for the given architecture."))
761 sub_build
.add_argument("--resultdir", nargs
="?",
762 help=_("Path were the output files should be copied to."))
763 sub_build
.add_argument("-m", "--mode", nargs
="?", default
="development",
764 help=_("Mode to run in. Is either 'release' or 'development' (default)."))
765 sub_build
.add_argument("--nodeps", action
="store_true",
766 help=_("Do not verify build dependencies."))
768 def handle_build(self
):
769 # Get the package descriptor from the command line options
770 pkg
= self
.args
.package
[0]
772 # Check, if we got a regular file
773 if os
.path
.exists(pkg
):
774 pkg
= os
.path
.abspath(pkg
)
776 raise FileNotFoundError
, pkg
778 conf
= config
.ConfigBuilder()
781 disable_repos
= ["*"]
786 "arch" : self
.args
.arch
,
787 "builder_mode" : self
.args
.mode
,
789 "disable_repos" : disable_repos
,
790 "resultdir" : self
.args
.resultdir
,
793 pakfire
._build
(pkg
, **kwargs
)
796 class CliClient(Cli
):
798 self
.parser
= argparse
.ArgumentParser(
799 description
= _("Pakfire client command line interface."),
802 self
.parse_common_arguments(repo_manage_switches
=True, offline_switch
=True)
805 self
.sub_commands
= self
.parser
.add_subparsers()
807 self
.parse_command_build()
808 self
.parse_command_connection_check()
809 self
.parse_command_info()
810 self
.parse_command_jobs()
811 self
.parse_command_builds()
813 # Finally parse all arguments from the command line and save them.
814 self
.args
= self
.parser
.parse_args()
817 "build" : self
.handle_build
,
818 "conn-check" : self
.handle_connection_check
,
819 "info" : self
.handle_info
,
820 "jobs_show" : self
.handle_jobs_show
,
821 "jobs_active" : self
.handle_jobs_active
,
822 "jobs_latest" : self
.handle_jobs_latest
,
823 "builds_show" : self
.handle_builds_show
,
826 # Read configuration for the pakfire client.
827 self
.conf
= conf
= config
.ConfigClient()
829 # Create connection to pakfire hub.
830 self
.client
= client
.PakfireUserClient(
831 conf
.get("client", "server"),
832 conf
.get("client", "username"),
833 conf
.get("client", "password"),
836 def parse_command_build(self
):
837 # Parse "build" command.
838 sub_build
= self
.sub_commands
.add_parser("build",
839 help=_("Build a package remotely."))
840 sub_build
.add_argument("package", nargs
=1,
841 help=_("Give name of a package to build."))
842 sub_build
.add_argument("action", action
="store_const", const
="build")
844 sub_build
.add_argument("-a", "--arch",
845 help=_("Build the package for the given architecture."))
847 def parse_command_info(self
):
848 # Implement the "info" command.
849 sub_info
= self
.sub_commands
.add_parser("info",
850 help=_("Print some information about this host."))
851 sub_info
.add_argument("action", action
="store_const", const
="info")
853 def parse_command_connection_check(self
):
854 # Implement the "conn-check" command.
855 sub_conn_check
= self
.sub_commands
.add_parser("conn-check",
856 help=_("Check the connection to the hub."))
857 sub_conn_check
.add_argument("action", action
="store_const", const
="conn-check")
859 def parse_command_jobs(self
):
860 sub_jobs
= self
.sub_commands
.add_parser("jobs",
861 help=_("Show information about build jobs."))
863 sub_jobs_commands
= sub_jobs
.add_subparsers()
865 self
.parse_command_jobs_active(sub_jobs_commands
)
866 self
.parse_command_jobs_latest(sub_jobs_commands
)
867 self
.parse_command_jobs_show(sub_jobs_commands
)
869 def parse_command_jobs_active(self
, sub_commands
):
870 sub_active
= sub_commands
.add_parser("active",
871 help=_("Show a list of all active jobs."))
872 sub_active
.add_argument("action", action
="store_const", const
="jobs_active")
874 def parse_command_jobs_latest(self
, sub_commands
):
875 sub_latest
= sub_commands
.add_parser("latest",
876 help=_("Show a list of all recently finished of failed build jobs."))
877 sub_latest
.add_argument("action", action
="store_const", const
="jobs_latest")
879 def parse_command_jobs_show(self
, sub_commands
):
880 sub_show
= sub_commands
.add_parser("show",
881 help=_("Show details about given build job."))
882 sub_show
.add_argument("job_id", nargs
=1, help=_("The ID of the build job."))
883 sub_show
.add_argument("action", action
="store_const", const
="jobs_show")
885 def parse_command_builds(self
):
886 sub_builds
= self
.sub_commands
.add_parser("builds",
887 help=_("Show information about builds."))
889 sub_builds_commands
= sub_builds
.add_subparsers()
891 self
.parse_command_builds_show(sub_builds_commands
)
893 def parse_command_builds_show(self
, sub_commands
):
894 sub_show
= sub_commands
.add_parser("show",
895 help=_("Show details about the given build."))
896 sub_show
.add_argument("build_id", nargs
=1, help=_("The ID of the build."))
897 sub_show
.add_argument("action", action
="store_const", const
="builds_show")
899 def handle_build(self
):
900 (package
,) = self
.args
.package
902 # XXX just for now, we do only upload source pfm files.
903 assert os
.path
.exists(package
)
905 # Create a temporary directory.
906 temp_dir
= tempfile
.mkdtemp()
909 if package
.endswith(".%s" % MAKEFILE_EXTENSION
):
910 pakfire_args
= { "mode" : "server" }
912 # Create a source package from the makefile.
913 package
= pakfire
.dist(package
, temp_dir
, **pakfire_args
)
915 elif package
.endswith(".%s" % PACKAGE_EXTENSION
):
919 raise Exception, "Unknown filetype: %s" % package
923 arches
= self
.args
.arch
.replace(",", " ")
927 # Create a new build on the server.
928 build
= self
.client
.build_create(package
, arches
=arches
)
930 # XXX Print the resulting build.
934 # Cleanup the temporary directory and all files.
935 if os
.path
.exists(temp_dir
):
936 shutil
.rmtree(temp_dir
, ignore_errors
=True)
938 def handle_info(self
):
942 ret
.append(" PAKFIRE %s" % PAKFIRE_VERSION
)
944 ret
.append(" %-20s: %s" % (_("Hostname"), system
.hostname
))
945 ret
.append(" %-20s: %s" % (_("Pakfire hub"), self
.conf
.get("client", "server")))
946 if self
.conf
.get("client", "username") and self
.conf
.get("client", "password"):
947 ret
.append(" %-20s: %s" % \
948 (_("Username"), self
.conf
.get("client", "username")))
951 # Hardware information
952 ret
.append(" %s:" % _("Hardware information"))
953 ret
.append(" %-16s: %s" % (_("CPU model"), system
.cpu_model
))
954 ret
.append(" %-16s: %s" % (_("Memory"), util
.format_size(system
.memory
)))
956 ret
.append(" %-16s: %s" % (_("Native arch"), system
.native_arch
))
957 if not system
.arch
== system
.native_arch
:
958 ret
.append(" %-16s: %s" % (_("Default arch"), system
.arch
))
960 header
= _("Supported arches")
961 for arch
in system
.supported_arches
:
962 ret
.append(" %-16s: %s" % (header
, arch
))
969 def handle_connection_check(self
):
972 address
= self
.client
.get_my_address()
973 ret
.append(" %-20s: %s" % (_("Your IP address"), address
))
976 authenticated
= self
.client
.check_auth()
978 ret
.append(" %s" % _("You are authenticated to the build service:"))
980 user
= self
.client
.get_user_profile()
981 assert user
, "Could not fetch user infomation"
984 ("name", _("User name")),
985 ("realname", _("Real name")),
986 ("email", _("Email address")),
987 ("registered", _("Registered")),
990 for key
, desc
in keys
:
991 ret
.append(" %-18s: %s" % (desc
, user
.get(key
)))
994 ret
.append(_("You could not be authenticated to the build service."))
999 def _print_jobs(self
, jobs
, heading
=None):
1001 print "%s:" % heading
1005 line
= " [%(type)8s] %(name)-30s: %(state)s"
1009 print # Empty line at the end.
1011 def handle_jobs_active(self
):
1012 jobs
= self
.client
.get_active_jobs()
1015 print _("No ongoing jobs found.")
1018 self
._print
_jobs
(jobs
, _("Active build jobs"))
1020 def handle_jobs_latest(self
):
1021 jobs
= self
.client
.get_latest_jobs()
1024 print _("No jobs found.")
1027 self
._print
_jobs
(jobs
, _("Recently processed build jobs"))
1029 def handle_builds_show(self
):
1030 (build_id
,) = self
.args
.build_id
1032 build
= self
.client
.get_build(build_id
)
1034 print _("A build with ID %s could not be found.") % build_id
1037 print _("Build: %(name)s") % build
1041 fmt
% (_("State"), build
["state"]),
1042 fmt
% (_("Priority"), build
["priority"]),
1045 lines
.append("%s:" % _("Jobs"))
1046 for job
in build
["jobs"]:
1047 lines
.append(" * [%(uuid)s] %(name)-30s: %(state)s" % job
)
1053 def handle_jobs_show(self
):
1054 (job_id
,) = self
.args
.job_id
1056 job
= self
.client
.get_job(job_id
)
1058 print _("A job with ID %s could not be found.") % job_id
1062 if job
["builder_id"]:
1063 builder
= self
.client
.get_builder(job
["builder_id"])
1065 print _("Job: %(name)s") % job
1069 fmt
% (_("State"), job
["state"]),
1070 fmt
% (_("Arch"), job
["arch"]),
1075 fmt
% (_("Build host"), builder
["name"]),
1080 fmt
% (_("Time created"), job
["time_created"]),
1081 fmt
% (_("Time started"), job
["time_started"]),
1082 fmt
% (_("Time finished"), job
["time_finished"]),
1083 fmt
% (_("Duration"), job
["duration"]),
1087 lines
+= ["", "%s:" % _("Packages")]
1089 for pkg
in job
["packages"]:
1091 "* %(friendly_name)s" % pkg
,
1096 lines
+= [" %s" % line
for line
in pkg_lines
]
1103 class CliDaemon(Cli
):
1105 self
.parser
= argparse
.ArgumentParser(
1106 description
= _("Pakfire daemon command line interface."),
1109 self
.parse_common_arguments(repo_manage_switches
=True, offline_switch
=True)
1111 # Finally parse all arguments from the command line and save them.
1112 self
.args
= self
.parser
.parse_args()
1116 Runs the pakfire daemon with provided settings.
1118 # Read the configuration file for the daemon.
1119 conf
= config
.ConfigDaemon()
1121 # Create daemon instance.
1122 d
= pakfire
.client
.PakfireDaemon(
1123 server
= conf
.get("daemon", "server"),
1124 hostname
= conf
.get("daemon", "hostname"),
1125 secret
= conf
.get("daemon", "secret"),
1131 # We cannot just kill the daemon, it needs a smooth shutdown.
1132 except (SystemExit, KeyboardInterrupt):
1138 self
.parser
= argparse
.ArgumentParser(
1139 description
= _("Pakfire key command line interface."),
1142 self
.parse_common_arguments(repo_manage_switches
=False,
1143 offline_switch
=True)
1146 self
.sub_commands
= self
.parser
.add_subparsers()
1148 self
.parse_command_init()
1149 self
.parse_command_generate()
1150 self
.parse_command_import()
1151 self
.parse_command_export()
1152 self
.parse_command_delete()
1153 self
.parse_command_list()
1154 self
.parse_command_sign()
1155 self
.parse_command_verify()
1157 # Finally parse all arguments from the command line and save them.
1158 self
.args
= self
.parser
.parse_args()
1160 # Create a pakfire instance.
1161 self
.pakfire
= pakfire
.Pakfire(**self
.pakfire_args
)
1163 self
.action2func
= {
1164 "init" : self
.handle_init
,
1165 "generate" : self
.handle_generate
,
1166 "import" : self
.handle_import
,
1167 "export" : self
.handle_export
,
1168 "delete" : self
.handle_delete
,
1169 "list" : self
.handle_list
,
1170 "sign" : self
.handle_sign
,
1171 "verify" : self
.handle_verify
,
1175 def pakfire_args(self
):
1182 def parse_command_init(self
):
1183 # Parse "init" command.
1184 sub_init
= self
.sub_commands
.add_parser("init",
1185 help=_("Initialize the local keyring."))
1186 sub_init
.add_argument("action", action
="store_const", const
="init")
1188 def parse_command_generate(self
):
1189 # Parse "generate" command.
1190 sub_gen
= self
.sub_commands
.add_parser("generate",
1191 help=_("Import a key from file."))
1192 sub_gen
.add_argument("--realname", nargs
=1,
1193 help=_("The real name of the owner of this key."))
1194 sub_gen
.add_argument("--email", nargs
=1,
1195 help=_("The email address of the owner of this key."))
1196 sub_gen
.add_argument("action", action
="store_const", const
="generate")
1198 def parse_command_import(self
):
1199 # Parse "import" command.
1200 sub_import
= self
.sub_commands
.add_parser("import",
1201 help=_("Import a key from file."))
1202 sub_import
.add_argument("filename", nargs
=1,
1203 help=_("Filename of that key to import."))
1204 sub_import
.add_argument("action", action
="store_const", const
="import")
1206 def parse_command_export(self
):
1207 # Parse "export" command.
1208 sub_export
= self
.sub_commands
.add_parser("export",
1209 help=_("Export a key to a file."))
1210 sub_export
.add_argument("keyid", nargs
=1,
1211 help=_("The ID of the key to export."))
1212 sub_export
.add_argument("filename", nargs
=1,
1213 help=_("Write the key to this file."))
1214 sub_export
.add_argument("action", action
="store_const", const
="export")
1216 def parse_command_delete(self
):
1217 # Parse "delete" command.
1218 sub_del
= self
.sub_commands
.add_parser("delete",
1219 help=_("Delete a key from the local keyring."))
1220 sub_del
.add_argument("keyid", nargs
=1,
1221 help=_("The ID of the key to delete."))
1222 sub_del
.add_argument("action", action
="store_const", const
="delete")
1224 def parse_command_list(self
):
1225 # Parse "list" command.
1226 sub_list
= self
.sub_commands
.add_parser("list",
1227 help=_("List all imported keys."))
1228 sub_list
.add_argument("action", action
="store_const", const
="list")
1230 def parse_command_sign(self
):
1231 # Implement the "sign" command.
1232 sub_sign
= self
.sub_commands
.add_parser("sign",
1233 help=_("Sign one or more packages."))
1234 sub_sign
.add_argument("--key", "-k", nargs
=1,
1235 help=_("Key that is used sign the package(s)."))
1236 sub_sign
.add_argument("package", nargs
="+",
1237 help=_("Package(s) to sign."))
1238 sub_sign
.add_argument("action", action
="store_const", const
="sign")
1240 def parse_command_verify(self
):
1241 # Implement the "verify" command.
1242 sub_verify
= self
.sub_commands
.add_parser("verify",
1243 help=_("Verify one or more packages."))
1244 #sub_verify.add_argument("--key", "-k", nargs=1,
1245 # help=_("Key that is used verify the package(s)."))
1246 sub_verify
.add_argument("package", nargs
="+",
1247 help=_("Package(s) to verify."))
1248 sub_verify
.add_argument("action", action
="store_const", const
="verify")
1250 def handle_init(self
):
1251 # Initialize the keyring...
1252 pakfire
.key_init(**self
.pakfire_args
)
1254 def handle_generate(self
):
1255 realname
= self
.args
.realname
[0]
1256 email
= self
.args
.email
[0]
1258 print _("Generating the key may take a moment...")
1262 pakfire
.key_generate(realname
, email
, **self
.pakfire_args
)
1264 def handle_import(self
):
1265 filename
= self
.args
.filename
[0]
1267 # Simply import the file.
1268 pakfire
.key_import(filename
, **self
.pakfire_args
)
1270 def handle_export(self
):
1271 keyid
= self
.args
.keyid
[0]
1272 filename
= self
.args
.filename
[0]
1274 pakfire
.key_export(keyid
, filename
, **self
.pakfire_args
)
1276 def handle_delete(self
):
1277 keyid
= self
.args
.keyid
[0]
1279 pakfire
.key_delete(keyid
, **self
.pakfire_args
)
1281 def handle_list(self
):
1282 lines
= pakfire
.key_list(**self
.pakfire_args
)
1287 def handle_sign(self
):
1288 # Get the files from the command line options
1291 for file in self
.args
.package
:
1292 # Check, if we got a regular file
1293 if os
.path
.exists(file):
1294 file = os
.path
.abspath(file)
1298 raise FileNotFoundError
, file
1300 key
= self
.args
.key
[0]
1304 pkg
= packages
.open(self
.pakfire
, None, file)
1306 print _("Signing %s...") % pkg
.friendly_name
1309 def handle_verify(self
):
1310 # Get the files from the command line options
1313 for file in self
.args
.package
:
1314 # Check, if we got a regular file
1315 if os
.path
.exists(file) and not os
.path
.isdir(file):
1316 file = os
.path
.abspath(file)
1321 pkg
= packages
.open(self
.pakfire
, None, file)
1323 print _("Verifying %s...") % pkg
.friendly_name
1327 key
= self
.pakfire
.keyring
.get_key(sig
.fpr
)
1329 subkey
= key
.subkeys
[0]
1331 print " %s %s" % (subkey
.fpr
[-16:], key
.uids
[0].uid
)
1333 print " %s" % _("This signature is valid.")
1336 print " %s <%s>" % (sig
.fpr
, _("Unknown key"))
1337 print " %s" % _("Could not check if this signature is valid.")
1339 created
= datetime
.datetime
.fromtimestamp(sig
.timestamp
)
1340 print " %s" % _("Created: %s") % created
1342 if sig
.exp_timestamp
:
1343 expires
= datetime
.datetime
.fromtimestamp(sig
.exp_timestamp
)
1344 print " %s" % _("Expires: %s") % expires