]>
git.ipfire.org Git - people/ms/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 ###############################################################################
40 from system
import system
41 from constants
import *
44 # Initialize a very simple logging that is removed when a Pakfire instance
46 logger
.setup_logging()
49 pakfire
= base
.Pakfire
52 self
.parser
= argparse
.ArgumentParser(
53 description
= _("Pakfire command line interface."),
56 self
.parse_common_arguments()
58 self
.parser
.add_argument("--root", metavar
="PATH",
60 help=_("The path where pakfire should operate in."))
63 self
.sub_commands
= self
.parser
.add_subparsers()
65 self
.parse_command_install()
66 self
.parse_command_reinstall()
67 self
.parse_command_remove()
68 self
.parse_command_info()
69 self
.parse_command_search()
70 self
.parse_command_check_update()
71 self
.parse_command_distro_sync()
72 self
.parse_command_update()
73 self
.parse_command_downgrade()
74 self
.parse_command_provides()
75 self
.parse_command_grouplist()
76 self
.parse_command_groupinstall()
77 self
.parse_command_repolist()
78 self
.parse_command_clean()
79 self
.parse_command_check()
80 self
.parse_command_resolvdep()
81 self
.parse_command_extract()
83 # Finally parse all arguments from the command line and save them.
84 self
.args
= self
.parser
.parse_args()
87 "install" : self
.handle_install
,
88 "reinstall" : self
.handle_reinstall
,
89 "remove" : self
.handle_remove
,
90 "check_update" : self
.handle_check_update
,
91 "distro_sync" : self
.handle_distro_sync
,
92 "update" : self
.handle_update
,
93 "downgrade" : self
.handle_downgrade
,
94 "info" : self
.handle_info
,
95 "search" : self
.handle_search
,
96 "provides" : self
.handle_provides
,
97 "grouplist" : self
.handle_grouplist
,
98 "groupinstall" : self
.handle_groupinstall
,
99 "repolist" : self
.handle_repolist
,
100 "clean_all" : self
.handle_clean_all
,
101 "check" : self
.handle_check
,
102 "resolvdep" : self
.handle_resolvdep
,
103 "extract" : self
.handle_extract
,
107 def pakfire_args(self
):
110 if hasattr(self
.args
, "root"):
111 ret
["path"] = self
.args
.root
113 if hasattr(self
.args
, "offline") and self
.args
.offline
:
114 ret
["downloader"] = {
115 "offline" : self
.args
.offline
,
118 if hasattr(self
.args
, "config"):
119 ret
["configs"] = self
.args
.config
121 ret
["configs"] = None
125 def create_pakfire(self
, cls
=None, **kwargs
):
129 args
= self
.pakfire_args
134 # Disable repositories.
135 for repo
in self
.args
.disable_repo
:
136 p
.repos
.disable_repo(repo
)
138 # Enable repositories.
139 for repo
in self
.args
.enable_repo
:
140 p
.repos
.enable_repo(repo
)
144 def parse_common_arguments(self
, offline_switch
=True):
145 self
.parser
.add_argument("--version", action
="version",
146 version
="%(prog)s " + PAKFIRE_VERSION
)
148 self
.parser
.add_argument("-v", "--verbose", action
="store_true",
149 help=_("Enable verbose output."))
151 self
.parser
.add_argument("-c", "--config", nargs
="?",
152 help=_("Path to a configuration file to load."))
154 self
.parser
.add_argument("--disable-repo", nargs
="*", metavar
="REPO",
155 help=_("Disable a repository temporarily."), default
=[])
157 self
.parser
.add_argument("--enable-repo", nargs
="*", metavar
="REPO",
158 help=_("Enable a repository temporarily."), default
=[])
161 self
.parser
.add_argument("--offline", action
="store_true",
162 help=_("Run pakfire in offline mode."))
164 def parse_command_install(self
):
165 # Implement the "install" command.
166 sub_install
= self
.sub_commands
.add_parser("install",
167 help=_("Install one or more packages to the system."))
168 sub_install
.add_argument("package", nargs
="+",
169 help=_("Give name of at least one package to install."))
170 sub_install
.add_argument("--without-recommends", action
="store_true",
171 help=_("Don't install recommended packages."))
172 sub_install
.add_argument("action", action
="store_const", const
="install")
174 def parse_command_reinstall(self
):
175 # Implement the "reinstall" command.
176 sub_install
= self
.sub_commands
.add_parser("reinstall",
177 help=_("Reinstall one or more packages."))
178 sub_install
.add_argument("package", nargs
="+",
179 help=_("Give name of at least one package to reinstall."))
180 sub_install
.add_argument("action", action
="store_const", const
="reinstall")
182 def parse_command_remove(self
):
183 # Implement the "remove" command.
184 sub_remove
= self
.sub_commands
.add_parser("remove",
185 help=_("Remove one or more packages from the system."))
186 sub_remove
.add_argument("package", nargs
="+",
187 help=_("Give name of at least one package to remove."))
188 sub_remove
.add_argument("action", action
="store_const", const
="remove")
191 def _parse_command_update(parser
, package
=True):
193 parser
.add_argument("package", nargs
="*",
194 help=_("Give a name of a package to update or leave emtpy for all."))
196 parser
.add_argument("--exclude", "-x", nargs
="+",
197 help=_("Exclude package from update."))
198 parser
.add_argument("--allow-vendorchange", action
="store_true",
199 help=_("Allow changing the vendor of packages."))
200 parser
.add_argument("--disallow-archchange", action
="store_true",
201 help=_("Disallow changing the architecture of packages."))
203 def parse_command_update(self
):
204 # Implement the "update" command.
205 sub_update
= self
.sub_commands
.add_parser("update",
206 help=_("Update the whole system or one specific package."))
207 sub_update
.add_argument("action", action
="store_const", const
="update")
208 self
._parse
_command
_update
(sub_update
)
210 def parse_command_distro_sync(self
):
211 # Implement the "distro-sync" command.
212 sub_distro_sync
= self
.sub_commands
.add_parser("distro-sync",
213 help=_("Sync all installed with the latest one in the distribution."))
214 sub_distro_sync
.add_argument("action", action
="store_const", const
="distro_sync")
215 self
._parse
_command
_update
(sub_distro_sync
, package
=False)
217 def parse_command_check_update(self
):
218 # Implement the "check-update" command.
219 sub_check_update
= self
.sub_commands
.add_parser("check-update",
220 help=_("Check, if there are any updates available."))
221 sub_check_update
.add_argument("action", action
="store_const", const
="check_update")
222 self
._parse
_command
_update
(sub_check_update
)
224 def parse_command_downgrade(self
):
225 # Implement the "downgrade" command.
226 sub_downgrade
= self
.sub_commands
.add_parser("downgrade",
227 help=_("Downgrade one or more packages."))
228 sub_downgrade
.add_argument("package", nargs
="*",
229 help=_("Give a name of a package to downgrade."))
230 sub_downgrade
.add_argument("--allow-vendorchange", action
="store_true",
231 help=_("Allow changing the vendor of packages."))
232 sub_downgrade
.add_argument("--disallow-archchange", action
="store_true",
233 help=_("Disallow changing the architecture of packages."))
234 sub_downgrade
.add_argument("action", action
="store_const", const
="downgrade")
236 def parse_command_info(self
):
237 # Implement the "info" command.
238 sub_info
= self
.sub_commands
.add_parser("info",
239 help=_("Print some information about the given package(s)."))
240 sub_info
.add_argument("package", nargs
="+",
241 help=_("Give at least the name of one package."))
242 sub_info
.add_argument("action", action
="store_const", const
="info")
244 def parse_command_search(self
):
245 # Implement the "search" command.
246 sub_search
= self
.sub_commands
.add_parser("search",
247 help=_("Search for a given pattern."))
248 sub_search
.add_argument("pattern",
249 help=_("A pattern to search for."))
250 sub_search
.add_argument("action", action
="store_const", const
="search")
252 def parse_command_provides(self
):
253 # Implement the "provides" command
254 sub_provides
= self
.sub_commands
.add_parser("provides",
255 help=_("Get a list of packages that provide a given file or feature."))
256 sub_provides
.add_argument("pattern", nargs
="+",
257 help=_("File or feature to search for."))
258 sub_provides
.add_argument("action", action
="store_const", const
="provides")
260 def parse_command_grouplist(self
):
261 # Implement the "grouplist" command
262 sub_grouplist
= self
.sub_commands
.add_parser("grouplist",
263 help=_("Get list of packages that belong to the given group."))
264 sub_grouplist
.add_argument("group", nargs
=1,
265 help=_("Group name to search for."))
266 sub_grouplist
.add_argument("action", action
="store_const", const
="grouplist")
268 def parse_command_groupinstall(self
):
269 # Implement the "grouplist" command
270 sub_groupinstall
= self
.sub_commands
.add_parser("groupinstall",
271 help=_("Install all packages that belong to the given group."))
272 sub_groupinstall
.add_argument("group", nargs
=1,
273 help=_("Group name."))
274 sub_groupinstall
.add_argument("action", action
="store_const", const
="groupinstall")
276 def parse_command_repolist(self
):
277 # Implement the "repolist" command
278 sub_repolist
= self
.sub_commands
.add_parser("repolist",
279 help=_("List all currently enabled repositories."))
280 sub_repolist
.add_argument("action", action
="store_const", const
="repolist")
282 def parse_command_clean(self
):
283 sub_clean
= self
.sub_commands
.add_parser("clean", help=_("Cleanup commands."))
285 sub_clean_commands
= sub_clean
.add_subparsers()
287 self
.parse_command_clean_all(sub_clean_commands
)
289 def parse_command_clean_all(self
, sub_commands
):
290 sub_create
= sub_commands
.add_parser("all",
291 help=_("Cleanup all temporary files."))
292 sub_create
.add_argument("action", action
="store_const", const
="clean_all")
294 def parse_command_check(self
):
295 # Implement the "check" command
296 sub_check
= self
.sub_commands
.add_parser("check",
297 help=_("Check the system for any errors."))
298 sub_check
.add_argument("action", action
="store_const", const
="check")
300 def parse_command_resolvdep(self
):
301 # Implement the "resolvdep" command.
302 sub_resolvdep
= self
.sub_commands
.add_parser("resolvdep",
303 help=_("Check the dependencies for a particular package."))
304 sub_resolvdep
.add_argument("package", nargs
=1,
305 help=_("Give name of at least one package to check."))
306 sub_resolvdep
.add_argument("action", action
="store_const", const
="resolvdep")
308 def parse_command_extract(self
):
309 # Implement the "extract" command.
310 sub_extract
= self
.sub_commands
.add_parser("extract",
311 help=_("Extract a package to a directory."))
312 sub_extract
.add_argument("package", nargs
="+",
313 help=_("Give name of the file to extract."))
314 sub_extract
.add_argument("--target", nargs
="?",
315 help=_("Target directory where to extract to."))
316 sub_extract
.add_argument("action", action
="store_const", const
="extract")
319 action
= self
.args
.action
322 func
= self
.action2func
[action
]
324 raise Exception, "Unhandled action: %s" % action
328 def handle_info(self
, long=False):
329 p
= self
.create_pakfire()
331 for pkg
in p
.info(self
.args
.package
):
332 print pkg
.dump(long=long)
334 def handle_search(self
):
335 p
= self
.create_pakfire()
337 for pkg
in p
.search(self
.args
.pattern
):
338 print pkg
.dump(short
=True)
340 def handle_update(self
, **args
):
341 p
= self
.create_pakfire()
343 packages
= getattr(self
.args
, "package", [])
346 "allow_archchange" : not self
.args
.disallow_archchange
,
347 "allow_vendorchange" : self
.args
.allow_vendorchange
,
348 "excludes" : self
.args
.exclude
,
351 p
.update(packages
, **args
)
353 def handle_distro_sync(self
):
354 self
.handle_update(sync
=True)
356 def handle_check_update(self
):
357 self
.handle_update(check
=True)
359 def handle_downgrade(self
, **args
):
360 p
= self
.create_pakfire()
363 allow_vendorchange
=self
.args
.allow_vendorchange
,
364 allow_archchange
=not self
.args
.disallow_archchange
,
368 def handle_install(self
):
369 p
= self
.create_pakfire()
370 p
.install(self
.args
.package
, ignore_recommended
=self
.args
.without_recommends
)
372 def handle_reinstall(self
):
373 p
= self
.create_pakfire()
374 p
.reinstall(self
.args
.package
)
376 def handle_remove(self
):
377 p
= self
.create_pakfire()
378 p
.remove(self
.args
.package
)
380 def handle_provides(self
, long=False):
381 p
= self
.create_pakfire()
383 for pkg
in p
.provides(self
.args
.pattern
):
384 print pkg
.dump(long=long)
386 def handle_grouplist(self
):
387 p
= self
.create_pakfire()
389 for pkg
in p
.grouplist(self
.args
.group
[0]):
392 def handle_groupinstall(self
):
393 p
= self
.create_pakfire()
394 p
.groupinstall(self
.args
.group
[0])
396 def handle_repolist(self
):
397 p
= self
.create_pakfire()
399 # Get a list of all repositories.
400 repos
= p
.repo_list()
402 FORMAT
= " %-20s %8s %12s %12s "
403 title
= FORMAT
% (_("Repository"), _("Enabled"), _("Priority"), _("Packages"))
405 print "=" * len(title
) # spacing line
408 print FORMAT
% (repo
.name
, repo
.enabled
, repo
.priority
, len(repo
))
410 def handle_clean_all(self
):
411 print _("Cleaning up everything...")
413 p
= self
.create_pakfire()
416 def handle_check(self
):
417 p
= self
.create_pakfire()
420 def handle_resolvdep(self
):
421 p
= self
.create_pakfire()
423 (pkg
,) = self
.args
.package
425 solver
= p
.resolvdep(pkg
)
428 t
= transaction
.Transaction
.from_solver(p
, solver
)
431 def handle_extract(self
):
432 p
= self
.create_pakfire()
436 for pkg
in self
.args
.package
:
437 pkg
= packages
.open(self
, None, pkg
)
440 target_prefix
= self
.args
.target
442 # Search for binary packages.
443 binary_packages
= any([p
.type == "binary" for p
in pkgs
])
444 source_packages
= any([p
.type == "source" for p
in pkgs
])
446 if binary_packages
and source_packages
:
447 raise Error
, _("Cannot extract mixed package types")
449 if binary_packages
and not target_prefix
:
450 raise Error
, _("You must provide an install directory with --target=...")
452 elif source_packages
and not target_prefix
:
453 target_prefix
= "/usr/src/packages/"
455 if target_prefix
== "/":
456 raise Error
, _("Cannot extract to /.")
459 if pkg
.type == "binary":
460 target_dir
= target_prefix
461 elif pkg
.type == "source":
462 target_dir
= os
.path
.join(target_prefix
, pkg
.friendly_name
)
464 pkg
.extract(message
=_("Extracting"), prefix
=target_dir
)
467 class CliBuilder(Cli
):
468 pakfire
= base
.PakfireBuilder
471 # Check if we are already running in a pakfire container. In that
472 # case, we cannot start another pakfire-builder.
473 if os
.environ
.get("container", None) == "pakfire-builder":
474 raise PakfireContainerError
, _("You cannot run pakfire-builder in a pakfire chroot.")
476 self
.parser
= argparse
.ArgumentParser(
477 description
= _("Pakfire builder command line interface."),
480 self
.parse_common_arguments()
483 self
.sub_commands
= self
.parser
.add_subparsers()
485 self
.parse_command_build()
486 self
.parse_command_dist()
487 self
.parse_command_info()
488 self
.parse_command_search()
489 self
.parse_command_shell()
490 self
.parse_command_update()
491 self
.parse_command_provides()
492 self
.parse_command_grouplist()
493 self
.parse_command_repolist()
494 self
.parse_command_clean()
495 self
.parse_command_resolvdep()
496 self
.parse_command_extract()
498 # Finally parse all arguments from the command line and save them.
499 self
.args
= self
.parser
.parse_args()
502 "build" : self
.handle_build
,
503 "dist" : self
.handle_dist
,
504 "update" : self
.handle_update
,
505 "info" : self
.handle_info
,
506 "search" : self
.handle_search
,
507 "shell" : self
.handle_shell
,
508 "provides" : self
.handle_provides
,
509 "grouplist" : self
.handle_grouplist
,
510 "repolist" : self
.handle_repolist
,
511 "clean_all" : self
.handle_clean_all
,
512 "resolvdep" : self
.handle_resolvdep
,
513 "extract" : self
.handle_extract
,
517 def pakfire_args(self
):
519 "arch" : self
.args
.arch
,
522 if hasattr(self
.args
, "offline") and self
.args
.offline
:
523 ret
["downloader"] = {
524 "offline" : self
.args
.offline
,
527 if hasattr(self
.args
, "distro"):
528 ret
["distro_name"] = self
.args
.distro
532 def parse_common_arguments(self
, *args
, **kwargs
):
533 Cli
.parse_common_arguments(self
, *args
, **kwargs
)
535 self
.parser
.add_argument("--distro", nargs
="?",
536 help=_("Choose the distribution configuration to use for build"))
538 self
.parser
.add_argument("--arch", "-a", nargs
="?",
539 help=_("Run pakfire for the given architecture."))
541 def parse_command_update(self
):
542 # Implement the "update" command.
543 sub_update
= self
.sub_commands
.add_parser("update",
544 help=_("Update the package indexes."))
545 sub_update
.add_argument("action", action
="store_const", const
="update")
547 def parse_command_build(self
):
548 # Implement the "build" command.
549 sub_build
= self
.sub_commands
.add_parser("build",
550 help=_("Build one or more packages."))
551 sub_build
.add_argument("package", nargs
=1,
552 help=_("Give name of at least one package to build."))
553 sub_build
.add_argument("action", action
="store_const", const
="build")
555 sub_build
.add_argument("--resultdir", nargs
="?",
556 help=_("Path were the output files should be copied to."))
557 sub_build
.add_argument("-m", "--mode", nargs
="?", default
="development",
558 help=_("Mode to run in. Is either 'release' or 'development' (default)."))
559 sub_build
.add_argument("--after-shell", action
="store_true",
560 help=_("Run a shell after a successful build."))
561 sub_build
.add_argument("--no-install-test", action
="store_true",
562 help=_("Do not perform the install test."))
563 sub_build
.add_argument("--private-network", action
="store_true",
564 help=_("Disable network in container."))
566 def parse_command_shell(self
):
567 # Implement the "shell" command.
568 sub_shell
= self
.sub_commands
.add_parser("shell",
569 help=_("Go into a shell."))
570 sub_shell
.add_argument("package", nargs
="?",
571 help=_("Give name of a package."))
572 sub_shell
.add_argument("action", action
="store_const", const
="shell")
574 sub_shell
.add_argument("-m", "--mode", nargs
="?", default
="development",
575 help=_("Mode to run in. Is either 'release' or 'development' (default)."))
576 sub_shell
.add_argument("--private-network", action
="store_true",
577 help=_("Disable network in container."))
579 def parse_command_dist(self
):
580 # Implement the "dist" command.
581 sub_dist
= self
.sub_commands
.add_parser("dist",
582 help=_("Generate a source package."))
583 sub_dist
.add_argument("package", nargs
="+",
584 help=_("Give name(s) of a package(s)."))
585 sub_dist
.add_argument("action", action
="store_const", const
="dist")
587 sub_dist
.add_argument("--resultdir", nargs
="?",
588 help=_("Path were the output files should be copied to."))
590 def handle_info(self
):
591 Cli
.handle_info(self
, long=True)
593 def handle_build(self
):
594 # Get the package descriptor from the command line options
595 pkg
= self
.args
.package
[0]
597 # Check, if we got a regular file
598 if os
.path
.exists(pkg
):
599 pkg
= os
.path
.abspath(pkg
)
602 raise FileNotFoundError
, pkg
604 # Build argument list.
606 "after_shell" : self
.args
.after_shell
,
607 # Check whether to enable the install test.
608 "install_test" : not self
.args
.no_install_test
,
609 "result_dir" : [self
.args
.resultdir
,],
613 if self
.args
.mode
== "release":
614 kwargs
["release_build"] = True
616 kwargs
["release_build"] = False
618 if self
.args
.private_network
:
619 kwargs
["private_network"] = True
621 p
= self
.create_pakfire()
622 p
.build(pkg
, **kwargs
)
624 def handle_shell(self
):
627 # Get the package descriptor from the command line options
628 if self
.args
.package
:
629 pkg
= self
.args
.package
631 # Check, if we got a regular file
632 if os
.path
.exists(pkg
):
633 pkg
= os
.path
.abspath(pkg
)
636 raise FileNotFoundError
, pkg
638 if self
.args
.mode
== "release":
641 release_build
= False
643 p
= self
.create_pakfire()
646 "release_build" : release_build
,
650 if self
.args
.private_network
:
651 kwargs
["private_network"] = True
653 p
.shell(pkg
, **kwargs
)
655 def handle_dist(self
):
656 # Get the packages from the command line options
659 for pkg
in self
.args
.package
:
660 # Check, if we got a regular file
661 if os
.path
.exists(pkg
):
662 pkg
= os
.path
.abspath(pkg
)
666 raise FileNotFoundError
, pkg
668 # Put packages to where the user said or our
669 # current working directory.
670 resultdir
= self
.args
.resultdir
or os
.getcwd()
672 p
= self
.create_pakfire()
674 p
.dist(pkg
, resultdir
=resultdir
)
676 def handle_provides(self
):
677 Cli
.handle_provides(self
, long=True)
680 class CliServer(Cli
):
681 pakfire
= base
.PakfireServer
684 self
.parser
= argparse
.ArgumentParser(
685 description
= _("Pakfire server command line interface."),
688 self
.parse_common_arguments()
691 self
.sub_commands
= self
.parser
.add_subparsers()
693 self
.parse_command_build()
694 self
.parse_command_keepalive()
695 self
.parse_command_repoupdate()
696 self
.parse_command_repo()
697 self
.parse_command_info()
699 # Finally parse all arguments from the command line and save them.
700 self
.args
= self
.parser
.parse_args()
702 #self.server = server.Server(**self.pakfire_args)
705 "build" : self
.handle_build
,
706 "info" : self
.handle_info
,
707 "keepalive" : self
.handle_keepalive
,
708 "repoupdate" : self
.handle_repoupdate
,
709 "repo_create": self
.handle_repo_create
,
713 def pakfire_args(self
):
716 if hasattr(self
.args
, "offline") and self
.args
.offline
:
717 ret
["downloader"] = {
718 "offline" : self
.args
.offline
,
723 def parse_command_build(self
):
724 # Implement the "build" command.
725 sub_build
= self
.sub_commands
.add_parser("build",
726 help=_("Send a scrach build job to the server."))
727 sub_build
.add_argument("package", nargs
=1,
728 help=_("Give name of at least one package to build."))
729 sub_build
.add_argument("--arch", "-a",
730 help=_("Limit build to only these architecture(s)."))
731 sub_build
.add_argument("action", action
="store_const", const
="build")
733 def parse_command_keepalive(self
):
734 # Implement the "keepalive" command.
735 sub_keepalive
= self
.sub_commands
.add_parser("keepalive",
736 help=_("Send a keepalive to the server."))
737 sub_keepalive
.add_argument("action", action
="store_const",
740 def parse_command_repoupdate(self
):
741 # Implement the "repoupdate" command.
742 sub_repoupdate
= self
.sub_commands
.add_parser("repoupdate",
743 help=_("Update all repositories."))
744 sub_repoupdate
.add_argument("action", action
="store_const",
747 def parse_command_repo(self
):
748 sub_repo
= self
.sub_commands
.add_parser("repo",
749 help=_("Repository management commands."))
751 sub_repo_commands
= sub_repo
.add_subparsers()
753 self
.parse_command_repo_create(sub_repo_commands
)
755 def parse_command_repo_create(self
, sub_commands
):
756 sub_create
= sub_commands
.add_parser("create",
757 help=_("Create a new repository index."))
758 sub_create
.add_argument("path", nargs
=1,
759 help=_("Path to the packages."))
760 sub_create
.add_argument("inputs", nargs
="+",
761 help=_("Path to input packages."))
762 sub_create
.add_argument("--key", "-k", nargs
="?",
763 help=_("Key to sign the repository with."))
764 sub_create
.add_argument("action", action
="store_const", const
="repo_create")
766 def parse_command_info(self
):
767 sub_info
= self
.sub_commands
.add_parser("info",
768 help=_("Dump some information about this machine."))
769 sub_info
.add_argument("action", action
="store_const", const
="info")
771 def handle_keepalive(self
):
772 self
.server
.update_info()
774 def handle_build(self
):
777 arches
= self
.args
.arch
.split()
779 (package
,) = self
.args
.package
781 self
.server
.create_scratch_build({})
784 # Temporary folter for source package.
785 tmpdir
= "/tmp/pakfire-%s" % util
.random_string()
790 pakfire
.dist(package
, resultdir
=[tmpdir
,])
792 for file in os
.listdir(tmpdir
):
793 file = os
.path
.join(tmpdir
, file)
798 if os
.path
.exists(tmpdir
):
801 def handle_repoupdate(self
):
802 self
.server
.update_repositories()
804 def handle_repo_create(self
):
805 path
= self
.args
.path
[0]
807 p
= self
.create_pakfire()
808 p
.repo_create(path
, self
.args
.inputs
, key_id
=self
.args
.key
)
810 def handle_info(self
):
811 info
= self
.server
.info()
813 print "\n".join(info
)
816 class CliBuilderIntern(Cli
):
818 self
.parser
= argparse
.ArgumentParser(
819 description
= _("Pakfire builder command line interface."),
822 self
.parse_common_arguments()
825 self
.sub_commands
= self
.parser
.add_subparsers()
827 self
.parse_command_build()
829 # Finally parse all arguments from the command line and save them.
830 self
.args
= self
.parser
.parse_args()
833 "build" : self
.handle_build
,
836 def parse_command_build(self
):
837 # Implement the "build" command.
838 sub_build
= self
.sub_commands
.add_parser("build",
839 help=_("Build one or more packages."))
840 sub_build
.add_argument("package", nargs
=1,
841 help=_("Give name of at least one 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."))
846 sub_build
.add_argument("--resultdir", nargs
="?",
847 help=_("Path were the output files should be copied to."))
848 sub_build
.add_argument("-m", "--mode", nargs
="?", default
="development",
849 help=_("Mode to run in. Is either 'release' or 'development' (default)."))
850 sub_build
.add_argument("--nodeps", action
="store_true",
851 help=_("Do not verify build dependencies."))
852 sub_build
.add_argument("--prepare", action
="store_true",
853 help=_("Only run the prepare stage."))
855 def handle_build(self
):
856 # Get the package descriptor from the command line options
857 pkg
= self
.args
.package
[0]
859 # Check, if we got a regular file
860 if os
.path
.exists(pkg
):
861 pkg
= os
.path
.abspath(pkg
)
863 raise FileNotFoundError
, pkg
865 # Create pakfire instance.
866 c
= config
.ConfigBuilder()
867 p
= base
.Pakfire(arch
= self
.args
.arch
, config
= c
)
869 # Disable all repositories.
871 p
.repos
.disable_repo("*")
873 # Limit stages that are to be run.
874 if self
.args
.prepare
:
879 p
.build(pkg
, resultdir
=self
.args
.resultdir
, stages
=stages
)
882 class CliClient(Cli
):
883 pakfire
= base
.PakfireClient
886 self
.parser
= argparse
.ArgumentParser(
887 description
= _("Pakfire client command line interface."),
890 self
.parse_common_arguments(offline_switch
=True)
893 self
.sub_commands
= self
.parser
.add_subparsers()
895 self
.parse_command_build()
896 self
.parse_command_connection_check()
897 self
.parse_command_info()
898 self
.parse_command_jobs()
899 self
.parse_command_builds()
900 self
.parse_command_test()
902 # Finally parse all arguments from the command line and save them.
903 self
.args
= self
.parser
.parse_args()
906 "build" : self
.handle_build
,
907 "conn-check" : self
.handle_connection_check
,
908 "info" : self
.handle_info
,
909 "jobs_show" : self
.handle_jobs_show
,
910 "jobs_active" : self
.handle_jobs_active
,
911 "jobs_latest" : self
.handle_jobs_latest
,
912 "builds_show" : self
.handle_builds_show
,
913 "test" : self
.handle_test
,
916 # Read configuration.
917 self
.config
= config
.ConfigClient()
919 # Create connection to pakfire hub.
920 self
.client
= client
.PakfireClient(self
.config
)
923 def pakfire_args(self
):
925 "config" : self
.config
,
928 def parse_command_build(self
):
929 # Parse "build" command.
930 sub_build
= self
.sub_commands
.add_parser("build",
931 help=_("Build a package remotely."))
932 sub_build
.add_argument("package", nargs
=1,
933 help=_("Give name of a package to build."))
934 sub_build
.add_argument("action", action
="store_const", const
="build")
936 sub_build
.add_argument("-a", "--arch",
937 help=_("Build the package for the given architecture."))
939 def parse_command_info(self
):
940 # Implement the "info" command.
941 sub_info
= self
.sub_commands
.add_parser("info",
942 help=_("Print some information about this host."))
943 sub_info
.add_argument("action", action
="store_const", const
="info")
945 def parse_command_connection_check(self
):
946 # Implement the "conn-check" command.
947 sub_conn_check
= self
.sub_commands
.add_parser("conn-check",
948 help=_("Check the connection to the hub."))
949 sub_conn_check
.add_argument("action", action
="store_const", const
="conn-check")
951 def parse_command_jobs(self
):
952 sub_jobs
= self
.sub_commands
.add_parser("jobs",
953 help=_("Show information about build jobs."))
955 sub_jobs_commands
= sub_jobs
.add_subparsers()
957 self
.parse_command_jobs_active(sub_jobs_commands
)
958 self
.parse_command_jobs_latest(sub_jobs_commands
)
959 self
.parse_command_jobs_show(sub_jobs_commands
)
961 def parse_command_jobs_active(self
, sub_commands
):
962 sub_active
= sub_commands
.add_parser("active",
963 help=_("Show a list of all active jobs."))
964 sub_active
.add_argument("action", action
="store_const", const
="jobs_active")
966 def parse_command_jobs_latest(self
, sub_commands
):
967 sub_latest
= sub_commands
.add_parser("latest",
968 help=_("Show a list of all recently finished of failed build jobs."))
969 sub_latest
.add_argument("action", action
="store_const", const
="jobs_latest")
971 def parse_command_jobs_show(self
, sub_commands
):
972 sub_show
= sub_commands
.add_parser("show",
973 help=_("Show details about given build job."))
974 sub_show
.add_argument("job_id", nargs
=1, help=_("The ID of the build job."))
975 sub_show
.add_argument("action", action
="store_const", const
="jobs_show")
977 def parse_command_builds(self
):
978 sub_builds
= self
.sub_commands
.add_parser("builds",
979 help=_("Show information about builds."))
981 sub_builds_commands
= sub_builds
.add_subparsers()
983 self
.parse_command_builds_show(sub_builds_commands
)
985 def parse_command_builds_show(self
, sub_commands
):
986 sub_show
= sub_commands
.add_parser("show",
987 help=_("Show details about the given build."))
988 sub_show
.add_argument("build_id", nargs
=1, help=_("The ID of the build."))
989 sub_show
.add_argument("action", action
="store_const", const
="builds_show")
991 def parse_command_test(self
):
992 sub_test
= self
.sub_commands
.add_parser("test",
993 help=_("Test the connection to the hub."))
994 sub_test
.add_argument("error_code", nargs
=1, help=_("Error code to test."))
995 sub_test
.add_argument("action", action
="store_const", const
="test")
997 def handle_build(self
):
998 (package
,) = self
.args
.package
1000 # XXX just for now, we do only upload source pfm files.
1001 assert os
.path
.exists(package
)
1003 # Create a temporary directory.
1004 temp_dir
= tempfile
.mkdtemp()
1007 if package
.endswith(".%s" % MAKEFILE_EXTENSION
):
1010 # Create a source package from the makefile.
1011 p
= self
.pakfire(**self
.pakfire_args
)
1012 package
= p
.dist(package
, temp_dir
)
1014 elif package
.endswith(".%s" % PACKAGE_EXTENSION
):
1018 raise Exception, "Unknown filetype: %s" % package
1022 arches
= self
.args
.arch
.split(",")
1026 # Create a new build on the server.
1027 build_id
= self
.client
.build_create(package
, build_type
="scratch",
1031 # Cleanup the temporary directory and all files.
1032 if os
.path
.exists(temp_dir
):
1033 shutil
.rmtree(temp_dir
, ignore_errors
=True)
1035 # Monitor the build.
1037 self
.watch_build(build_id
)
1039 def handle_info(self
):
1043 ret
.append(" PAKFIRE %s" % PAKFIRE_VERSION
)
1045 ret
.append(" %-20s: %s" % (_("Hostname"), system
.hostname
))
1046 ret
.append(" %-20s: %s" % (_("Pakfire hub"), self
.config
.get("client", "server")))
1047 if self
.config
.get("client", "username") and self
.config
.get("client", "password"):
1048 ret
.append(" %-20s: %s" % \
1049 (_("Username"), self
.config
.get("client", "username")))
1052 # Hardware information
1053 ret
.append(" %s:" % _("Hardware information"))
1054 ret
.append(" %-16s: %s" % (_("CPU model"), system
.cpu_model
))
1055 ret
.append(" %-16s: %s" % (_("Memory"), util
.format_size(system
.memory
)))
1056 ret
.append(" %-16s: %s" % (_("Parallelism"), system
.parallelism
))
1058 ret
.append(" %-16s: %s" % (_("Native arch"), system
.native_arch
))
1059 if not system
.arch
== system
.native_arch
:
1060 ret
.append(" %-16s: %s" % (_("Default arch"), system
.arch
))
1062 header
= _("Supported arches")
1063 for arch
in system
.supported_arches
:
1064 ret
.append(" %-16s: %s" % (header
, arch
))
1071 def handle_connection_check(self
):
1074 address
= self
.client
.get_my_address()
1075 ret
.append(" %-20s: %s" % (_("Your IP address"), address
))
1078 authenticated
= self
.client
.check_auth()
1080 ret
.append(" %s" % _("You are authenticated to the build service:"))
1082 user
= self
.client
.get_user_profile()
1083 assert user
, "Could not fetch user infomation"
1086 ("name", _("User name")),
1087 ("realname", _("Real name")),
1088 ("email", _("Email address")),
1089 ("registered", _("Registered")),
1092 for key
, desc
in keys
:
1093 ret
.append(" %-18s: %s" % (desc
, user
.get(key
)))
1096 ret
.append(_("You could not be authenticated to the build service."))
1101 def _print_jobs(self
, jobs
, heading
=None):
1103 print "%s:" % heading
1107 line
= " [%(type)8s] %(name)-30s: %(state)s"
1111 print # Empty line at the end.
1113 def handle_jobs_active(self
):
1114 jobs
= self
.client
.get_active_jobs()
1117 print _("No ongoing jobs found.")
1120 self
._print
_jobs
(jobs
, _("Active build jobs"))
1122 def handle_jobs_latest(self
):
1123 jobs
= self
.client
.get_latest_jobs()
1126 print _("No jobs found.")
1129 self
._print
_jobs
(jobs
, _("Recently processed build jobs"))
1131 def handle_builds_show(self
):
1132 (build_id
,) = self
.args
.build_id
1134 build
= self
.client
.get_build(build_id
)
1136 print _("A build with ID %s could not be found.") % build_id
1139 print _("Build: %(name)s") % build
1143 fmt
% (_("State"), build
["state"]),
1144 fmt
% (_("Priority"), build
["priority"]),
1147 lines
.append("%s:" % _("Jobs"))
1148 for job
in build
["jobs"]:
1149 lines
.append(" * [%(uuid)s] %(name)-30s: %(state)s" % job
)
1155 def handle_jobs_show(self
):
1156 (job_id
,) = self
.args
.job_id
1158 job
= self
.client
.get_job(job_id
)
1160 print _("A job with ID %s could not be found.") % job_id
1164 if job
["builder_id"]:
1165 builder
= self
.client
.get_builder(job
["builder_id"])
1167 print _("Job: %(name)s") % job
1171 fmt
% (_("State"), job
["state"]),
1172 fmt
% (_("Arch"), job
["arch"]),
1177 fmt
% (_("Build host"), builder
["name"]),
1182 fmt
% (_("Time created"), job
["time_created"]),
1183 fmt
% (_("Time started"), job
["time_started"]),
1184 fmt
% (_("Time finished"), job
["time_finished"]),
1185 fmt
% (_("Duration"), job
["duration"]),
1189 lines
+= ["", "%s:" % _("Packages")]
1191 for pkg
in job
["packages"]:
1193 "* %(friendly_name)s" % pkg
,
1198 lines
+= [" %s" % line
for line
in pkg_lines
]
1204 def handle_test(self
):
1205 error_code
= self
.args
.error_code
[0]
1208 error_code
= int(error_code
)
1212 if error_code
< 100 or error_code
> 999:
1213 raise Error
, _("Invalid error code given.")
1215 res
= self
.client
.test_code(error_code
)
1216 print _("Reponse from the server: %s") % res
1218 def watch_build(self
, build_id
):
1219 print self
.client
.build_get(build_id
)
1224 class CliDaemon(Cli
):
1226 self
.parser
= argparse
.ArgumentParser(
1227 description
= _("Pakfire daemon command line interface."),
1230 self
.parse_common_arguments(offline_switch
=True)
1232 # Finally parse all arguments from the command line and save them.
1233 self
.args
= self
.parser
.parse_args()
1237 Runs the pakfire daemon with provided settings.
1239 # Read the configuration file for the daemon.
1240 self
.config
= config
.ConfigDaemon()
1241 logger
.setup_logging(self
.config
)
1243 # Create daemon instance.
1244 d
= daemon
.PakfireDaemon(self
.config
)
1248 # We cannot just kill the daemon, it needs a smooth shutdown.
1249 except (SystemExit, KeyboardInterrupt):
1254 pakfire
= base
.PakfireKey
1257 self
.parser
= argparse
.ArgumentParser(
1258 description
= _("Pakfire key command line interface."),
1261 self
.parse_common_arguments(offline_switch
=True)
1264 self
.sub_commands
= self
.parser
.add_subparsers()
1266 self
.parse_command_generate()
1267 self
.parse_command_import()
1268 self
.parse_command_export()
1269 self
.parse_command_delete()
1270 self
.parse_command_list()
1271 self
.parse_command_sign()
1272 self
.parse_command_verify()
1274 # Finally parse all arguments from the command line and save them.
1275 self
.args
= self
.parser
.parse_args()
1277 self
.action2func
= {
1278 "generate" : self
.handle_generate
,
1279 "import" : self
.handle_import
,
1280 "export" : self
.handle_export
,
1281 "delete" : self
.handle_delete
,
1282 "list" : self
.handle_list
,
1283 "sign" : self
.handle_sign
,
1284 "verify" : self
.handle_verify
,
1288 def pakfire_args(self
):
1291 def parse_command_generate(self
):
1292 # Parse "generate" command.
1293 sub_gen
= self
.sub_commands
.add_parser("generate",
1294 help=_("Import a key from file."))
1295 sub_gen
.add_argument("--realname", nargs
=1,
1296 help=_("The real name of the owner of this key."))
1297 sub_gen
.add_argument("--email", nargs
=1,
1298 help=_("The email address of the owner of this key."))
1299 sub_gen
.add_argument("action", action
="store_const", const
="generate")
1301 def parse_command_import(self
):
1302 # Parse "import" command.
1303 sub_import
= self
.sub_commands
.add_parser("import",
1304 help=_("Import a key from file."))
1305 sub_import
.add_argument("filename", nargs
=1,
1306 help=_("Filename of that key to import."))
1307 sub_import
.add_argument("action", action
="store_const", const
="import")
1309 def parse_command_export(self
):
1310 # Parse "export" command.
1311 sub_export
= self
.sub_commands
.add_parser("export",
1312 help=_("Export a key to a file."))
1313 sub_export
.add_argument("keyid", nargs
=1,
1314 help=_("The ID of the key to export."))
1315 sub_export
.add_argument("filename", nargs
=1,
1316 help=_("Write the key to this file."))
1317 sub_export
.add_argument("action", action
="store_const", const
="export")
1319 def parse_command_delete(self
):
1320 # Parse "delete" command.
1321 sub_del
= self
.sub_commands
.add_parser("delete",
1322 help=_("Delete a key from the local keyring."))
1323 sub_del
.add_argument("keyid", nargs
=1,
1324 help=_("The ID of the key to delete."))
1325 sub_del
.add_argument("action", action
="store_const", const
="delete")
1327 def parse_command_list(self
):
1328 # Parse "list" command.
1329 sub_list
= self
.sub_commands
.add_parser("list",
1330 help=_("List all imported keys."))
1331 sub_list
.add_argument("action", action
="store_const", const
="list")
1333 def parse_command_sign(self
):
1334 # Implement the "sign" command.
1335 sub_sign
= self
.sub_commands
.add_parser("sign",
1336 help=_("Sign one or more packages."))
1337 sub_sign
.add_argument("--key", "-k", nargs
=1,
1338 help=_("Key that is used sign the package(s)."))
1339 sub_sign
.add_argument("package", nargs
="+",
1340 help=_("Package(s) to sign."))
1341 sub_sign
.add_argument("action", action
="store_const", const
="sign")
1343 def parse_command_verify(self
):
1344 # Implement the "verify" command.
1345 sub_verify
= self
.sub_commands
.add_parser("verify",
1346 help=_("Verify one or more packages."))
1347 #sub_verify.add_argument("--key", "-k", nargs=1,
1348 # help=_("Key that is used verify the package(s)."))
1349 sub_verify
.add_argument("package", nargs
="+",
1350 help=_("Package(s) to verify."))
1351 sub_verify
.add_argument("action", action
="store_const", const
="verify")
1353 def handle_generate(self
):
1354 realname
= self
.args
.realname
[0]
1355 email
= self
.args
.email
[0]
1357 print _("Generating the key may take a moment...")
1361 p
= self
.create_pakfire()
1362 p
.keyring
.gen_key(realname
, email
)
1364 def handle_import(self
):
1365 filename
= self
.args
.filename
[0]
1367 # Simply import the file.
1368 p
= self
.create_pakfire()
1369 p
.keyring
.import_key(filename
)
1371 def handle_export(self
):
1372 keyid
= self
.args
.keyid
[0]
1373 filename
= self
.args
.filename
[0]
1375 p
= self
.create_pakfire()
1376 p
.keyring
.export_key(keyid
, filename
)
1378 def handle_delete(self
):
1379 keyid
= self
.args
.keyid
[0]
1381 p
= self
.create_pakfire()
1382 p
.keyring
.delete_key(keyid
)
1384 def handle_list(self
):
1385 p
= self
.create_pakfire()
1386 for line
in p
.keyring
.list_keys():
1389 def handle_sign(self
):
1390 # Get the files from the command line options
1393 for file in self
.args
.package
:
1394 # Check, if we got a regular file
1395 if os
.path
.exists(file):
1396 file = os
.path
.abspath(file)
1400 raise FileNotFoundError
, file
1402 key
= self
.args
.key
[0]
1404 # Create pakfire instance.
1405 p
= self
.create_pakfire()
1409 pkg
= packages
.open(p
, None, file)
1411 print _("Signing %s...") % pkg
.friendly_name
1414 def handle_verify(self
):
1415 # Get the files from the command line options
1418 for file in self
.args
.package
:
1419 # Check, if we got a regular file
1420 if os
.path
.exists(file) and not os
.path
.isdir(file):
1421 file = os
.path
.abspath(file)
1424 # Create pakfire instance.
1425 p
= self
.create_pakfire()
1429 pkg
= packages
.open(p
, None, file)
1431 print _("Verifying %s...") % pkg
.friendly_name
1435 key
= p
.keyring
.get_key(sig
.fpr
)
1437 subkey
= key
.subkeys
[0]
1439 print " %s %s" % (subkey
.fpr
[-16:], key
.uids
[0].uid
)
1441 print " %s" % _("This signature is valid.")
1444 print " %s <%s>" % (sig
.fpr
, _("Unknown key"))
1445 print " %s" % _("Could not check if this signature is valid.")
1447 created
= datetime
.datetime
.fromtimestamp(sig
.timestamp
)
1448 print " %s" % _("Created: %s") % created
1450 if sig
.exp_timestamp
:
1451 expires
= datetime
.datetime
.fromtimestamp(sig
.exp_timestamp
)
1452 print " %s" % _("Expires: %s") % expires