]> git.ipfire.org Git - pakfire.git/blame_incremental - pakfire/cli.py
Allow uninstall of packages on install test.
[pakfire.git] / pakfire / cli.py
... / ...
CommitLineData
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
22import argparse
23import sys
24
25import logger
26import packages
27import repository
28import server
29import util
30
31import pakfire.api as pakfire
32from constants import *
33from i18n import _
34
35# Initialize a very simple logging that is removed when a Pakfire instance
36# is started.
37logger.setup_logging()
38
39class 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
321class 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
489class 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
576class 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)