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