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