]> git.ipfire.org Git - pakfire.git/blob - python/pakfire/cli.py
Merge branch 'master' of ssh://git.ipfire.org/pub/git/oddments/pakfire
[pakfire.git] / python / pakfire / cli.py
1 #!/usr/bin/python
2 ###############################################################################
3 # #
4 # Pakfire - The IPFire package management system #
5 # Copyright (C) 2011 Pakfire development team #
6 # #
7 # This program is free software: you can redistribute it and/or modify #
8 # it under the terms of the GNU General Public License as published by #
9 # the Free Software Foundation, either version 3 of the License, or #
10 # (at your option) any later version. #
11 # #
12 # This program is distributed in the hope that it will be useful, #
13 # but WITHOUT ANY WARRANTY; without even the implied warranty of #
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
15 # GNU General Public License for more details. #
16 # #
17 # You should have received a copy of the GNU General Public License #
18 # along with this program. If not, see <http://www.gnu.org/licenses/>. #
19 # #
20 ###############################################################################
21
22 import argparse
23 import os
24 import sys
25
26 import logger
27 import packages
28 import repository
29 import server
30 import util
31
32 import pakfire.api as pakfire
33 from constants import *
34 from i18n import _
35
36 # Initialize a very simple logging that is removed when a Pakfire instance
37 # is started.
38 logger.setup_logging()
39
40 class Cli(object):
41 def __init__(self):
42 self.parser = argparse.ArgumentParser(
43 description = _("Pakfire command line interface."),
44 )
45
46 self.parse_common_arguments()
47
48 self.parser.add_argument("--root", metavar="PATH",
49 default="/",
50 help=_("The path where pakfire should operate in."))
51
52 # Add sub-commands.
53 self.sub_commands = self.parser.add_subparsers()
54
55 self.parse_command_install()
56 self.parse_command_localinstall()
57 self.parse_command_remove()
58 self.parse_command_info()
59 self.parse_command_search()
60 self.parse_command_check_update()
61 self.parse_command_update()
62 self.parse_command_provides()
63 self.parse_command_grouplist()
64 self.parse_command_groupinstall()
65 self.parse_command_repolist()
66 self.parse_command_clean()
67 self.parse_command_check()
68 self.parse_command_resolvdep()
69
70 # Finally parse all arguments from the command line and save them.
71 self.args = self.parser.parse_args()
72
73 self.action2func = {
74 "install" : self.handle_install,
75 "localinstall" : self.handle_localinstall,
76 "remove" : self.handle_remove,
77 "check_update" : self.handle_check_update,
78 "update" : self.handle_update,
79 "info" : self.handle_info,
80 "search" : self.handle_search,
81 "provides" : self.handle_provides,
82 "grouplist" : self.handle_grouplist,
83 "groupinstall" : self.handle_groupinstall,
84 "repolist" : self.handle_repolist,
85 "clean_all" : self.handle_clean_all,
86 "check" : self.handle_check,
87 "resolvdep" : self.handle_resolvdep,
88 }
89
90 @property
91 def pakfire_args(self):
92 ret = { "mode" : "normal" }
93
94 if hasattr(self.args, "root"):
95 ret["path"] = self.args.root
96
97 if hasattr(self.args, "disable_repo"):
98 ret["disable_repos"] = self.args.disable_repo
99
100 if hasattr(self.args, "enable_repo"):
101 ret["enable_repos"] = self.args.enable_repo
102
103 if hasattr(self.args, "offline"):
104 ret["offline"] = self.args.offline
105
106 return ret
107
108 def parse_common_arguments(self):
109 self.parser.add_argument("--version", action="version",
110 version="%(prog)s " + PAKFIRE_VERSION)
111
112 self.parser.add_argument("-v", "--verbose", action="store_true",
113 help=_("Enable verbose output."))
114
115 self.parser.add_argument("-c", "--config", nargs="?",
116 help=_("Path to a configuration file to load."))
117
118 self.parser.add_argument("--disable-repo", nargs="*", metavar="REPO",
119 help=_("Disable a repository temporarily."))
120
121 self.parser.add_argument("--enabled-repo", nargs="*", metavar="REPO",
122 help=_("Enable a repository temporarily."))
123
124 self.parser.add_argument("--offline", action="store_true",
125 help=_("Run pakfire in offline mode."))
126
127 def parse_command_install(self):
128 # Implement the "install" command.
129 sub_install = self.sub_commands.add_parser("install",
130 help=_("Install one or more packages to the system."))
131 sub_install.add_argument("package", nargs="+",
132 help=_("Give name of at least one package to install."))
133 sub_install.add_argument("action", action="store_const", const="install")
134
135 def parse_command_localinstall(self):
136 # Implement the "localinstall" command.
137 sub_install = self.sub_commands.add_parser("localinstall",
138 help=_("Install one or more packages from the filesystem."))
139 sub_install.add_argument("package", nargs="+",
140 help=_("Give filename of at least one package."))
141 sub_install.add_argument("action", action="store_const", const="localinstall")
142
143 def parse_command_remove(self):
144 # Implement the "remove" command.
145 sub_remove = self.sub_commands.add_parser("remove",
146 help=_("Remove one or more packages from the system."))
147 sub_remove.add_argument("package", nargs="+",
148 help=_("Give name of at least one package to remove."))
149 sub_remove.add_argument("action", action="store_const", const="remove")
150
151 def parse_command_update(self):
152 # Implement the "update" command.
153 sub_update = self.sub_commands.add_parser("update",
154 help=_("Update the whole system or one specific package."))
155 sub_update.add_argument("package", nargs="*",
156 help=_("Give a name of a package to update or leave emtpy for all."))
157 sub_update.add_argument("action", action="store_const", const="update")
158
159 def parse_command_check_update(self):
160 # Implement the "check-update" command.
161 sub_check_update = self.sub_commands.add_parser("check-update",
162 help=_("Check, if there are any updates available."))
163 sub_check_update.add_argument("package", nargs="*",
164 help=_("Give a name of a package to update or leave emtpy for all."))
165 sub_check_update.add_argument("action", action="store_const", const="check_update")
166
167 def parse_command_info(self):
168 # Implement the "info" command.
169 sub_info = self.sub_commands.add_parser("info",
170 help=_("Print some information about the given package(s)."))
171 sub_info.add_argument("package", nargs="+",
172 help=_("Give at least the name of one package."))
173 sub_info.add_argument("action", action="store_const", const="info")
174
175 def parse_command_search(self):
176 # Implement the "search" command.
177 sub_search = self.sub_commands.add_parser("search",
178 help=_("Search for a given pattern."))
179 sub_search.add_argument("pattern",
180 help=_("A pattern to search for."))
181 sub_search.add_argument("action", action="store_const", const="search")
182
183 def parse_command_provides(self):
184 # Implement the "provides" command
185 sub_provides = self.sub_commands.add_parser("provides",
186 help=_("Get a list of packages that provide a given file or feature."))
187 sub_provides.add_argument("pattern", nargs="+",
188 help=_("File or feature to search for."))
189 sub_provides.add_argument("action", action="store_const", const="provides")
190
191 def parse_command_grouplist(self):
192 # Implement the "grouplist" command
193 sub_grouplist = self.sub_commands.add_parser("grouplist",
194 help=_("Get list of packages that belong to the given group."))
195 sub_grouplist.add_argument("group", nargs=1,
196 help=_("Group name to search for."))
197 sub_grouplist.add_argument("action", action="store_const", const="grouplist")
198
199 def parse_command_groupinstall(self):
200 # Implement the "grouplist" command
201 sub_groupinstall = self.sub_commands.add_parser("groupinstall",
202 help=_("Install all packages that belong to the given group."))
203 sub_groupinstall.add_argument("group", nargs=1,
204 help=_("Group name."))
205 sub_groupinstall.add_argument("action", action="store_const", const="groupinstall")
206
207 def parse_command_repolist(self):
208 # Implement the "repolist" command
209 sub_repolist = self.sub_commands.add_parser("repolist",
210 help=_("List all currently enabled repositories."))
211 sub_repolist.add_argument("action", action="store_const", const="repolist")
212
213 def parse_command_clean(self):
214 sub_clean = self.sub_commands.add_parser("clean", help=_("Cleanup commands."))
215
216 sub_clean_commands = sub_clean.add_subparsers()
217
218 self.parse_command_clean_all(sub_clean_commands)
219
220 def parse_command_clean_all(self, sub_commands):
221 sub_create = sub_commands.add_parser("all",
222 help=_("Cleanup all temporary files."))
223 sub_create.add_argument("action", action="store_const", const="clean_all")
224
225 def parse_command_check(self):
226 # Implement the "check" command
227 sub_check = self.sub_commands.add_parser("check",
228 help=_("Check the system for any errors."))
229 sub_check.add_argument("action", action="store_const", const="check")
230
231 def parse_command_resolvdep(self):
232 # Implement the "resolvdep" command.
233 sub_resolvdep = self.sub_commands.add_parser("resolvdep",
234 help=_("Check the dependencies for a particular package."))
235 sub_resolvdep.add_argument("package", nargs="+",
236 help=_("Give name of at least one package to check."))
237 sub_resolvdep.add_argument("action", action="store_const", const="resolvdep")
238
239 def run(self):
240 action = self.args.action
241
242 if not self.action2func.has_key(action):
243 raise
244
245 try:
246 func = self.action2func[action]
247 except KeyError:
248 raise # XXX catch and return better error message
249
250 return func()
251
252 def handle_info(self, long=False):
253 pkgs = pakfire.info(self.args.package, **self.pakfire_args)
254
255 for pkg in pkgs:
256 print pkg.dump(long=long)
257
258 def handle_search(self):
259 pkgs = pakfire.search(self.args.pattern, **self.pakfire_args)
260
261 for pkg in pkgs:
262 print pkg.dump(short=True)
263
264 def handle_update(self):
265 pakfire.update(self.args.package, **self.pakfire_args)
266
267 def handle_check_update(self):
268 pakfire.update(self.args.package, check=True, **self.pakfire_args)
269
270 def handle_install(self):
271 pakfire.install(self.args.package, **self.pakfire_args)
272
273 def handle_localinstall(self):
274 pakfire.localinstall(self.args.package, **self.pakfire_args)
275
276 def handle_remove(self):
277 pakfire.remove(self.args.package, **self.pakfire_args)
278
279 def handle_provides(self):
280 pkgs = pakfire.provides(self.args.pattern, **self.pakfire_args)
281
282 for pkg in pkgs:
283 print pkg.dump()
284
285 def handle_grouplist(self):
286 pkgs = pakfire.grouplist(self.args.group[0], **self.pakfire_args)
287
288 for pkg in pkgs:
289 print " * %s" % pkg
290
291 def handle_groupinstall(self):
292 pakfire.groupinstall(self.args.group[0], **self.pakfire_args)
293
294 def handle_repolist(self):
295 repos = pakfire.repo_list(**self.pakfire_args)
296
297 FORMAT = " %-20s %8s %12s %12s "
298
299 title = FORMAT % (_("Repository"), _("Enabled"), _("Priority"), _("Packages"))
300 print title
301 print "=" * len(title) # spacing line
302
303 for repo in repos:
304 # Skip the installed repository.
305 if repo.name == "installed":
306 continue
307
308 print FORMAT % (repo.name, repo.enabled, repo.priority, len(repo))
309
310 def handle_clean_all(self):
311 print _("Cleaning up everything...")
312
313 pakfire.clean_all(**self.pakfire_args)
314
315 def handle_check(self):
316 pakfire.check(**self.pakfire_args)
317
318 def handle_resolvdep(self):
319 pakfire.resolvdep(self.args.package, **self.pakfire_args)
320
321
322 class CliBuilder(Cli):
323 def __init__(self):
324 # Check if we are already running in a pakfire container. In that
325 # case, we cannot start another pakfire-builder.
326 if os.environ.get("container", None) == "pakfire-builder":
327 raise PakfireContainerError, _("You cannot run pakfire-builder in a pakfire chroot.")
328
329 self.parser = argparse.ArgumentParser(
330 description = _("Pakfire builder command line interface."),
331 )
332
333 self.parse_common_arguments()
334
335 # Add sub-commands.
336 self.sub_commands = self.parser.add_subparsers()
337
338 self.parse_command_build()
339 self.parse_command_dist()
340 self.parse_command_info()
341 self.parse_command_search()
342 self.parse_command_shell()
343 self.parse_command_update()
344 self.parse_command_provides()
345 self.parse_command_grouplist()
346 self.parse_command_repolist()
347 self.parse_command_clean()
348 self.parse_command_resolvdep()
349
350 # Finally parse all arguments from the command line and save them.
351 self.args = self.parser.parse_args()
352
353 self.action2func = {
354 "build" : self.handle_build,
355 "dist" : self.handle_dist,
356 "update" : self.handle_update,
357 "info" : self.handle_info,
358 "search" : self.handle_search,
359 "shell" : self.handle_shell,
360 "provides" : self.handle_provides,
361 "grouplist" : self.handle_grouplist,
362 "repolist" : self.handle_repolist,
363 "clean_all" : self.handle_clean_all,
364 "resolvdep" : self.handle_resolvdep,
365 }
366
367 @property
368 def pakfire_args(self):
369 ret = { "mode" : "builder" }
370
371 if hasattr(self.args, "disable_repo"):
372 ret["disable_repos"] = self.args.disable_repo
373
374 if hasattr(self.args, "enable_repo"):
375 ret["enable_repos"] = self.args.enable_repo
376
377 if hasattr(self.args, "offline"):
378 ret["offline"] = self.args.offline
379
380 return ret
381
382 def parse_command_update(self):
383 # Implement the "update" command.
384 sub_update = self.sub_commands.add_parser("update",
385 help=_("Update the package indexes."))
386 sub_update.add_argument("action", action="store_const", const="update")
387
388 def parse_command_build(self):
389 # Implement the "build" command.
390 sub_build = self.sub_commands.add_parser("build",
391 help=_("Build one or more packages."))
392 sub_build.add_argument("package", nargs=1,
393 help=_("Give name of at least one package to build."))
394 sub_build.add_argument("action", action="store_const", const="build")
395
396 sub_build.add_argument("-a", "--arch",
397 help=_("Build the package for the given architecture."))
398 sub_build.add_argument("--resultdir", nargs="?",
399 help=_("Path were the output files should be copied to."))
400 sub_build.add_argument("-m", "--mode", nargs="?", default="development",
401 help=_("Mode to run in. Is either 'release' or 'development' (default)."))
402
403 def parse_command_shell(self):
404 # Implement the "shell" command.
405 sub_shell = self.sub_commands.add_parser("shell",
406 help=_("Go into a shell."))
407 sub_shell.add_argument("package", nargs="?",
408 help=_("Give name of a package."))
409 sub_shell.add_argument("action", action="store_const", const="shell")
410
411 sub_shell.add_argument("-a", "--arch",
412 help=_("Emulated architecture in the shell."))
413 sub_shell.add_argument("-m", "--mode", nargs="?", default="development",
414 help=_("Mode to run in. Is either 'release' or 'development' (default)."))
415
416 def parse_command_dist(self):
417 # Implement the "dist" command.
418 sub_dist = self.sub_commands.add_parser("dist",
419 help=_("Generate a source package."))
420 sub_dist.add_argument("package", nargs="+",
421 help=_("Give name(s) of a package(s)."))
422 sub_dist.add_argument("action", action="store_const", const="dist")
423
424 sub_dist.add_argument("--resultdir", nargs="?",
425 help=_("Path were the output files should be copied to."))
426
427 def handle_info(self):
428 Cli.handle_info(self, long=True)
429
430 def handle_build(self):
431 # Get the package descriptor from the command line options
432 pkg = self.args.package[0]
433
434 # Check, if we got a regular file
435 if os.path.exists(pkg):
436 pkg = os.path.abspath(pkg)
437
438 else:
439 raise FileNotFoundError, pkg
440
441 # Create distribution configuration from command line.
442 distro_config = {
443 "arch" : self.args.arch,
444 }
445
446 pakfire.build(pkg, builder_mode=self.args.mode,
447 distro_config=distro_config, resultdirs=[self.args.resultdir,],
448 shell=True, **self.pakfire_args)
449
450 def handle_shell(self):
451 pkg = None
452
453 # Get the package descriptor from the command line options
454 if self.args.package:
455 pkg = self.args.package
456
457 # Check, if we got a regular file
458 if os.path.exists(pkg):
459 pkg = os.path.abspath(pkg)
460
461 else:
462 raise FileNotFoundError, pkg
463
464 # Create distribution configuration from command line.
465 distro_config = {
466 "arch" : self.args.arch,
467 }
468
469 pakfire.shell(pkg, builder_mode=self.args.mode,
470 distro_config=distro_config, **self.pakfire_args)
471
472 def handle_dist(self):
473 # Get the packages from the command line options
474 pkgs = []
475
476 for pkg in self.args.package:
477 # Check, if we got a regular file
478 if os.path.exists(pkg):
479 pkg = os.path.abspath(pkg)
480 pkgs.append(pkg)
481
482 else:
483 raise FileNotFoundError, pkg
484
485 pakfire.dist(pkgs, resultdirs=[self.args.resultdir,],
486 **self.pakfire_args)
487
488 def handle_provides(self):
489 pkgs = pakfire.provides(self.args.pattern, **self.pakfire_args)
490
491 for pkg in pkgs:
492 print pkg.dump(long=True)
493
494
495 class CliServer(Cli):
496 def __init__(self):
497 self.parser = argparse.ArgumentParser(
498 description = _("Pakfire server command line interface."),
499 )
500
501 self.parse_common_arguments()
502
503 # Add sub-commands.
504 self.sub_commands = self.parser.add_subparsers()
505
506 self.parse_command_build()
507 self.parse_command_keepalive()
508 self.parse_command_repoupdate()
509 self.parse_command_repo()
510
511 # Finally parse all arguments from the command line and save them.
512 self.args = self.parser.parse_args()
513
514 self.server = server.Server()
515
516 self.action2func = {
517 "build" : self.handle_build,
518 "keepalive" : self.handle_keepalive,
519 "repoupdate" : self.handle_repoupdate,
520 "repo_create": self.handle_repo_create,
521 }
522
523 @property
524 def pakfire_args(self):
525 ret = { "mode" : "server" }
526
527 if hasattr(self.args, "offline"):
528 ret["offline"] = self.args.offline
529
530 return ret
531
532 def parse_command_build(self):
533 # Implement the "build" command.
534 sub_keepalive = self.sub_commands.add_parser("build",
535 help=_("Request a build job from the server."))
536 sub_keepalive.add_argument("action", action="store_const", const="build")
537
538 def parse_command_keepalive(self):
539 # Implement the "keepalive" command.
540 sub_keepalive = self.sub_commands.add_parser("keepalive",
541 help=_("Send a keepalive to the server."))
542 sub_keepalive.add_argument("action", action="store_const",
543 const="keepalive")
544
545 def parse_command_repoupdate(self):
546 # Implement the "repoupdate" command.
547 sub_repoupdate = self.sub_commands.add_parser("repoupdate",
548 help=_("Update all repositories."))
549 sub_repoupdate.add_argument("action", action="store_const",
550 const="repoupdate")
551
552 def parse_command_repo(self):
553 sub_repo = self.sub_commands.add_parser("repo",
554 help=_("Repository management commands."))
555
556 sub_repo_commands = sub_repo.add_subparsers()
557
558 self.parse_command_repo_create(sub_repo_commands)
559
560 def parse_command_repo_create(self, sub_commands):
561 sub_create = sub_commands.add_parser("create",
562 help=_("Create a new repository index."))
563 sub_create.add_argument("path", nargs=1, help=_("Path to the packages."))
564 sub_create.add_argument("inputs", nargs="+", help=_("Path to input packages."))
565 sub_create.add_argument("action", action="store_const", const="repo_create")
566
567 def handle_keepalive(self):
568 self.server.update_info()
569
570 def handle_build(self):
571 self.server.build_job()
572
573 def handle_repoupdate(self):
574 self.server.update_repositories()
575
576 def handle_repo_create(self):
577 path = self.args.path[0]
578
579 pakfire.repo_create(path, self.args.inputs, **self.pakfire_args)
580
581
582 class CliBuilderIntern(Cli):
583 def __init__(self):
584 self.parser = argparse.ArgumentParser(
585 description = _("Pakfire builder command line interface."),
586 )
587
588 self.parse_common_arguments()
589
590 # Add sub-commands.
591 self.sub_commands = self.parser.add_subparsers()
592
593 self.parse_command_build()
594
595 # Finally parse all arguments from the command line and save them.
596 self.args = self.parser.parse_args()
597
598 self.action2func = {
599 "build" : self.handle_build,
600 }
601
602 def parse_command_build(self):
603 # Implement the "build" command.
604 sub_build = self.sub_commands.add_parser("build",
605 help=_("Build one or more packages."))
606 sub_build.add_argument("package", nargs=1,
607 help=_("Give name of at least one package to build."))
608 sub_build.add_argument("action", action="store_const", const="build")
609
610 sub_build.add_argument("-a", "--arch",
611 help=_("Build the package for the given architecture."))
612 sub_build.add_argument("--resultdir", nargs="?",
613 help=_("Path were the output files should be copied to."))
614 sub_build.add_argument("-m", "--mode", nargs="?", default="development",
615 help=_("Mode to run in. Is either 'release' or 'development' (default)."))
616 sub_build.add_argument("--nodeps", action="store_true",
617 help=_("Do not verify build dependencies."))
618
619 def handle_build(self):
620 # Get the package descriptor from the command line options
621 pkg = self.args.package[0]
622
623 # Check, if we got a regular file
624 if os.path.exists(pkg):
625 pkg = os.path.abspath(pkg)
626 else:
627 raise FileNotFoundError, pkg
628
629 # Create distribution configuration from command line.
630 distro_config = {
631 "arch" : self.args.arch,
632 }
633
634 pakfire._build(pkg, builder_mode=self.args.mode,
635 distro_config=distro_config, resultdir=self.args.resultdir,
636 nodeps=self.args.nodeps, **self.pakfire_args)