]>
git.ipfire.org Git - pakfire.git/blob - python/pakfire/cli.py
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 ###############################################################################
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()
48 pakfire
= base
.Pakfire
51 self
.parser
= argparse
.ArgumentParser(
52 description
= _("Pakfire command line interface."),
55 self
.parse_common_arguments()
57 self
.parser
.add_argument("--root", metavar
="PATH",
59 help=_("The path where pakfire should operate in."))
62 self
.sub_commands
= self
.parser
.add_subparsers()
64 self
.parse_command_install()
65 self
.parse_command_reinstall()
66 self
.parse_command_remove()
67 self
.parse_command_info()
68 self
.parse_command_search()
69 self
.parse_command_check_update()
70 self
.parse_command_update()
71 self
.parse_command_downgrade()
72 self
.parse_command_provides()
73 self
.parse_command_grouplist()
74 self
.parse_command_groupinstall()
75 self
.parse_command_repolist()
76 self
.parse_command_clean()
77 self
.parse_command_check()
78 self
.parse_command_resolvdep()
80 # Finally parse all arguments from the command line and save them.
81 self
.args
= self
.parser
.parse_args()
84 "install" : self
.handle_install
,
85 "reinstall" : self
.handle_reinstall
,
86 "remove" : self
.handle_remove
,
87 "check_update" : self
.handle_check_update
,
88 "update" : self
.handle_update
,
89 "downgrade" : self
.handle_downgrade
,
90 "info" : self
.handle_info
,
91 "search" : self
.handle_search
,
92 "provides" : self
.handle_provides
,
93 "grouplist" : self
.handle_grouplist
,
94 "groupinstall" : self
.handle_groupinstall
,
95 "repolist" : self
.handle_repolist
,
96 "clean_all" : self
.handle_clean_all
,
97 "check" : self
.handle_check
,
98 "resolvdep" : self
.handle_resolvdep
,
102 def pakfire_args(self
):
105 if hasattr(self
.args
, "root"):
106 ret
["path"] = self
.args
.root
108 if hasattr(self
.args
, "disable_repo"):
109 ret
["disable_repos"] = self
.args
.disable_repo
111 if hasattr(self
.args
, "enable_repo"):
112 ret
["enable_repos"] = self
.args
.enable_repo
114 if hasattr(self
.args
, "offline") and self
.args
.offline
:
115 ret
["downloader"] = {
116 "offline" : self
.args
.offline
,
119 if hasattr(self
.args
, "config"):
120 ret
["configs"] = self
.args
.config
122 ret
["configs"] = None
126 def parse_common_arguments(self
, repo_manage_switches
=True, offline_switch
=True):
127 self
.parser
.add_argument("--version", action
="version",
128 version
="%(prog)s " + PAKFIRE_VERSION
)
130 self
.parser
.add_argument("-v", "--verbose", action
="store_true",
131 help=_("Enable verbose output."))
133 self
.parser
.add_argument("-c", "--config", nargs
="?",
134 help=_("Path to a configuration file to load."))
136 if repo_manage_switches
:
137 self
.parser
.add_argument("--disable-repo", nargs
="*", metavar
="REPO",
138 help=_("Disable a repository temporarily."))
140 self
.parser
.add_argument("--enabled-repo", nargs
="*", metavar
="REPO",
141 help=_("Enable a repository temporarily."))
144 self
.parser
.add_argument("--offline", action
="store_true",
145 help=_("Run pakfire in offline mode."))
147 def parse_command_install(self
):
148 # Implement the "install" command.
149 sub_install
= self
.sub_commands
.add_parser("install",
150 help=_("Install one or more packages to the system."))
151 sub_install
.add_argument("package", nargs
="+",
152 help=_("Give name of at least one package to install."))
153 sub_install
.add_argument("--without-recommends", action
="store_true",
154 help=_("Don't install recommended packages."))
155 sub_install
.add_argument("action", action
="store_const", const
="install")
157 def parse_command_reinstall(self
):
158 # Implement the "reinstall" command.
159 sub_install
= self
.sub_commands
.add_parser("reinstall",
160 help=_("Reinstall one or more packages."))
161 sub_install
.add_argument("package", nargs
="+",
162 help=_("Give name of at least one package to reinstall."))
163 sub_install
.add_argument("action", action
="store_const", const
="reinstall")
165 def parse_command_remove(self
):
166 # Implement the "remove" command.
167 sub_remove
= self
.sub_commands
.add_parser("remove",
168 help=_("Remove one or more packages from the system."))
169 sub_remove
.add_argument("package", nargs
="+",
170 help=_("Give name of at least one package to remove."))
171 sub_remove
.add_argument("action", action
="store_const", const
="remove")
174 def _parse_command_update(parser
):
175 parser
.add_argument("package", nargs
="*",
176 help=_("Give a name of a package to update or leave emtpy for all."))
177 parser
.add_argument("--exclude", "-x", nargs
="+",
178 help=_("Exclude package from update."))
179 parser
.add_argument("--allow-vendorchange", action
="store_true",
180 help=_("Allow changing the vendor of packages."))
181 parser
.add_argument("--allow-archchange", action
="store_true",
182 help=_("Allow changing the architecture of packages."))
184 def parse_command_update(self
):
185 # Implement the "update" command.
186 sub_update
= self
.sub_commands
.add_parser("update",
187 help=_("Update the whole system or one specific package."))
188 sub_update
.add_argument("action", action
="store_const", const
="update")
189 self
._parse
_command
_update
(sub_update
)
191 def parse_command_check_update(self
):
192 # Implement the "check-update" command.
193 sub_check_update
= self
.sub_commands
.add_parser("check-update",
194 help=_("Check, if there are any updates available."))
195 sub_check_update
.add_argument("action", action
="store_const", const
="check_update")
196 self
._parse
_command
_update
(sub_check_update
)
198 def parse_command_downgrade(self
):
199 # Implement the "downgrade" command.
200 sub_downgrade
= self
.sub_commands
.add_parser("downgrade",
201 help=_("Downgrade one or more packages."))
202 sub_downgrade
.add_argument("package", nargs
="*",
203 help=_("Give a name of a package to downgrade."))
204 sub_downgrade
.add_argument("--allow-vendorchange", action
="store_true",
205 help=_("Allow changing the vendor of packages."))
206 sub_downgrade
.add_argument("--allow-archchange", action
="store_true",
207 help=_("Allow changing the architecture of packages."))
208 sub_downgrade
.add_argument("action", action
="store_const", const
="downgrade")
210 def parse_command_info(self
):
211 # Implement the "info" command.
212 sub_info
= self
.sub_commands
.add_parser("info",
213 help=_("Print some information about the given package(s)."))
214 sub_info
.add_argument("package", nargs
="+",
215 help=_("Give at least the name of one package."))
216 sub_info
.add_argument("action", action
="store_const", const
="info")
218 def parse_command_search(self
):
219 # Implement the "search" command.
220 sub_search
= self
.sub_commands
.add_parser("search",
221 help=_("Search for a given pattern."))
222 sub_search
.add_argument("pattern",
223 help=_("A pattern to search for."))
224 sub_search
.add_argument("action", action
="store_const", const
="search")
226 def parse_command_provides(self
):
227 # Implement the "provides" command
228 sub_provides
= self
.sub_commands
.add_parser("provides",
229 help=_("Get a list of packages that provide a given file or feature."))
230 sub_provides
.add_argument("pattern", nargs
="+",
231 help=_("File or feature to search for."))
232 sub_provides
.add_argument("action", action
="store_const", const
="provides")
234 def parse_command_grouplist(self
):
235 # Implement the "grouplist" command
236 sub_grouplist
= self
.sub_commands
.add_parser("grouplist",
237 help=_("Get list of packages that belong to the given group."))
238 sub_grouplist
.add_argument("group", nargs
=1,
239 help=_("Group name to search for."))
240 sub_grouplist
.add_argument("action", action
="store_const", const
="grouplist")
242 def parse_command_groupinstall(self
):
243 # Implement the "grouplist" command
244 sub_groupinstall
= self
.sub_commands
.add_parser("groupinstall",
245 help=_("Install all packages that belong to the given group."))
246 sub_groupinstall
.add_argument("group", nargs
=1,
247 help=_("Group name."))
248 sub_groupinstall
.add_argument("action", action
="store_const", const
="groupinstall")
250 def parse_command_repolist(self
):
251 # Implement the "repolist" command
252 sub_repolist
= self
.sub_commands
.add_parser("repolist",
253 help=_("List all currently enabled repositories."))
254 sub_repolist
.add_argument("action", action
="store_const", const
="repolist")
256 def parse_command_clean(self
):
257 sub_clean
= self
.sub_commands
.add_parser("clean", help=_("Cleanup commands."))
259 sub_clean_commands
= sub_clean
.add_subparsers()
261 self
.parse_command_clean_all(sub_clean_commands
)
263 def parse_command_clean_all(self
, sub_commands
):
264 sub_create
= sub_commands
.add_parser("all",
265 help=_("Cleanup all temporary files."))
266 sub_create
.add_argument("action", action
="store_const", const
="clean_all")
268 def parse_command_check(self
):
269 # Implement the "check" command
270 sub_check
= self
.sub_commands
.add_parser("check",
271 help=_("Check the system for any errors."))
272 sub_check
.add_argument("action", action
="store_const", const
="check")
274 def parse_command_resolvdep(self
):
275 # Implement the "resolvdep" command.
276 sub_resolvdep
= self
.sub_commands
.add_parser("resolvdep",
277 help=_("Check the dependencies for a particular package."))
278 sub_resolvdep
.add_argument("package", nargs
=1,
279 help=_("Give name of at least one package to check."))
280 sub_resolvdep
.add_argument("action", action
="store_const", const
="resolvdep")
283 action
= self
.args
.action
286 func
= self
.action2func
[action
]
288 raise Exception, "Unhandled action: %s" % action
292 def handle_info(self
, long=False):
293 p
= self
.pakfire(**self
.pakfire_args
)
295 for pkg
in p
.info(self
.args
.package
):
296 print pkg
.dump(long=long)
298 def handle_search(self
):
299 p
= self
.pakfire(**self
.pakfire_args
)
301 for pkg
in p
.search(self
.args
.pattern
):
302 print pkg
.dump(short
=True)
304 def handle_update(self
, **args
):
305 p
= self
.pakfire(**self
.pakfire_args
)
308 excludes
=self
.args
.exclude
,
309 allow_vendorchange
=self
.args
.allow_vendorchange
,
310 allow_archchange
=self
.args
.allow_archchange
,
314 def handle_check_update(self
):
315 self
.handle_update(check
=True)
317 def handle_downgrade(self
, **args
):
318 p
= self
.pakfire(**self
.pakfire_args
)
321 allow_vendorchange
=self
.args
.allow_vendorchange
,
322 allow_archchange
=self
.args
.allow_archchange
,
326 def handle_install(self
):
327 p
= self
.pakfire(**self
.pakfire_args
)
328 p
.install(self
.args
.package
, ignore_recommended
=self
.args
.without_recommends
)
330 def handle_reinstall(self
):
331 p
= self
.pakfire(**self
.pakfire_args
)
332 p
.reinstall(self
.args
.package
)
334 def handle_remove(self
):
335 p
= self
.pakfire(**self
.pakfire_args
)
336 p
.remove(self
.args
.package
)
338 def handle_provides(self
, long=False):
339 p
= self
.pakfire(**self
.pakfire_args
)
341 for pkg
in p
.provides(self
.args
.pattern
):
342 print pkg
.dump(long=long)
344 def handle_grouplist(self
):
345 p
= self
.pakfire(**self
.pakfire_args
)
347 for pkg
in p
.grouplist(self
.args
.group
[0]):
350 def handle_groupinstall(self
):
351 p
= self
.pakfire(**self
.pakfire_args
)
352 p
.groupinstall(self
.args
.group
[0])
354 def handle_repolist(self
):
355 p
= self
.pakfire(**self
.pakfire_args
)
357 FORMAT
= " %-20s %8s %12s %12s "
358 title
= FORMAT
% (_("Repository"), _("Enabled"), _("Priority"), _("Packages"))
360 print "=" * len(title
) # spacing line
362 for repo
in p
.repo_list():
363 # Skip the installed repository.
364 if repo
.name
== "installed":
367 print FORMAT
% (repo
.name
, repo
.enabled
, repo
.priority
, len(repo
))
369 def handle_clean_all(self
):
370 print _("Cleaning up everything...")
372 p
= self
.pakfire(**self
.pakfire_args
)
375 def handle_check(self
):
376 p
= self
.pakfire(**self
.pakfire_args
)
379 def handle_resolvdep(self
):
380 p
= self
.pakfire(**self
.pakfire_args
)
382 (pkg
,) = self
.args
.package
384 solver
= p
.pool
.resolvdep(pkg
)
387 t
= transaction
.Transaction
.from_solver(p
, solver
)
391 class CliBuilder(Cli
):
392 pakfire
= base
.PakfireBuilder
395 # Check if we are already running in a pakfire container. In that
396 # case, we cannot start another pakfire-builder.
397 if os
.environ
.get("container", None) == "pakfire-builder":
398 raise PakfireContainerError
, _("You cannot run pakfire-builder in a pakfire chroot.")
400 self
.parser
= argparse
.ArgumentParser(
401 description
= _("Pakfire builder command line interface."),
404 self
.parse_common_arguments()
407 self
.sub_commands
= self
.parser
.add_subparsers()
409 self
.parse_command_build()
410 self
.parse_command_dist()
411 self
.parse_command_info()
412 self
.parse_command_search()
413 self
.parse_command_shell()
414 self
.parse_command_update()
415 self
.parse_command_provides()
416 self
.parse_command_grouplist()
417 self
.parse_command_repolist()
418 self
.parse_command_clean()
419 self
.parse_command_resolvdep()
421 # Finally parse all arguments from the command line and save them.
422 self
.args
= self
.parser
.parse_args()
425 "build" : self
.handle_build
,
426 "dist" : self
.handle_dist
,
427 "update" : self
.handle_update
,
428 "info" : self
.handle_info
,
429 "search" : self
.handle_search
,
430 "shell" : self
.handle_shell
,
431 "provides" : self
.handle_provides
,
432 "grouplist" : self
.handle_grouplist
,
433 "repolist" : self
.handle_repolist
,
434 "clean_all" : self
.handle_clean_all
,
435 "resolvdep" : self
.handle_resolvdep
,
439 def pakfire_args(self
):
442 if hasattr(self
.args
, "disable_repo"):
443 ret
["disable_repos"] = self
.args
.disable_repo
445 if hasattr(self
.args
, "enable_repo"):
446 ret
["enable_repos"] = self
.args
.enable_repo
448 if hasattr(self
.args
, "offline") and self
.args
.offline
:
449 ret
["downloader"] = {
450 "offline" : self
.args
.offline
,
453 if hasattr(self
.args
, "distro"):
454 ret
["distro_name"] = self
.args
.distro
458 def parse_common_arguments(self
, *args
, **kwargs
):
459 Cli
.parse_common_arguments(self
, *args
, **kwargs
)
461 self
.parser
.add_argument("--distro", nargs
="?",
462 help=_("Choose the distribution configuration to use for build"))
464 def parse_command_update(self
):
465 # Implement the "update" command.
466 sub_update
= self
.sub_commands
.add_parser("update",
467 help=_("Update the package indexes."))
468 sub_update
.add_argument("action", action
="store_const", const
="update")
470 def parse_command_build(self
):
471 # Implement the "build" command.
472 sub_build
= self
.sub_commands
.add_parser("build",
473 help=_("Build one or more packages."))
474 sub_build
.add_argument("package", nargs
=1,
475 help=_("Give name of at least one package to build."))
476 sub_build
.add_argument("action", action
="store_const", const
="build")
478 sub_build
.add_argument("-a", "--arch",
479 help=_("Build the package for the given architecture."))
480 sub_build
.add_argument("--resultdir", nargs
="?",
481 help=_("Path were the output files should be copied to."))
482 sub_build
.add_argument("-m", "--mode", nargs
="?", default
="development",
483 help=_("Mode to run in. Is either 'release' or 'development' (default)."))
484 sub_build
.add_argument("--after-shell", action
="store_true",
485 help=_("Run a shell after a successful build."))
486 sub_build
.add_argument("--no-install-test", action
="store_true",
487 help=_("Do not perform the install test."))
489 def parse_command_shell(self
):
490 # Implement the "shell" command.
491 sub_shell
= self
.sub_commands
.add_parser("shell",
492 help=_("Go into a shell."))
493 sub_shell
.add_argument("package", nargs
="?",
494 help=_("Give name of a package."))
495 sub_shell
.add_argument("action", action
="store_const", const
="shell")
497 sub_shell
.add_argument("-a", "--arch",
498 help=_("Emulated architecture in the shell."))
499 sub_shell
.add_argument("-m", "--mode", nargs
="?", default
="development",
500 help=_("Mode to run in. Is either 'release' or 'development' (default)."))
502 def parse_command_dist(self
):
503 # Implement the "dist" command.
504 sub_dist
= self
.sub_commands
.add_parser("dist",
505 help=_("Generate a source package."))
506 sub_dist
.add_argument("package", nargs
="+",
507 help=_("Give name(s) of a package(s)."))
508 sub_dist
.add_argument("action", action
="store_const", const
="dist")
510 sub_dist
.add_argument("--resultdir", nargs
="?",
511 help=_("Path were the output files should be copied to."))
513 def handle_info(self
):
514 Cli
.handle_info(self
, long=True)
516 def handle_build(self
):
517 # Get the package descriptor from the command line options
518 pkg
= self
.args
.package
[0]
520 # Check, if we got a regular file
521 if os
.path
.exists(pkg
):
522 pkg
= os
.path
.abspath(pkg
)
525 raise FileNotFoundError
, pkg
527 # Check whether to enable the install test.
528 install_test
= not self
.args
.no_install_test
530 if self
.args
.mode
== "release":
533 release_build
= False
535 p
= self
.pakfire(arch
=self
.args
.arch
, **self
.pakfire_args
)
537 install_test
=install_test
,
538 resultdirs
=[self
.args
.resultdir
,],
540 after_shell
=self
.args
.after_shell
,
541 release_build
=release_build
,
544 def handle_shell(self
):
547 # Get the package descriptor from the command line options
548 if self
.args
.package
:
549 pkg
= self
.args
.package
551 # Check, if we got a regular file
552 if os
.path
.exists(pkg
):
553 pkg
= os
.path
.abspath(pkg
)
556 raise FileNotFoundError
, pkg
558 if self
.args
.mode
== "release":
561 release_build
= False
563 p
= self
.pakfire(arch
=self
.args
.arch
, **self
.pakfire_args
)
564 p
.shell(pkg
, release_build
=release_build
)
566 def handle_dist(self
):
567 # Get the packages from the command line options
570 for pkg
in self
.args
.package
:
571 # Check, if we got a regular file
572 if os
.path
.exists(pkg
):
573 pkg
= os
.path
.abspath(pkg
)
577 raise FileNotFoundError
, pkg
579 # Put packages to where the user said or our
580 # current working directory.
581 resultdir
= self
.args
.resultdir
or os
.getcwd()
583 p
= self
.pakfire(**self
.pakfire_args
)
585 p
.dist(pkg
, resultdir
=resultdir
)
587 def handle_provides(self
):
588 Cli
.handle_provides(long=True)
591 class CliServer(Cli
):
592 pakfire
= base
.PakfireServer
595 self
.parser
= argparse
.ArgumentParser(
596 description
= _("Pakfire server command line interface."),
599 self
.parse_common_arguments()
602 self
.sub_commands
= self
.parser
.add_subparsers()
604 self
.parse_command_build()
605 self
.parse_command_keepalive()
606 self
.parse_command_repoupdate()
607 self
.parse_command_repo()
608 self
.parse_command_info()
610 # Finally parse all arguments from the command line and save them.
611 self
.args
= self
.parser
.parse_args()
613 self
.server
= server
.Server(**self
.pakfire_args
)
616 "build" : self
.handle_build
,
617 "info" : self
.handle_info
,
618 "keepalive" : self
.handle_keepalive
,
619 "repoupdate" : self
.handle_repoupdate
,
620 "repo_create": self
.handle_repo_create
,
624 def pakfire_args(self
):
627 if hasattr(self
.args
, "offline") and self
.args
.offline
:
628 ret
["downloader"] = {
629 "offline" : self
.args
.offline
,
634 def parse_command_build(self
):
635 # Implement the "build" command.
636 sub_build
= self
.sub_commands
.add_parser("build",
637 help=_("Send a scrach build job to the server."))
638 sub_build
.add_argument("package", nargs
=1,
639 help=_("Give name of at least one package to build."))
640 sub_build
.add_argument("--arch", "-a",
641 help=_("Limit build to only these architecture(s)."))
642 sub_build
.add_argument("action", action
="store_const", const
="build")
644 def parse_command_keepalive(self
):
645 # Implement the "keepalive" command.
646 sub_keepalive
= self
.sub_commands
.add_parser("keepalive",
647 help=_("Send a keepalive to the server."))
648 sub_keepalive
.add_argument("action", action
="store_const",
651 def parse_command_repoupdate(self
):
652 # Implement the "repoupdate" command.
653 sub_repoupdate
= self
.sub_commands
.add_parser("repoupdate",
654 help=_("Update all repositories."))
655 sub_repoupdate
.add_argument("action", action
="store_const",
658 def parse_command_repo(self
):
659 sub_repo
= self
.sub_commands
.add_parser("repo",
660 help=_("Repository management commands."))
662 sub_repo_commands
= sub_repo
.add_subparsers()
664 self
.parse_command_repo_create(sub_repo_commands
)
666 def parse_command_repo_create(self
, sub_commands
):
667 sub_create
= sub_commands
.add_parser("create",
668 help=_("Create a new repository index."))
669 sub_create
.add_argument("path", nargs
=1,
670 help=_("Path to the packages."))
671 sub_create
.add_argument("inputs", nargs
="+",
672 help=_("Path to input packages."))
673 sub_create
.add_argument("--key", "-k", nargs
="?",
674 help=_("Key to sign the repository with."))
675 sub_create
.add_argument("action", action
="store_const", const
="repo_create")
677 def parse_command_info(self
):
678 sub_info
= self
.sub_commands
.add_parser("info",
679 help=_("Dump some information about this machine."))
680 sub_info
.add_argument("action", action
="store_const", const
="info")
682 def handle_keepalive(self
):
683 self
.server
.update_info()
685 def handle_build(self
):
688 arches
= self
.args
.arch
.split()
690 (package
,) = self
.args
.package
692 self
.server
.create_scratch_build({})
695 # Temporary folter for source package.
696 tmpdir
= "/tmp/pakfire-%s" % util
.random_string()
701 pakfire
.dist(package
, resultdir
=[tmpdir
,])
703 for file in os
.listdir(tmpdir
):
704 file = os
.path
.join(tmpdir
, file)
709 if os
.path
.exists(tmpdir
):
712 def handle_repoupdate(self
):
713 self
.server
.update_repositories()
715 def handle_repo_create(self
):
716 path
= self
.args
.path
[0]
718 p
= self
.pakfire(**self
.pakfire_args
)
719 p
.repo_create(path
, self
.args
.inputs
, key_id
=self
.args
.key
)
721 def handle_info(self
):
722 info
= self
.server
.info()
724 print "\n".join(info
)
727 class CliBuilderIntern(Cli
):
729 self
.parser
= argparse
.ArgumentParser(
730 description
= _("Pakfire builder command line interface."),
733 self
.parse_common_arguments()
736 self
.sub_commands
= self
.parser
.add_subparsers()
738 self
.parse_command_build()
740 # Finally parse all arguments from the command line and save them.
741 self
.args
= self
.parser
.parse_args()
744 "build" : self
.handle_build
,
747 def parse_command_build(self
):
748 # Implement the "build" command.
749 sub_build
= self
.sub_commands
.add_parser("build",
750 help=_("Build one or more packages."))
751 sub_build
.add_argument("package", nargs
=1,
752 help=_("Give name of at least one package to build."))
753 sub_build
.add_argument("action", action
="store_const", const
="build")
755 sub_build
.add_argument("-a", "--arch",
756 help=_("Build the package for the given architecture."))
757 sub_build
.add_argument("--resultdir", nargs
="?",
758 help=_("Path were the output files should be copied to."))
759 sub_build
.add_argument("-m", "--mode", nargs
="?", default
="development",
760 help=_("Mode to run in. Is either 'release' or 'development' (default)."))
761 sub_build
.add_argument("--nodeps", action
="store_true",
762 help=_("Do not verify build dependencies."))
763 sub_build
.add_argument("--prepare", action
="store_true",
764 help=_("Only run the prepare stage."))
766 def handle_build(self
):
767 # Get the package descriptor from the command line options
768 pkg
= self
.args
.package
[0]
770 # Check, if we got a regular file
771 if os
.path
.exists(pkg
):
772 pkg
= os
.path
.abspath(pkg
)
774 raise FileNotFoundError
, pkg
776 # Create pakfire instance.
777 c
= config
.ConfigBuilder()
778 p
= base
.Pakfire(arch
= self
.args
.arch
, config
= c
)
780 # Disable all repositories.
782 p
.repos
.disable_repo("*")
784 # Limit stages that are to be run.
785 if self
.args
.prepare
:
790 p
.build(pkg
, resultdir
=self
.args
.resultdir
, stages
=stages
)
793 class CliClient(Cli
):
795 self
.parser
= argparse
.ArgumentParser(
796 description
= _("Pakfire client command line interface."),
799 self
.parse_common_arguments(repo_manage_switches
=True, offline_switch
=True)
802 self
.sub_commands
= self
.parser
.add_subparsers()
804 self
.parse_command_build()
805 self
.parse_command_connection_check()
806 self
.parse_command_info()
807 self
.parse_command_jobs()
808 self
.parse_command_builds()
809 self
.parse_command_test()
811 # Finally parse all arguments from the command line and save them.
812 self
.args
= self
.parser
.parse_args()
815 "build" : self
.handle_build
,
816 "conn-check" : self
.handle_connection_check
,
817 "info" : self
.handle_info
,
818 "jobs_show" : self
.handle_jobs_show
,
819 "jobs_active" : self
.handle_jobs_active
,
820 "jobs_latest" : self
.handle_jobs_latest
,
821 "builds_show" : self
.handle_builds_show
,
822 "test" : self
.handle_test
,
825 # Read configuration for the pakfire client.
826 self
.conf
= conf
= config
.ConfigClient()
828 # Create connection to pakfire hub.
829 self
.client
= client
.PakfireUserClient(
830 conf
.get("client", "server"),
831 conf
.get("client", "username"),
832 conf
.get("client", "password"),
835 def parse_command_build(self
):
836 # Parse "build" command.
837 sub_build
= self
.sub_commands
.add_parser("build",
838 help=_("Build a package remotely."))
839 sub_build
.add_argument("package", nargs
=1,
840 help=_("Give name of a package to build."))
841 sub_build
.add_argument("action", action
="store_const", const
="build")
843 sub_build
.add_argument("-a", "--arch",
844 help=_("Build the package for the given architecture."))
846 def parse_command_info(self
):
847 # Implement the "info" command.
848 sub_info
= self
.sub_commands
.add_parser("info",
849 help=_("Print some information about this host."))
850 sub_info
.add_argument("action", action
="store_const", const
="info")
852 def parse_command_connection_check(self
):
853 # Implement the "conn-check" command.
854 sub_conn_check
= self
.sub_commands
.add_parser("conn-check",
855 help=_("Check the connection to the hub."))
856 sub_conn_check
.add_argument("action", action
="store_const", const
="conn-check")
858 def parse_command_jobs(self
):
859 sub_jobs
= self
.sub_commands
.add_parser("jobs",
860 help=_("Show information about build jobs."))
862 sub_jobs_commands
= sub_jobs
.add_subparsers()
864 self
.parse_command_jobs_active(sub_jobs_commands
)
865 self
.parse_command_jobs_latest(sub_jobs_commands
)
866 self
.parse_command_jobs_show(sub_jobs_commands
)
868 def parse_command_jobs_active(self
, sub_commands
):
869 sub_active
= sub_commands
.add_parser("active",
870 help=_("Show a list of all active jobs."))
871 sub_active
.add_argument("action", action
="store_const", const
="jobs_active")
873 def parse_command_jobs_latest(self
, sub_commands
):
874 sub_latest
= sub_commands
.add_parser("latest",
875 help=_("Show a list of all recently finished of failed build jobs."))
876 sub_latest
.add_argument("action", action
="store_const", const
="jobs_latest")
878 def parse_command_jobs_show(self
, sub_commands
):
879 sub_show
= sub_commands
.add_parser("show",
880 help=_("Show details about given build job."))
881 sub_show
.add_argument("job_id", nargs
=1, help=_("The ID of the build job."))
882 sub_show
.add_argument("action", action
="store_const", const
="jobs_show")
884 def parse_command_builds(self
):
885 sub_builds
= self
.sub_commands
.add_parser("builds",
886 help=_("Show information about builds."))
888 sub_builds_commands
= sub_builds
.add_subparsers()
890 self
.parse_command_builds_show(sub_builds_commands
)
892 def parse_command_builds_show(self
, sub_commands
):
893 sub_show
= sub_commands
.add_parser("show",
894 help=_("Show details about the given build."))
895 sub_show
.add_argument("build_id", nargs
=1, help=_("The ID of the build."))
896 sub_show
.add_argument("action", action
="store_const", const
="builds_show")
898 def parse_command_test(self
):
899 sub_test
= self
.sub_commands
.add_parser("test",
900 help=_("Test the connection to the hub."))
901 sub_test
.add_argument("error_code", nargs
=1, help=_("Error code to test."))
902 sub_test
.add_argument("action", action
="store_const", const
="test")
904 def handle_build(self
):
905 (package
,) = self
.args
.package
907 # XXX just for now, we do only upload source pfm files.
908 assert os
.path
.exists(package
)
910 # Create a temporary directory.
911 temp_dir
= tempfile
.mkdtemp()
914 if package
.endswith(".%s" % MAKEFILE_EXTENSION
):
917 # Create a source package from the makefile.
918 p
= self
.pakfire(**self
.pakfire_args
)
919 package
= p
.dist(package
, temp_dir
)
921 elif package
.endswith(".%s" % PACKAGE_EXTENSION
):
925 raise Exception, "Unknown filetype: %s" % package
929 arches
= self
.args
.arch
.replace(",", " ")
933 # Create a new build on the server.
934 build
= self
.client
.build_create(package
, arches
=arches
)
936 # XXX Print the resulting build.
940 # Cleanup the temporary directory and all files.
941 if os
.path
.exists(temp_dir
):
942 shutil
.rmtree(temp_dir
, ignore_errors
=True)
944 def handle_info(self
):
948 ret
.append(" PAKFIRE %s" % PAKFIRE_VERSION
)
950 ret
.append(" %-20s: %s" % (_("Hostname"), system
.hostname
))
951 ret
.append(" %-20s: %s" % (_("Pakfire hub"), self
.conf
.get("client", "server")))
952 if self
.conf
.get("client", "username") and self
.conf
.get("client", "password"):
953 ret
.append(" %-20s: %s" % \
954 (_("Username"), self
.conf
.get("client", "username")))
957 # Hardware information
958 ret
.append(" %s:" % _("Hardware information"))
959 ret
.append(" %-16s: %s" % (_("CPU model"), system
.cpu_model
))
960 ret
.append(" %-16s: %s" % (_("Memory"), util
.format_size(system
.memory
)))
961 ret
.append(" %-16s: %s" % (_("Parallelism"), system
.parallelism
))
963 ret
.append(" %-16s: %s" % (_("Native arch"), system
.native_arch
))
964 if not system
.arch
== system
.native_arch
:
965 ret
.append(" %-16s: %s" % (_("Default arch"), system
.arch
))
967 header
= _("Supported arches")
968 for arch
in system
.supported_arches
:
969 ret
.append(" %-16s: %s" % (header
, arch
))
976 def handle_connection_check(self
):
979 address
= self
.client
.get_my_address()
980 ret
.append(" %-20s: %s" % (_("Your IP address"), address
))
983 authenticated
= self
.client
.check_auth()
985 ret
.append(" %s" % _("You are authenticated to the build service:"))
987 user
= self
.client
.get_user_profile()
988 assert user
, "Could not fetch user infomation"
991 ("name", _("User name")),
992 ("realname", _("Real name")),
993 ("email", _("Email address")),
994 ("registered", _("Registered")),
997 for key
, desc
in keys
:
998 ret
.append(" %-18s: %s" % (desc
, user
.get(key
)))
1001 ret
.append(_("You could not be authenticated to the build service."))
1006 def _print_jobs(self
, jobs
, heading
=None):
1008 print "%s:" % heading
1012 line
= " [%(type)8s] %(name)-30s: %(state)s"
1016 print # Empty line at the end.
1018 def handle_jobs_active(self
):
1019 jobs
= self
.client
.get_active_jobs()
1022 print _("No ongoing jobs found.")
1025 self
._print
_jobs
(jobs
, _("Active build jobs"))
1027 def handle_jobs_latest(self
):
1028 jobs
= self
.client
.get_latest_jobs()
1031 print _("No jobs found.")
1034 self
._print
_jobs
(jobs
, _("Recently processed build jobs"))
1036 def handle_builds_show(self
):
1037 (build_id
,) = self
.args
.build_id
1039 build
= self
.client
.get_build(build_id
)
1041 print _("A build with ID %s could not be found.") % build_id
1044 print _("Build: %(name)s") % build
1048 fmt
% (_("State"), build
["state"]),
1049 fmt
% (_("Priority"), build
["priority"]),
1052 lines
.append("%s:" % _("Jobs"))
1053 for job
in build
["jobs"]:
1054 lines
.append(" * [%(uuid)s] %(name)-30s: %(state)s" % job
)
1060 def handle_jobs_show(self
):
1061 (job_id
,) = self
.args
.job_id
1063 job
= self
.client
.get_job(job_id
)
1065 print _("A job with ID %s could not be found.") % job_id
1069 if job
["builder_id"]:
1070 builder
= self
.client
.get_builder(job
["builder_id"])
1072 print _("Job: %(name)s") % job
1076 fmt
% (_("State"), job
["state"]),
1077 fmt
% (_("Arch"), job
["arch"]),
1082 fmt
% (_("Build host"), builder
["name"]),
1087 fmt
% (_("Time created"), job
["time_created"]),
1088 fmt
% (_("Time started"), job
["time_started"]),
1089 fmt
% (_("Time finished"), job
["time_finished"]),
1090 fmt
% (_("Duration"), job
["duration"]),
1094 lines
+= ["", "%s:" % _("Packages")]
1096 for pkg
in job
["packages"]:
1098 "* %(friendly_name)s" % pkg
,
1103 lines
+= [" %s" % line
for line
in pkg_lines
]
1109 def handle_test(self
):
1110 error_code
= self
.args
.error_code
[0]
1113 error_code
= int(error_code
)
1117 if error_code
< 100 or error_code
> 999:
1118 raise Error
, _("Invalid error code given.")
1120 res
= self
.client
.test_code(error_code
)
1121 print _("Reponse from the server: %s") % res
1124 class CliDaemon(Cli
):
1126 self
.parser
= argparse
.ArgumentParser(
1127 description
= _("Pakfire daemon command line interface."),
1130 self
.parse_common_arguments(repo_manage_switches
=True, offline_switch
=True)
1132 # Finally parse all arguments from the command line and save them.
1133 self
.args
= self
.parser
.parse_args()
1137 Runs the pakfire daemon with provided settings.
1139 # Read the configuration file for the daemon.
1140 conf
= config
.ConfigDaemon()
1142 # Create daemon instance.
1143 d
= pakfire
.client
.PakfireDaemon()
1147 # We cannot just kill the daemon, it needs a smooth shutdown.
1148 except (SystemExit, KeyboardInterrupt):
1154 self
.parser
= argparse
.ArgumentParser(
1155 description
= _("Pakfire key command line interface."),
1158 self
.parse_common_arguments(repo_manage_switches
=False,
1159 offline_switch
=True)
1162 self
.sub_commands
= self
.parser
.add_subparsers()
1164 self
.parse_command_generate()
1165 self
.parse_command_import()
1166 self
.parse_command_export()
1167 self
.parse_command_delete()
1168 self
.parse_command_list()
1169 self
.parse_command_sign()
1170 self
.parse_command_verify()
1172 # Finally parse all arguments from the command line and save them.
1173 self
.args
= self
.parser
.parse_args()
1175 self
.action2func
= {
1176 "generate" : self
.handle_generate
,
1177 "import" : self
.handle_import
,
1178 "export" : self
.handle_export
,
1179 "delete" : self
.handle_delete
,
1180 "list" : self
.handle_list
,
1181 "sign" : self
.handle_sign
,
1182 "verify" : self
.handle_verify
,
1186 def pakfire_args(self
):
1189 def parse_command_generate(self
):
1190 # Parse "generate" command.
1191 sub_gen
= self
.sub_commands
.add_parser("generate",
1192 help=_("Import a key from file."))
1193 sub_gen
.add_argument("--realname", nargs
=1,
1194 help=_("The real name of the owner of this key."))
1195 sub_gen
.add_argument("--email", nargs
=1,
1196 help=_("The email address of the owner of this key."))
1197 sub_gen
.add_argument("action", action
="store_const", const
="generate")
1199 def parse_command_import(self
):
1200 # Parse "import" command.
1201 sub_import
= self
.sub_commands
.add_parser("import",
1202 help=_("Import a key from file."))
1203 sub_import
.add_argument("filename", nargs
=1,
1204 help=_("Filename of that key to import."))
1205 sub_import
.add_argument("action", action
="store_const", const
="import")
1207 def parse_command_export(self
):
1208 # Parse "export" command.
1209 sub_export
= self
.sub_commands
.add_parser("export",
1210 help=_("Export a key to a file."))
1211 sub_export
.add_argument("keyid", nargs
=1,
1212 help=_("The ID of the key to export."))
1213 sub_export
.add_argument("filename", nargs
=1,
1214 help=_("Write the key to this file."))
1215 sub_export
.add_argument("--secret", action
="store_true",
1216 help=_("Export the secret key, too."))
1217 sub_export
.add_argument("action", action
="store_const", const
="export")
1219 def parse_command_delete(self
):
1220 # Parse "delete" command.
1221 sub_del
= self
.sub_commands
.add_parser("delete",
1222 help=_("Delete a key from the local keyring."))
1223 sub_del
.add_argument("keyid", nargs
=1,
1224 help=_("The ID of the key to delete."))
1225 sub_del
.add_argument("action", action
="store_const", const
="delete")
1227 def parse_command_list(self
):
1228 # Parse "list" command.
1229 sub_list
= self
.sub_commands
.add_parser("list",
1230 help=_("List all imported keys."))
1231 sub_list
.add_argument("action", action
="store_const", const
="list")
1233 def parse_command_sign(self
):
1234 # Implement the "sign" command.
1235 sub_sign
= self
.sub_commands
.add_parser("sign",
1236 help=_("Sign one or more packages."))
1237 sub_sign
.add_argument("--key", "-k", nargs
=1,
1238 help=_("Key that is used sign the package(s)."))
1239 sub_sign
.add_argument("package", nargs
="+",
1240 help=_("Package(s) to sign."))
1241 sub_sign
.add_argument("action", action
="store_const", const
="sign")
1243 def parse_command_verify(self
):
1244 # Implement the "verify" command.
1245 sub_verify
= self
.sub_commands
.add_parser("verify",
1246 help=_("Verify one or more packages."))
1247 #sub_verify.add_argument("--key", "-k", nargs=1,
1248 # help=_("Key that is used verify the package(s)."))
1249 sub_verify
.add_argument("package", nargs
="+",
1250 help=_("Package(s) to verify."))
1251 sub_verify
.add_argument("action", action
="store_const", const
="verify")
1253 def handle_generate(self
):
1254 realname
= self
.args
.realname
[0]
1255 email
= self
.args
.email
[0]
1257 print _("Generating the key may take a moment...")
1261 p
= self
.pakfire(**self
.pakfire_args
)
1262 p
.key_generate(realname
, email
)
1264 def handle_import(self
):
1265 filename
= self
.args
.filename
[0]
1267 # Simply import the file.
1268 p
= self
.pakfire(**self
.pakfire_args
)
1269 p
.key_import(filename
)
1271 def handle_export(self
):
1272 keyid
= self
.args
.keyid
[0]
1273 filename
= self
.args
.filename
[0]
1274 secret
= self
.args
.secret
1276 p
= self
.pakfire(**self
.pakfire_args
)
1277 p
.key_export(keyid
, filename
, secret
=secret
)
1279 def handle_delete(self
):
1280 keyid
= self
.args
.keyid
[0]
1282 p
= self
.pakfire(**self
.pakfire_args
)
1285 def handle_list(self
):
1286 p
= self
.pakfire(**self
.pakfire_args
)
1287 for line
in p
.key_list():
1290 def handle_sign(self
):
1291 # Get the files from the command line options
1294 for file in self
.args
.package
:
1295 # Check, if we got a regular file
1296 if os
.path
.exists(file):
1297 file = os
.path
.abspath(file)
1301 raise FileNotFoundError
, file
1303 key
= self
.args
.key
[0]
1305 # Create pakfire instance.
1306 p
= self
.pakfire(**self
.pakfire_args
)
1310 pkg
= packages
.open(p
, None, file)
1312 print _("Signing %s...") % pkg
.friendly_name
1315 def handle_verify(self
):
1316 # Get the files from the command line options
1319 for file in self
.args
.package
:
1320 # Check, if we got a regular file
1321 if os
.path
.exists(file) and not os
.path
.isdir(file):
1322 file = os
.path
.abspath(file)
1325 # Create pakfire instance.
1326 p
= self
.pakfire(**self
.pakfire_args
)
1330 pkg
= packages
.open(p
, None, file)
1332 print _("Verifying %s...") % pkg
.friendly_name
1336 key
= self
.pakfire
.keyring
.get_key(sig
.fpr
)
1338 subkey
= key
.subkeys
[0]
1340 print " %s %s" % (subkey
.fpr
[-16:], key
.uids
[0].uid
)
1342 print " %s" % _("This signature is valid.")
1345 print " %s <%s>" % (sig
.fpr
, _("Unknown key"))
1346 print " %s" % _("Could not check if this signature is valid.")
1348 created
= datetime
.datetime
.fromtimestamp(sig
.timestamp
)
1349 print " %s" % _("Created: %s") % created
1351 if sig
.exp_timestamp
:
1352 expires
= datetime
.datetime
.fromtimestamp(sig
.exp_timestamp
)
1353 print " %s" % _("Expires: %s") % expires