]> git.ipfire.org Git - pakfire.git/blame - python/pakfire/cli.py
Update pakfire-daemon:
[pakfire.git] / python / pakfire / cli.py
CommitLineData
47a4cb89 1#!/usr/bin/python
b792d887
MT
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###############################################################################
47a4cb89
MT
21
22import argparse
68c0e769 23import datetime
936f6b37 24import os
b913e798 25import shutil
47a4cb89 26import sys
b913e798 27import tempfile
47a4cb89 28
36b328f2 29import base
c62d93f1
MT
30import client
31import config
aa14071d 32import daemon
60845a36 33import logger
47a4cb89 34import packages
fa6d335b 35import repository
677ff42a 36import server
36b328f2 37import transaction
e9c20259 38import util
47a4cb89 39
c62d93f1 40from system import system
47a4cb89
MT
41from constants import *
42from i18n import _
43
60845a36
MT
44# Initialize a very simple logging that is removed when a Pakfire instance
45# is started.
46logger.setup_logging()
47
47a4cb89 48class Cli(object):
36b328f2
MT
49 pakfire = base.Pakfire
50
47a4cb89
MT
51 def __init__(self):
52 self.parser = argparse.ArgumentParser(
53 description = _("Pakfire command line interface."),
54 )
55
56 self.parse_common_arguments()
57
2ba449f0 58 self.parser.add_argument("--root", metavar="PATH",
d2e26956 59 default="/",
47a4cb89
MT
60 help=_("The path where pakfire should operate in."))
61
62 # Add sub-commands.
63 self.sub_commands = self.parser.add_subparsers()
64
65 self.parse_command_install()
0ca71090 66 self.parse_command_reinstall()
a39fd08b 67 self.parse_command_remove()
47a4cb89
MT
68 self.parse_command_info()
69 self.parse_command_search()
e38914be 70 self.parse_command_check_update()
47a4cb89 71 self.parse_command_update()
67d1ddbd 72 self.parse_command_downgrade()
fa6d335b 73 self.parse_command_provides()
c1962d40 74 self.parse_command_grouplist()
ce2764c1 75 self.parse_command_groupinstall()
67bc4528 76 self.parse_command_repolist()
31267a64 77 self.parse_command_clean()
35d89fd7 78 self.parse_command_check()
b25a3d84 79 self.parse_command_resolvdep()
995ed2dd 80 self.parse_command_extract()
47a4cb89
MT
81
82 # Finally parse all arguments from the command line and save them.
83 self.args = self.parser.parse_args()
84
47a4cb89 85 self.action2func = {
5e87fa4f 86 "install" : self.handle_install,
0ca71090 87 "reinstall" : self.handle_reinstall,
a39fd08b 88 "remove" : self.handle_remove,
e38914be 89 "check_update" : self.handle_check_update,
5e87fa4f 90 "update" : self.handle_update,
67d1ddbd 91 "downgrade" : self.handle_downgrade,
5e87fa4f
MT
92 "info" : self.handle_info,
93 "search" : self.handle_search,
fa6d335b 94 "provides" : self.handle_provides,
c1962d40 95 "grouplist" : self.handle_grouplist,
ce2764c1 96 "groupinstall" : self.handle_groupinstall,
67bc4528 97 "repolist" : self.handle_repolist,
31267a64 98 "clean_all" : self.handle_clean_all,
35d89fd7 99 "check" : self.handle_check,
b25a3d84 100 "resolvdep" : self.handle_resolvdep,
995ed2dd 101 "extract" : self.handle_extract,
47a4cb89
MT
102 }
103
7c8f2953
MT
104 @property
105 def pakfire_args(self):
36b328f2 106 ret = {}
6557ff4c 107
2ba449f0
MT
108 if hasattr(self.args, "root"):
109 ret["path"] = self.args.root
f9a012a8 110
98733451
MT
111 if hasattr(self.args, "offline") and self.args.offline:
112 ret["downloader"] = {
113 "offline" : self.args.offline,
114 }
6a509182 115
854d8ccf
MT
116 if hasattr(self.args, "config"):
117 ret["configs"] = self.args.config
118 else:
119 ret["configs"] = None
120
f9a012a8 121 return ret
7c8f2953 122
685cb819
MT
123 def create_pakfire(self, cls=None, **kwargs):
124 if cls is None:
125 cls = self.pakfire
126
127 args = self.pakfire_args
128 args.update(kwargs)
129
130 p = cls(**args)
131
132 # Disable repositories.
133 for repo in self.args.disable_repo:
134 p.repos.disable_repo(repo)
135
136 # Enable repositories.
137 for repo in self.args.enable_repo:
138 p.repos.enable_repo(repo)
139
140 return p
141
142 def parse_common_arguments(self, offline_switch=True):
50381f5c
MT
143 self.parser.add_argument("--version", action="version",
144 version="%(prog)s " + PAKFIRE_VERSION)
145
47a4cb89
MT
146 self.parser.add_argument("-v", "--verbose", action="store_true",
147 help=_("Enable verbose output."))
148
149 self.parser.add_argument("-c", "--config", nargs="?",
150 help=_("Path to a configuration file to load."))
151
685cb819
MT
152 self.parser.add_argument("--disable-repo", nargs="*", metavar="REPO",
153 help=_("Disable a repository temporarily."), default=[])
f781b1ab 154
685cb819
MT
155 self.parser.add_argument("--enable-repo", nargs="*", metavar="REPO",
156 help=_("Enable a repository temporarily."), default=[])
f9a012a8 157
c62d93f1
MT
158 if offline_switch:
159 self.parser.add_argument("--offline", action="store_true",
160 help=_("Run pakfire in offline mode."))
6a509182 161
47a4cb89
MT
162 def parse_command_install(self):
163 # Implement the "install" command.
164 sub_install = self.sub_commands.add_parser("install",
165 help=_("Install one or more packages to the system."))
166 sub_install.add_argument("package", nargs="+",
167 help=_("Give name of at least one package to install."))
a60f0f7d
MT
168 sub_install.add_argument("--without-recommends", action="store_true",
169 help=_("Don't install recommended packages."))
47a4cb89
MT
170 sub_install.add_argument("action", action="store_const", const="install")
171
0ca71090
MT
172 def parse_command_reinstall(self):
173 # Implement the "reinstall" command.
174 sub_install = self.sub_commands.add_parser("reinstall",
175 help=_("Reinstall one or more packages."))
176 sub_install.add_argument("package", nargs="+",
177 help=_("Give name of at least one package to reinstall."))
178 sub_install.add_argument("action", action="store_const", const="reinstall")
179
a39fd08b
MT
180 def parse_command_remove(self):
181 # Implement the "remove" command.
182 sub_remove = self.sub_commands.add_parser("remove",
183 help=_("Remove one or more packages from the system."))
184 sub_remove.add_argument("package", nargs="+",
185 help=_("Give name of at least one package to remove."))
186 sub_remove.add_argument("action", action="store_const", const="remove")
187
05fb1da0
MT
188 @staticmethod
189 def _parse_command_update(parser):
190 parser.add_argument("package", nargs="*",
191 help=_("Give a name of a package to update or leave emtpy for all."))
192 parser.add_argument("--exclude", "-x", nargs="+",
193 help=_("Exclude package from update."))
194 parser.add_argument("--allow-vendorchange", action="store_true",
195 help=_("Allow changing the vendor of packages."))
94c11aff
MT
196 parser.add_argument("--disallow-archchange", action="store_true",
197 help=_("Disallow changing the architecture of packages."))
05fb1da0 198
47a4cb89
MT
199 def parse_command_update(self):
200 # Implement the "update" command.
201 sub_update = self.sub_commands.add_parser("update",
202 help=_("Update the whole system or one specific package."))
47a4cb89 203 sub_update.add_argument("action", action="store_const", const="update")
05fb1da0 204 self._parse_command_update(sub_update)
47a4cb89 205
e38914be
MT
206 def parse_command_check_update(self):
207 # Implement the "check-update" command.
208 sub_check_update = self.sub_commands.add_parser("check-update",
209 help=_("Check, if there are any updates available."))
e38914be 210 sub_check_update.add_argument("action", action="store_const", const="check_update")
05fb1da0 211 self._parse_command_update(sub_check_update)
e38914be 212
67d1ddbd
MT
213 def parse_command_downgrade(self):
214 # Implement the "downgrade" command.
215 sub_downgrade = self.sub_commands.add_parser("downgrade",
216 help=_("Downgrade one or more packages."))
217 sub_downgrade.add_argument("package", nargs="*",
218 help=_("Give a name of a package to downgrade."))
219 sub_downgrade.add_argument("--allow-vendorchange", action="store_true",
220 help=_("Allow changing the vendor of packages."))
94c11aff
MT
221 sub_downgrade.add_argument("--disallow-archchange", action="store_true",
222 help=_("Disallow changing the architecture of packages."))
67d1ddbd
MT
223 sub_downgrade.add_argument("action", action="store_const", const="downgrade")
224
47a4cb89
MT
225 def parse_command_info(self):
226 # Implement the "info" command.
227 sub_info = self.sub_commands.add_parser("info",
228 help=_("Print some information about the given package(s)."))
229 sub_info.add_argument("package", nargs="+",
230 help=_("Give at least the name of one package."))
231 sub_info.add_argument("action", action="store_const", const="info")
232
233 def parse_command_search(self):
234 # Implement the "search" command.
235 sub_search = self.sub_commands.add_parser("search",
236 help=_("Search for a given pattern."))
237 sub_search.add_argument("pattern",
238 help=_("A pattern to search for."))
239 sub_search.add_argument("action", action="store_const", const="search")
240
fa6d335b
MT
241 def parse_command_provides(self):
242 # Implement the "provides" command
243 sub_provides = self.sub_commands.add_parser("provides",
244 help=_("Get a list of packages that provide a given file or feature."))
245 sub_provides.add_argument("pattern", nargs="+",
246 help=_("File or feature to search for."))
247 sub_provides.add_argument("action", action="store_const", const="provides")
248
c1962d40
MT
249 def parse_command_grouplist(self):
250 # Implement the "grouplist" command
251 sub_grouplist = self.sub_commands.add_parser("grouplist",
252 help=_("Get list of packages that belong to the given group."))
253 sub_grouplist.add_argument("group", nargs=1,
254 help=_("Group name to search for."))
255 sub_grouplist.add_argument("action", action="store_const", const="grouplist")
256
ce2764c1
MT
257 def parse_command_groupinstall(self):
258 # Implement the "grouplist" command
259 sub_groupinstall = self.sub_commands.add_parser("groupinstall",
260 help=_("Install all packages that belong to the given group."))
261 sub_groupinstall.add_argument("group", nargs=1,
262 help=_("Group name."))
263 sub_groupinstall.add_argument("action", action="store_const", const="groupinstall")
264
67bc4528
MT
265 def parse_command_repolist(self):
266 # Implement the "repolist" command
267 sub_repolist = self.sub_commands.add_parser("repolist",
268 help=_("List all currently enabled repositories."))
269 sub_repolist.add_argument("action", action="store_const", const="repolist")
ce2764c1 270
31267a64
MT
271 def parse_command_clean(self):
272 sub_clean = self.sub_commands.add_parser("clean", help=_("Cleanup commands."))
273
274 sub_clean_commands = sub_clean.add_subparsers()
275
276 self.parse_command_clean_all(sub_clean_commands)
277
278 def parse_command_clean_all(self, sub_commands):
279 sub_create = sub_commands.add_parser("all",
280 help=_("Cleanup all temporary files."))
281 sub_create.add_argument("action", action="store_const", const="clean_all")
282
35d89fd7
MT
283 def parse_command_check(self):
284 # Implement the "check" command
285 sub_check = self.sub_commands.add_parser("check",
286 help=_("Check the system for any errors."))
287 sub_check.add_argument("action", action="store_const", const="check")
288
b25a3d84
MT
289 def parse_command_resolvdep(self):
290 # Implement the "resolvdep" command.
291 sub_resolvdep = self.sub_commands.add_parser("resolvdep",
292 help=_("Check the dependencies for a particular package."))
c901e1f8 293 sub_resolvdep.add_argument("package", nargs=1,
b25a3d84
MT
294 help=_("Give name of at least one package to check."))
295 sub_resolvdep.add_argument("action", action="store_const", const="resolvdep")
296
995ed2dd
MT
297 def parse_command_extract(self):
298 # Implement the "extract" command.
299 sub_extract = self.sub_commands.add_parser("extract",
300 help=_("Extract a package to a directory."))
301 sub_extract.add_argument("package", nargs="+",
302 help=_("Give name of the file to extract."))
303 sub_extract.add_argument("--target", nargs="?",
304 help=_("Target directory where to extract to."))
305 sub_extract.add_argument("action", action="store_const", const="extract")
306
47a4cb89
MT
307 def run(self):
308 action = self.args.action
309
47a4cb89
MT
310 try:
311 func = self.action2func[action]
312 except KeyError:
c62d93f1 313 raise Exception, "Unhandled action: %s" % action
47a4cb89
MT
314
315 return func()
316
9afa5620 317 def handle_info(self, long=False):
685cb819 318 p = self.create_pakfire()
47a4cb89 319
36b328f2 320 for pkg in p.info(self.args.package):
7c8f2953 321 print pkg.dump(long=long)
47a4cb89
MT
322
323 def handle_search(self):
685cb819 324 p = self.create_pakfire()
47a4cb89 325
36b328f2 326 for pkg in p.search(self.args.pattern):
47a4cb89
MT
327 print pkg.dump(short=True)
328
05fb1da0 329 def handle_update(self, **args):
685cb819 330 p = self.create_pakfire()
36b328f2
MT
331 p.update(
332 self.args.package,
333 excludes=self.args.exclude,
05fb1da0 334 allow_vendorchange=self.args.allow_vendorchange,
94c11aff 335 allow_archchange=not self.args.disallow_archchange,
36b328f2
MT
336 **args
337 )
47a4cb89 338
e38914be 339 def handle_check_update(self):
05fb1da0 340 self.handle_update(check=True)
e38914be 341
67d1ddbd 342 def handle_downgrade(self, **args):
685cb819 343 p = self.create_pakfire()
36b328f2
MT
344 p.downgrade(
345 self.args.package,
67d1ddbd 346 allow_vendorchange=self.args.allow_vendorchange,
94c11aff 347 allow_archchange=not self.args.disallow_archchange,
36b328f2
MT
348 **args
349 )
67d1ddbd 350
e0b99370 351 def handle_install(self):
685cb819 352 p = self.create_pakfire()
36b328f2 353 p.install(self.args.package, ignore_recommended=self.args.without_recommends)
5e87fa4f 354
0ca71090 355 def handle_reinstall(self):
685cb819 356 p = self.create_pakfire()
36b328f2 357 p.reinstall(self.args.package)
0ca71090 358
a39fd08b 359 def handle_remove(self):
685cb819 360 p = self.create_pakfire()
36b328f2 361 p.remove(self.args.package)
a39fd08b 362
36b328f2 363 def handle_provides(self, long=False):
685cb819 364 p = self.create_pakfire()
fa6d335b 365
36b328f2
MT
366 for pkg in p.provides(self.args.pattern):
367 print pkg.dump(long=long)
fa6d335b 368
c1962d40 369 def handle_grouplist(self):
685cb819 370 p = self.create_pakfire()
c1962d40 371
36b328f2 372 for pkg in p.grouplist(self.args.group[0]):
c1962d40
MT
373 print " * %s" % pkg
374
ce2764c1 375 def handle_groupinstall(self):
685cb819 376 p = self.create_pakfire()
36b328f2 377 p.groupinstall(self.args.group[0])
ce2764c1 378
67bc4528 379 def handle_repolist(self):
685cb819
MT
380 p = self.create_pakfire()
381
382 # Get a list of all repositories.
569b3054 383 repos = p.repo_list()
67bc4528 384
c605d735 385 FORMAT = " %-20s %8s %12s %12s "
c605d735 386 title = FORMAT % (_("Repository"), _("Enabled"), _("Priority"), _("Packages"))
67bc4528
MT
387 print title
388 print "=" * len(title) # spacing line
389
569b3054 390 for repo in repos:
c605d735 391 print FORMAT % (repo.name, repo.enabled, repo.priority, len(repo))
67bc4528 392
31267a64
MT
393 def handle_clean_all(self):
394 print _("Cleaning up everything...")
395
685cb819 396 p = self.create_pakfire()
36b328f2 397 p.clean_all()
31267a64 398
35d89fd7 399 def handle_check(self):
685cb819 400 p = self.create_pakfire()
36b328f2 401 p.check()
35d89fd7 402
b25a3d84 403 def handle_resolvdep(self):
685cb819 404 p = self.create_pakfire()
c901e1f8 405
36b328f2 406 (pkg,) = self.args.package
c901e1f8 407
569b3054 408 solver = p.resolvdep(pkg)
c901e1f8 409 assert solver.status
36b328f2
MT
410
411 t = transaction.Transaction.from_solver(p, solver)
412 t.dump()
b25a3d84 413
995ed2dd
MT
414 def handle_extract(self):
415 p = self.create_pakfire()
416
417 # Open all packages.
418 pkgs = []
419 for pkg in self.args.package:
420 pkg = packages.open(self, None, pkg)
421 pkgs.append(pkg)
422
423 target_prefix = self.args.target
424
425 # Search for binary packages.
426 binary_packages = any([p.type == "binary" for p in pkgs])
427 source_packages = any([p.type == "source" for p in pkgs])
428
429 if binary_packages and source_packages:
430 raise Error, _("Cannot extract mixed package types")
431
432 if binary_packages and not target_prefix:
433 raise Error, _("You must provide an install directory with --target=...")
434
435 elif source_packages and not target_prefix:
436 target_prefix = "/usr/src/packages/"
437
438 if target_prefix == "/":
439 raise Error, _("Cannot extract to /.")
440
441 for pkg in pkgs:
442 if pkg.type == "binary":
443 target_dir = target_prefix
444 elif pkg.type == "source":
445 target_dir = os.path.join(target_prefix, pkg.friendly_name)
446
447 pkg.extract(message=_("Extracting"), prefix=target_dir)
448
47a4cb89
MT
449
450class CliBuilder(Cli):
36b328f2
MT
451 pakfire = base.PakfireBuilder
452
47a4cb89 453 def __init__(self):
936f6b37
MT
454 # Check if we are already running in a pakfire container. In that
455 # case, we cannot start another pakfire-builder.
456 if os.environ.get("container", None) == "pakfire-builder":
457 raise PakfireContainerError, _("You cannot run pakfire-builder in a pakfire chroot.")
458
47a4cb89
MT
459 self.parser = argparse.ArgumentParser(
460 description = _("Pakfire builder command line interface."),
461 )
462
463 self.parse_common_arguments()
464
465 # Add sub-commands.
466 self.sub_commands = self.parser.add_subparsers()
467
468 self.parse_command_build()
469 self.parse_command_dist()
470 self.parse_command_info()
471 self.parse_command_search()
472 self.parse_command_shell()
473 self.parse_command_update()
4fbd4216 474 self.parse_command_provides()
2c84aceb 475 self.parse_command_grouplist()
67bc4528 476 self.parse_command_repolist()
31267a64 477 self.parse_command_clean()
b25a3d84 478 self.parse_command_resolvdep()
995ed2dd 479 self.parse_command_extract()
47a4cb89
MT
480
481 # Finally parse all arguments from the command line and save them.
482 self.args = self.parser.parse_args()
483
47a4cb89 484 self.action2func = {
fa6d335b
MT
485 "build" : self.handle_build,
486 "dist" : self.handle_dist,
487 "update" : self.handle_update,
488 "info" : self.handle_info,
489 "search" : self.handle_search,
490 "shell" : self.handle_shell,
4fbd4216 491 "provides" : self.handle_provides,
2c84aceb 492 "grouplist" : self.handle_grouplist,
67bc4528 493 "repolist" : self.handle_repolist,
31267a64 494 "clean_all" : self.handle_clean_all,
b25a3d84 495 "resolvdep" : self.handle_resolvdep,
995ed2dd 496 "extract" : self.handle_extract,
47a4cb89
MT
497 }
498
7c8f2953
MT
499 @property
500 def pakfire_args(self):
91f20fe4
MT
501 ret = {
502 "arch" : self.args.arch,
503 }
f9a012a8 504
98733451
MT
505 if hasattr(self.args, "offline") and self.args.offline:
506 ret["downloader"] = {
507 "offline" : self.args.offline,
508 }
6a509182 509
4f08c65d
MT
510 if hasattr(self.args, "distro"):
511 ret["distro_name"] = self.args.distro
512
f9a012a8 513 return ret
7c8f2953 514
4f08c65d
MT
515 def parse_common_arguments(self, *args, **kwargs):
516 Cli.parse_common_arguments(self, *args, **kwargs)
517
518 self.parser.add_argument("--distro", nargs="?",
519 help=_("Choose the distribution configuration to use for build"))
520
91f20fe4
MT
521 self.parser.add_argument("--arch", "-a", nargs="?",
522 help=_("Run pakfire for the given architecture."))
523
47a4cb89
MT
524 def parse_command_update(self):
525 # Implement the "update" command.
526 sub_update = self.sub_commands.add_parser("update",
527 help=_("Update the package indexes."))
528 sub_update.add_argument("action", action="store_const", const="update")
529
530 def parse_command_build(self):
531 # Implement the "build" command.
532 sub_build = self.sub_commands.add_parser("build",
533 help=_("Build one or more packages."))
534 sub_build.add_argument("package", nargs=1,
535 help=_("Give name of at least one package to build."))
536 sub_build.add_argument("action", action="store_const", const="build")
537
47a4cb89
MT
538 sub_build.add_argument("--resultdir", nargs="?",
539 help=_("Path were the output files should be copied to."))
f22069bb
MT
540 sub_build.add_argument("-m", "--mode", nargs="?", default="development",
541 help=_("Mode to run in. Is either 'release' or 'development' (default)."))
1710ccec
MT
542 sub_build.add_argument("--after-shell", action="store_true",
543 help=_("Run a shell after a successful build."))
4fffe3c4
MT
544 sub_build.add_argument("--no-install-test", action="store_true",
545 help=_("Do not perform the install test."))
47a4cb89
MT
546
547 def parse_command_shell(self):
548 # Implement the "shell" command.
549 sub_shell = self.sub_commands.add_parser("shell",
550 help=_("Go into a shell."))
042266f3 551 sub_shell.add_argument("package", nargs="?",
47a4cb89
MT
552 help=_("Give name of a package."))
553 sub_shell.add_argument("action", action="store_const", const="shell")
554
6ee3d6b9
MT
555 sub_shell.add_argument("-m", "--mode", nargs="?", default="development",
556 help=_("Mode to run in. Is either 'release' or 'development' (default)."))
47a4cb89
MT
557
558 def parse_command_dist(self):
559 # Implement the "dist" command.
560 sub_dist = self.sub_commands.add_parser("dist",
561 help=_("Generate a source package."))
e412b8dc
MT
562 sub_dist.add_argument("package", nargs="+",
563 help=_("Give name(s) of a package(s)."))
47a4cb89
MT
564 sub_dist.add_argument("action", action="store_const", const="dist")
565
566 sub_dist.add_argument("--resultdir", nargs="?",
567 help=_("Path were the output files should be copied to."))
568
9afa5620
MT
569 def handle_info(self):
570 Cli.handle_info(self, long=True)
571
47a4cb89 572 def handle_build(self):
47a4cb89
MT
573 # Get the package descriptor from the command line options
574 pkg = self.args.package[0]
575
576 # Check, if we got a regular file
577 if os.path.exists(pkg):
578 pkg = os.path.abspath(pkg)
579
47a4cb89 580 else:
7c8f2953 581 raise FileNotFoundError, pkg
47a4cb89 582
4fffe3c4
MT
583 # Check whether to enable the install test.
584 install_test = not self.args.no_install_test
585
36b328f2
MT
586 if self.args.mode == "release":
587 release_build = True
588 else:
589 release_build = False
590
91f20fe4 591 p = self.create_pakfire()
36b328f2
MT
592 p.build(pkg,
593 install_test=install_test,
594 resultdirs=[self.args.resultdir,],
595 shell=True,
596 after_shell=self.args.after_shell,
597 release_build=release_build,
598 )
47a4cb89
MT
599
600 def handle_shell(self):
042266f3
MT
601 pkg = None
602
47a4cb89 603 # Get the package descriptor from the command line options
042266f3 604 if self.args.package:
ad1b844f 605 pkg = self.args.package
47a4cb89 606
7c8f2953
MT
607 # Check, if we got a regular file
608 if os.path.exists(pkg):
609 pkg = os.path.abspath(pkg)
47a4cb89 610
7c8f2953
MT
611 else:
612 raise FileNotFoundError, pkg
47a4cb89 613
36b328f2
MT
614 if self.args.mode == "release":
615 release_build = True
616 else:
617 release_build = False
618
91f20fe4 619 p = self.create_pakfire()
36b328f2 620 p.shell(pkg, release_build=release_build)
47a4cb89
MT
621
622 def handle_dist(self):
e412b8dc
MT
623 # Get the packages from the command line options
624 pkgs = []
47a4cb89 625
e412b8dc
MT
626 for pkg in self.args.package:
627 # Check, if we got a regular file
628 if os.path.exists(pkg):
629 pkg = os.path.abspath(pkg)
7c8f2953 630 pkgs.append(pkg)
47a4cb89 631
e412b8dc 632 else:
7c8f2953
MT
633 raise FileNotFoundError, pkg
634
7d40ac70
MT
635 # Put packages to where the user said or our
636 # current working directory.
637 resultdir = self.args.resultdir or os.getcwd()
638
685cb819 639 p = self.create_pakfire()
7d40ac70 640 for pkg in pkgs:
36b328f2 641 p.dist(pkg, resultdir=resultdir)
47a4cb89 642
c605d735 643 def handle_provides(self):
e313dac1 644 Cli.handle_provides(self, long=True)
c605d735 645
47a4cb89 646
3ad4bb5a 647class CliServer(Cli):
36b328f2
MT
648 pakfire = base.PakfireServer
649
677ff42a
MT
650 def __init__(self):
651 self.parser = argparse.ArgumentParser(
3ad4bb5a 652 description = _("Pakfire server command line interface."),
677ff42a
MT
653 )
654
655 self.parse_common_arguments()
656
657 # Add sub-commands.
658 self.sub_commands = self.parser.add_subparsers()
659
a52f536c 660 self.parse_command_build()
677ff42a 661 self.parse_command_keepalive()
8276111d 662 self.parse_command_repoupdate()
df9c4f62 663 self.parse_command_repo()
aad6f600 664 self.parse_command_info()
677ff42a
MT
665
666 # Finally parse all arguments from the command line and save them.
667 self.args = self.parser.parse_args()
668
27296963 669 #self.server = server.Server(**self.pakfire_args)
677ff42a
MT
670
671 self.action2func = {
8276111d 672 "build" : self.handle_build,
aad6f600 673 "info" : self.handle_info,
8276111d
MT
674 "keepalive" : self.handle_keepalive,
675 "repoupdate" : self.handle_repoupdate,
df9c4f62 676 "repo_create": self.handle_repo_create,
677ff42a
MT
677 }
678
6557ff4c
MT
679 @property
680 def pakfire_args(self):
36b328f2 681 ret = {}
6557ff4c 682
98733451
MT
683 if hasattr(self.args, "offline") and self.args.offline:
684 ret["downloader"] = {
685 "offline" : self.args.offline,
686 }
6a509182 687
6557ff4c
MT
688 return ret
689
a52f536c
MT
690 def parse_command_build(self):
691 # Implement the "build" command.
c62d93f1
MT
692 sub_build = self.sub_commands.add_parser("build",
693 help=_("Send a scrach build job to the server."))
694 sub_build.add_argument("package", nargs=1,
695 help=_("Give name of at least one package to build."))
696 sub_build.add_argument("--arch", "-a",
697 help=_("Limit build to only these architecture(s)."))
698 sub_build.add_argument("action", action="store_const", const="build")
a52f536c 699
677ff42a
MT
700 def parse_command_keepalive(self):
701 # Implement the "keepalive" command.
702 sub_keepalive = self.sub_commands.add_parser("keepalive",
703 help=_("Send a keepalive to the server."))
704 sub_keepalive.add_argument("action", action="store_const",
705 const="keepalive")
706
8276111d
MT
707 def parse_command_repoupdate(self):
708 # Implement the "repoupdate" command.
709 sub_repoupdate = self.sub_commands.add_parser("repoupdate",
710 help=_("Update all repositories."))
711 sub_repoupdate.add_argument("action", action="store_const",
712 const="repoupdate")
713
df9c4f62
MT
714 def parse_command_repo(self):
715 sub_repo = self.sub_commands.add_parser("repo",
716 help=_("Repository management commands."))
717
718 sub_repo_commands = sub_repo.add_subparsers()
719
720 self.parse_command_repo_create(sub_repo_commands)
721
722 def parse_command_repo_create(self, sub_commands):
723 sub_create = sub_commands.add_parser("create",
724 help=_("Create a new repository index."))
68c0e769
MT
725 sub_create.add_argument("path", nargs=1,
726 help=_("Path to the packages."))
727 sub_create.add_argument("inputs", nargs="+",
728 help=_("Path to input packages."))
729 sub_create.add_argument("--key", "-k", nargs="?",
730 help=_("Key to sign the repository with."))
df9c4f62
MT
731 sub_create.add_argument("action", action="store_const", const="repo_create")
732
aad6f600
MT
733 def parse_command_info(self):
734 sub_info = self.sub_commands.add_parser("info",
735 help=_("Dump some information about this machine."))
736 sub_info.add_argument("action", action="store_const", const="info")
737
677ff42a 738 def handle_keepalive(self):
3ad4bb5a 739 self.server.update_info()
9613a111 740
a52f536c 741 def handle_build(self):
c62d93f1
MT
742 # Arch.
743 if self.args.arch:
744 arches = self.args.arch.split()
745
746 (package,) = self.args.package
747
748 self.server.create_scratch_build({})
749 return
750
751 # Temporary folter for source package.
752 tmpdir = "/tmp/pakfire-%s" % util.random_string()
753
754 try:
755 os.makedirs(tmpdir)
756
757 pakfire.dist(package, resultdir=[tmpdir,])
758
759 for file in os.listdir(tmpdir):
760 file = os.path.join(tmpdir, file)
761
762 print file
763
764 finally:
765 if os.path.exists(tmpdir):
766 util.rm(tmpdir)
8276111d
MT
767
768 def handle_repoupdate(self):
769 self.server.update_repositories()
df9c4f62
MT
770
771 def handle_repo_create(self):
772 path = self.args.path[0]
773
3a1ddabb 774 p = self.create_pakfire()
36b328f2 775 p.repo_create(path, self.args.inputs, key_id=self.args.key)
c07a3ca7 776
aad6f600
MT
777 def handle_info(self):
778 info = self.server.info()
779
780 print "\n".join(info)
781
c07a3ca7 782
9b875540 783class CliBuilderIntern(Cli):
c07a3ca7
MT
784 def __init__(self):
785 self.parser = argparse.ArgumentParser(
786 description = _("Pakfire builder command line interface."),
787 )
788
789 self.parse_common_arguments()
790
791 # Add sub-commands.
792 self.sub_commands = self.parser.add_subparsers()
793
794 self.parse_command_build()
795
796 # Finally parse all arguments from the command line and save them.
797 self.args = self.parser.parse_args()
798
799 self.action2func = {
800 "build" : self.handle_build,
801 }
802
803 def parse_command_build(self):
804 # Implement the "build" command.
805 sub_build = self.sub_commands.add_parser("build",
806 help=_("Build one or more packages."))
807 sub_build.add_argument("package", nargs=1,
808 help=_("Give name of at least one package to build."))
809 sub_build.add_argument("action", action="store_const", const="build")
810
811 sub_build.add_argument("-a", "--arch",
812 help=_("Build the package for the given architecture."))
813 sub_build.add_argument("--resultdir", nargs="?",
814 help=_("Path were the output files should be copied to."))
815 sub_build.add_argument("-m", "--mode", nargs="?", default="development",
816 help=_("Mode to run in. Is either 'release' or 'development' (default)."))
817 sub_build.add_argument("--nodeps", action="store_true",
818 help=_("Do not verify build dependencies."))
47230b23
MT
819 sub_build.add_argument("--prepare", action="store_true",
820 help=_("Only run the prepare stage."))
c07a3ca7
MT
821
822 def handle_build(self):
823 # Get the package descriptor from the command line options
824 pkg = self.args.package[0]
825
826 # Check, if we got a regular file
827 if os.path.exists(pkg):
828 pkg = os.path.abspath(pkg)
829 else:
830 raise FileNotFoundError, pkg
831
013eb9f2
MT
832 # Create pakfire instance.
833 c = config.ConfigBuilder()
834 p = base.Pakfire(arch = self.args.arch, config = c)
854d8ccf 835
013eb9f2 836 # Disable all repositories.
8fe602a7 837 if self.args.nodeps:
013eb9f2
MT
838 p.repos.disable_repo("*")
839
840 # Limit stages that are to be run.
841 if self.args.prepare:
842 stages = ["prepare"]
8fe602a7 843 else:
013eb9f2 844 stages = None
4fffe3c4 845
013eb9f2 846 p.build(pkg, resultdir=self.args.resultdir, stages=stages)
c62d93f1
MT
847
848
849class CliClient(Cli):
7af1fde4
MT
850 pakfire = base.PakfireClient
851
c62d93f1
MT
852 def __init__(self):
853 self.parser = argparse.ArgumentParser(
854 description = _("Pakfire client command line interface."),
855 )
856
56278400 857 self.parse_common_arguments(offline_switch=True)
c62d93f1
MT
858
859 # Add sub-commands.
860 self.sub_commands = self.parser.add_subparsers()
861
862 self.parse_command_build()
863 self.parse_command_connection_check()
864 self.parse_command_info()
25a98632
MT
865 self.parse_command_jobs()
866 self.parse_command_builds()
37ff3f8f 867 self.parse_command_test()
c62d93f1
MT
868
869 # Finally parse all arguments from the command line and save them.
870 self.args = self.parser.parse_args()
871
872 self.action2func = {
873 "build" : self.handle_build,
874 "conn-check" : self.handle_connection_check,
875 "info" : self.handle_info,
25a98632
MT
876 "jobs_show" : self.handle_jobs_show,
877 "jobs_active" : self.handle_jobs_active,
878 "jobs_latest" : self.handle_jobs_latest,
879 "builds_show" : self.handle_builds_show,
37ff3f8f 880 "test" : self.handle_test,
c62d93f1
MT
881 }
882
aa14071d 883 # Read configuration.
7af1fde4 884 self.config = config.ConfigClient()
c62d93f1
MT
885
886 # Create connection to pakfire hub.
aa14071d 887 self.client = client.PakfireClient(self.config)
c62d93f1 888
7af1fde4
MT
889 @property
890 def pakfire_args(self):
891 return {
892 "config" : self.config,
893 }
894
c62d93f1
MT
895 def parse_command_build(self):
896 # Parse "build" command.
897 sub_build = self.sub_commands.add_parser("build",
898 help=_("Build a package remotely."))
899 sub_build.add_argument("package", nargs=1,
900 help=_("Give name of a package to build."))
901 sub_build.add_argument("action", action="store_const", const="build")
902
903 sub_build.add_argument("-a", "--arch",
904 help=_("Build the package for the given architecture."))
905
906 def parse_command_info(self):
907 # Implement the "info" command.
908 sub_info = self.sub_commands.add_parser("info",
909 help=_("Print some information about this host."))
910 sub_info.add_argument("action", action="store_const", const="info")
911
912 def parse_command_connection_check(self):
913 # Implement the "conn-check" command.
914 sub_conn_check = self.sub_commands.add_parser("conn-check",
915 help=_("Check the connection to the hub."))
916 sub_conn_check.add_argument("action", action="store_const", const="conn-check")
917
25a98632
MT
918 def parse_command_jobs(self):
919 sub_jobs = self.sub_commands.add_parser("jobs",
920 help=_("Show information about build jobs."))
921
922 sub_jobs_commands = sub_jobs.add_subparsers()
923
924 self.parse_command_jobs_active(sub_jobs_commands)
925 self.parse_command_jobs_latest(sub_jobs_commands)
926 self.parse_command_jobs_show(sub_jobs_commands)
927
928 def parse_command_jobs_active(self, sub_commands):
929 sub_active = sub_commands.add_parser("active",
930 help=_("Show a list of all active jobs."))
931 sub_active.add_argument("action", action="store_const", const="jobs_active")
932
933 def parse_command_jobs_latest(self, sub_commands):
934 sub_latest = sub_commands.add_parser("latest",
935 help=_("Show a list of all recently finished of failed build jobs."))
936 sub_latest.add_argument("action", action="store_const", const="jobs_latest")
937
938 def parse_command_jobs_show(self, sub_commands):
939 sub_show = sub_commands.add_parser("show",
940 help=_("Show details about given build job."))
941 sub_show.add_argument("job_id", nargs=1, help=_("The ID of the build job."))
942 sub_show.add_argument("action", action="store_const", const="jobs_show")
943
944 def parse_command_builds(self):
945 sub_builds = self.sub_commands.add_parser("builds",
946 help=_("Show information about builds."))
947
948 sub_builds_commands = sub_builds.add_subparsers()
949
950 self.parse_command_builds_show(sub_builds_commands)
951
952 def parse_command_builds_show(self, sub_commands):
953 sub_show = sub_commands.add_parser("show",
954 help=_("Show details about the given build."))
955 sub_show.add_argument("build_id", nargs=1, help=_("The ID of the build."))
956 sub_show.add_argument("action", action="store_const", const="builds_show")
957
37ff3f8f
MT
958 def parse_command_test(self):
959 sub_test = self.sub_commands.add_parser("test",
960 help=_("Test the connection to the hub."))
961 sub_test.add_argument("error_code", nargs=1, help=_("Error code to test."))
962 sub_test.add_argument("action", action="store_const", const="test")
963
c62d93f1
MT
964 def handle_build(self):
965 (package,) = self.args.package
966
967 # XXX just for now, we do only upload source pfm files.
968 assert os.path.exists(package)
969
b913e798
MT
970 # Create a temporary directory.
971 temp_dir = tempfile.mkdtemp()
972
973 try:
974 if package.endswith(".%s" % MAKEFILE_EXTENSION):
36b328f2 975 pakfire_args = {}
b913e798
MT
976
977 # Create a source package from the makefile.
36b328f2
MT
978 p = self.pakfire(**self.pakfire_args)
979 package = p.dist(package, temp_dir)
b913e798
MT
980
981 elif package.endswith(".%s" % PACKAGE_EXTENSION):
982 pass
c62d93f1 983
b913e798
MT
984 else:
985 raise Exception, "Unknown filetype: %s" % package
986
987 # Format arches.
988 if self.args.arch:
aa14071d 989 arches = self.args.arch.split(",")
b913e798
MT
990 else:
991 arches = None
c62d93f1 992
b913e798 993 # Create a new build on the server.
aa14071d
MT
994 build_id = self.client.build_create(package, build_type="scratch",
995 arches=arches)
b913e798
MT
996
997 finally:
998 # Cleanup the temporary directory and all files.
999 if os.path.exists(temp_dir):
1000 shutil.rmtree(temp_dir, ignore_errors=True)
c62d93f1 1001
aa14071d
MT
1002 # Monitor the build.
1003 if build_id:
1004 self.watch_build(build_id)
1005
c62d93f1
MT
1006 def handle_info(self):
1007 ret = []
1008
1009 ret.append("")
1010 ret.append(" PAKFIRE %s" % PAKFIRE_VERSION)
1011 ret.append("")
1012 ret.append(" %-20s: %s" % (_("Hostname"), system.hostname))
7af1fde4
MT
1013 ret.append(" %-20s: %s" % (_("Pakfire hub"), self.config.get("client", "server")))
1014 if self.config.get("client", "username") and self.config.get("client", "password"):
c62d93f1 1015 ret.append(" %-20s: %s" % \
7af1fde4 1016 (_("Username"), self.config.get("client", "username")))
c62d93f1
MT
1017 ret.append("")
1018
1019 # Hardware information
1020 ret.append(" %s:" % _("Hardware information"))
1021 ret.append(" %-16s: %s" % (_("CPU model"), system.cpu_model))
1022 ret.append(" %-16s: %s" % (_("Memory"), util.format_size(system.memory)))
cae35096 1023 ret.append(" %-16s: %s" % (_("Parallelism"), system.parallelism))
c62d93f1 1024 ret.append("")
790a44cc
MT
1025 ret.append(" %-16s: %s" % (_("Native arch"), system.native_arch))
1026 if not system.arch == system.native_arch:
1027 ret.append(" %-16s: %s" % (_("Default arch"), system.arch))
c62d93f1
MT
1028
1029 header = _("Supported arches")
1030 for arch in system.supported_arches:
1031 ret.append(" %-16s: %s" % (header, arch))
1032 header = ""
1033 ret.append("")
1034
1035 for line in ret:
1036 print line
1037
1038 def handle_connection_check(self):
1039 ret = []
1040
1041 address = self.client.get_my_address()
1042 ret.append(" %-20s: %s" % (_("Your IP address"), address))
1043 ret.append("")
1044
1045 authenticated = self.client.check_auth()
1046 if authenticated:
1047 ret.append(" %s" % _("You are authenticated to the build service:"))
1048
1049 user = self.client.get_user_profile()
1050 assert user, "Could not fetch user infomation"
1051
1052 keys = [
1053 ("name", _("User name")),
1054 ("realname", _("Real name")),
1055 ("email", _("Email address")),
1056 ("registered", _("Registered")),
1057 ]
1058
1059 for key, desc in keys:
1060 ret.append(" %-18s: %s" % (desc, user.get(key)))
1061
1062 else:
1063 ret.append(_("You could not be authenticated to the build service."))
1064
1065 for line in ret:
1066 print line
1067
25a98632
MT
1068 def _print_jobs(self, jobs, heading=None):
1069 if heading:
1070 print "%s:" % heading
1071 print
1072
1073 for job in jobs:
1074 line = " [%(type)8s] %(name)-30s: %(state)s"
1075
1076 print line % job
1077
1078 print # Empty line at the end.
1079
1080 def handle_jobs_active(self):
1081 jobs = self.client.get_active_jobs()
1082
1083 if not jobs:
1084 print _("No ongoing jobs found.")
1085 return
1086
1087 self._print_jobs(jobs, _("Active build jobs"))
1088
1089 def handle_jobs_latest(self):
1090 jobs = self.client.get_latest_jobs()
1091
1092 if not jobs:
1093 print _("No jobs found.")
1094 return
1095
1096 self._print_jobs(jobs, _("Recently processed build jobs"))
1097
1098 def handle_builds_show(self):
1099 (build_id,) = self.args.build_id
1100
1101 build = self.client.get_build(build_id)
1102 if not build:
1103 print _("A build with ID %s could not be found.") % build_id
1104 return
1105
1106 print _("Build: %(name)s") % build
1107
1108 fmt = "%-14s: %s"
1109 lines = [
1110 fmt % (_("State"), build["state"]),
1111 fmt % (_("Priority"), build["priority"]),
1112 ]
1113
1114 lines.append("%s:" % _("Jobs"))
1115 for job in build["jobs"]:
1116 lines.append(" * [%(uuid)s] %(name)-30s: %(state)s" % job)
1117
1118 for line in lines:
1119 print " ", line
1120 print
1121
1122 def handle_jobs_show(self):
1123 (job_id,) = self.args.job_id
1124
1125 job = self.client.get_job(job_id)
1126 if not job:
1127 print _("A job with ID %s could not be found.") % job_id
1128 return
1129
1130 builder = None
1131 if job["builder_id"]:
1132 builder = self.client.get_builder(job["builder_id"])
1133
1134 print _("Job: %(name)s") % job
1135
1136 fmt = "%-14s: %s"
1137 lines = [
1138 fmt % (_("State"), job["state"]),
1139 fmt % (_("Arch"), job["arch"]),
1140 ]
1141
1142 if builder:
1143 lines += [
1144 fmt % (_("Build host"), builder["name"]),
1145 "",
1146 ]
1147
1148 lines += [
1149 fmt % (_("Time created"), job["time_created"]),
1150 fmt % (_("Time started"), job["time_started"]),
1151 fmt % (_("Time finished"), job["time_finished"]),
1152 fmt % (_("Duration"), job["duration"]),
1153 ]
1154
1155 if job["packages"]:
1156 lines += ["", "%s:" % _("Packages")]
1157
1158 for pkg in job["packages"]:
1159 pkg_lines = [
1160 "* %(friendly_name)s" % pkg,
1161 " %(uuid)s" % pkg,
1162 "",
1163 ]
1164
1165 lines += [" %s" % line for line in pkg_lines]
1166
1167 for line in lines:
1168 print " ", line
1169 print # New line.
1170
37ff3f8f
MT
1171 def handle_test(self):
1172 error_code = self.args.error_code[0]
1173
1174 try:
1175 error_code = int(error_code)
1176 except ValueError:
1177 error_code = 0
1178
1179 if error_code < 100 or error_code > 999:
1180 raise Error, _("Invalid error code given.")
1181
1182 res = self.client.test_code(error_code)
1183 print _("Reponse from the server: %s") % res
1184
aa14071d
MT
1185 def watch_build(self, build_id):
1186 print self.client.build_get(build_id)
1187 # XXX TODO
1188 print build_id
1189
c62d93f1
MT
1190
1191class CliDaemon(Cli):
1192 def __init__(self):
1193 self.parser = argparse.ArgumentParser(
1194 description = _("Pakfire daemon command line interface."),
1195 )
1196
56278400 1197 self.parse_common_arguments(offline_switch=True)
c62d93f1
MT
1198
1199 # Finally parse all arguments from the command line and save them.
1200 self.args = self.parser.parse_args()
1201
1202 def run(self):
1203 """
1204 Runs the pakfire daemon with provided settings.
1205 """
1206 # Read the configuration file for the daemon.
aa14071d
MT
1207 self.config = config.ConfigDaemon()
1208 logger.setup_logging(self.config)
c62d93f1
MT
1209
1210 # Create daemon instance.
aa14071d 1211 d = daemon.PakfireDaemon(self.config)
c62d93f1
MT
1212 try:
1213 d.run()
1214
1215 # We cannot just kill the daemon, it needs a smooth shutdown.
1216 except (SystemExit, KeyboardInterrupt):
1217 d.shutdown()
68c0e769
MT
1218
1219
1220class CliKey(Cli):
1f6c466e
MT
1221 pakfire = base.PakfireKey
1222
68c0e769
MT
1223 def __init__(self):
1224 self.parser = argparse.ArgumentParser(
1225 description = _("Pakfire key command line interface."),
1226 )
1227
56278400 1228 self.parse_common_arguments(offline_switch=True)
68c0e769
MT
1229
1230 # Add sub-commands.
1231 self.sub_commands = self.parser.add_subparsers()
1232
68c0e769
MT
1233 self.parse_command_generate()
1234 self.parse_command_import()
1235 self.parse_command_export()
eaf999ef 1236 self.parse_command_delete()
68c0e769
MT
1237 self.parse_command_list()
1238 self.parse_command_sign()
1239 self.parse_command_verify()
1240
1241 # Finally parse all arguments from the command line and save them.
1242 self.args = self.parser.parse_args()
1243
68c0e769 1244 self.action2func = {
68c0e769
MT
1245 "generate" : self.handle_generate,
1246 "import" : self.handle_import,
1247 "export" : self.handle_export,
eaf999ef 1248 "delete" : self.handle_delete,
68c0e769
MT
1249 "list" : self.handle_list,
1250 "sign" : self.handle_sign,
1251 "verify" : self.handle_verify,
1252 }
1253
1254 @property
1255 def pakfire_args(self):
36b328f2 1256 return {}
68c0e769 1257
68c0e769
MT
1258 def parse_command_generate(self):
1259 # Parse "generate" command.
1260 sub_gen = self.sub_commands.add_parser("generate",
1261 help=_("Import a key from file."))
1262 sub_gen.add_argument("--realname", nargs=1,
1263 help=_("The real name of the owner of this key."))
1264 sub_gen.add_argument("--email", nargs=1,
1265 help=_("The email address of the owner of this key."))
1266 sub_gen.add_argument("action", action="store_const", const="generate")
1267
1268 def parse_command_import(self):
1269 # Parse "import" command.
1270 sub_import = self.sub_commands.add_parser("import",
1271 help=_("Import a key from file."))
1272 sub_import.add_argument("filename", nargs=1,
1273 help=_("Filename of that key to import."))
1274 sub_import.add_argument("action", action="store_const", const="import")
1275
1276 def parse_command_export(self):
1277 # Parse "export" command.
1278 sub_export = self.sub_commands.add_parser("export",
1279 help=_("Export a key to a file."))
1280 sub_export.add_argument("keyid", nargs=1,
1281 help=_("The ID of the key to export."))
1282 sub_export.add_argument("filename", nargs=1,
1283 help=_("Write the key to this file."))
1284 sub_export.add_argument("action", action="store_const", const="export")
1285
eaf999ef
MT
1286 def parse_command_delete(self):
1287 # Parse "delete" command.
1288 sub_del = self.sub_commands.add_parser("delete",
1289 help=_("Delete a key from the local keyring."))
1290 sub_del.add_argument("keyid", nargs=1,
1291 help=_("The ID of the key to delete."))
1292 sub_del.add_argument("action", action="store_const", const="delete")
1293
68c0e769
MT
1294 def parse_command_list(self):
1295 # Parse "list" command.
1296 sub_list = self.sub_commands.add_parser("list",
1297 help=_("List all imported keys."))
1298 sub_list.add_argument("action", action="store_const", const="list")
1299
1300 def parse_command_sign(self):
1301 # Implement the "sign" command.
1302 sub_sign = self.sub_commands.add_parser("sign",
1303 help=_("Sign one or more packages."))
1304 sub_sign.add_argument("--key", "-k", nargs=1,
1305 help=_("Key that is used sign the package(s)."))
1306 sub_sign.add_argument("package", nargs="+",
1307 help=_("Package(s) to sign."))
1308 sub_sign.add_argument("action", action="store_const", const="sign")
1309
1310 def parse_command_verify(self):
1311 # Implement the "verify" command.
1312 sub_verify = self.sub_commands.add_parser("verify",
1313 help=_("Verify one or more packages."))
1314 #sub_verify.add_argument("--key", "-k", nargs=1,
1315 # help=_("Key that is used verify the package(s)."))
1316 sub_verify.add_argument("package", nargs="+",
1317 help=_("Package(s) to verify."))
1318 sub_verify.add_argument("action", action="store_const", const="verify")
1319
68c0e769
MT
1320 def handle_generate(self):
1321 realname = self.args.realname[0]
1322 email = self.args.email[0]
1323
1324 print _("Generating the key may take a moment...")
1325 print
1326
1327 # Generate the key.
3a1ddabb 1328 p = self.create_pakfire()
1f6c466e 1329 p.keyring.gen_key(realname, email)
68c0e769
MT
1330
1331 def handle_import(self):
1332 filename = self.args.filename[0]
1333
1334 # Simply import the file.
3a1ddabb 1335 p = self.create_pakfire()
1f6c466e 1336 p.keyring.import_key(filename)
68c0e769
MT
1337
1338 def handle_export(self):
1339 keyid = self.args.keyid[0]
1340 filename = self.args.filename[0]
1341
3a1ddabb 1342 p = self.create_pakfire()
1f6c466e 1343 p.keyring.export_key(keyid, filename)
68c0e769 1344
eaf999ef
MT
1345 def handle_delete(self):
1346 keyid = self.args.keyid[0]
1347
3a1ddabb 1348 p = self.create_pakfire()
1f6c466e 1349 p.keyring.delete_key(keyid)
eaf999ef 1350
68c0e769 1351 def handle_list(self):
3a1ddabb 1352 p = self.create_pakfire()
1f6c466e 1353 for line in p.keyring.list_keys():
68c0e769
MT
1354 print line
1355
1356 def handle_sign(self):
1357 # Get the files from the command line options
1358 files = []
1359
1360 for file in self.args.package:
1361 # Check, if we got a regular file
1362 if os.path.exists(file):
1363 file = os.path.abspath(file)
1364 files.append(file)
1365
1366 else:
1367 raise FileNotFoundError, file
1368
1369 key = self.args.key[0]
1370
36b328f2 1371 # Create pakfire instance.
3a1ddabb 1372 p = self.create_pakfire()
36b328f2 1373
68c0e769
MT
1374 for file in files:
1375 # Open the package.
36b328f2 1376 pkg = packages.open(p, None, file)
68c0e769
MT
1377
1378 print _("Signing %s...") % pkg.friendly_name
1379 pkg.sign(key)
1380
1381 def handle_verify(self):
1382 # Get the files from the command line options
1383 files = []
1384
1385 for file in self.args.package:
1386 # Check, if we got a regular file
1387 if os.path.exists(file) and not os.path.isdir(file):
1388 file = os.path.abspath(file)
1389 files.append(file)
1390
36b328f2 1391 # Create pakfire instance.
3a1ddabb 1392 p = self.create_pakfire()
36b328f2 1393
68c0e769
MT
1394 for file in files:
1395 # Open the package.
36b328f2 1396 pkg = packages.open(p, None, file)
68c0e769
MT
1397
1398 print _("Verifying %s...") % pkg.friendly_name
1399 sigs = pkg.verify()
1400
1401 for sig in sigs:
3a1ddabb 1402 key = p.keyring.get_key(sig.fpr)
68c0e769
MT
1403 if key:
1404 subkey = key.subkeys[0]
1405
1406 print " %s %s" % (subkey.fpr[-16:], key.uids[0].uid)
1407 if sig.validity:
1408 print " %s" % _("This signature is valid.")
1409
1410 else:
1411 print " %s <%s>" % (sig.fpr, _("Unknown key"))
1412 print " %s" % _("Could not check if this signature is valid.")
1413
1414 created = datetime.datetime.fromtimestamp(sig.timestamp)
1415 print " %s" % _("Created: %s") % created
1416
1417 if sig.exp_timestamp:
1418 expires = datetime.datetime.fromtimestamp(sig.exp_timestamp)
1419 print " %s" % _("Expires: %s") % expires
1420
1421 print # Empty line