]> git.ipfire.org Git - pakfire.git/blame - python/pakfire/cli.py
Create an extra namespace for build environments and private network.
[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."))
392371f7
MT
546 sub_build.add_argument("--private-network", action="store_true",
547 help=_("Disable network in container."))
47a4cb89
MT
548
549 def parse_command_shell(self):
550 # Implement the "shell" command.
551 sub_shell = self.sub_commands.add_parser("shell",
552 help=_("Go into a shell."))
042266f3 553 sub_shell.add_argument("package", nargs="?",
47a4cb89
MT
554 help=_("Give name of a package."))
555 sub_shell.add_argument("action", action="store_const", const="shell")
556
6ee3d6b9
MT
557 sub_shell.add_argument("-m", "--mode", nargs="?", default="development",
558 help=_("Mode to run in. Is either 'release' or 'development' (default)."))
392371f7
MT
559 sub_shell.add_argument("--private-network", action="store_true",
560 help=_("Disable network in container."))
47a4cb89
MT
561
562 def parse_command_dist(self):
563 # Implement the "dist" command.
564 sub_dist = self.sub_commands.add_parser("dist",
565 help=_("Generate a source package."))
e412b8dc
MT
566 sub_dist.add_argument("package", nargs="+",
567 help=_("Give name(s) of a package(s)."))
47a4cb89
MT
568 sub_dist.add_argument("action", action="store_const", const="dist")
569
570 sub_dist.add_argument("--resultdir", nargs="?",
571 help=_("Path were the output files should be copied to."))
572
9afa5620
MT
573 def handle_info(self):
574 Cli.handle_info(self, long=True)
575
47a4cb89 576 def handle_build(self):
47a4cb89
MT
577 # Get the package descriptor from the command line options
578 pkg = self.args.package[0]
579
580 # Check, if we got a regular file
581 if os.path.exists(pkg):
582 pkg = os.path.abspath(pkg)
583
47a4cb89 584 else:
7c8f2953 585 raise FileNotFoundError, pkg
47a4cb89 586
392371f7
MT
587 # Build argument list.
588 kwargs = {
589 "after_shell" : self.args.after_shell,
590 # Check whether to enable the install test.
591 "install_test" : not self.args.no_install_test,
592 "result_dir" : [self.args.resultdir,],
593 "shell" : True,
594 }
4fffe3c4 595
36b328f2 596 if self.args.mode == "release":
392371f7 597 kwargs["release_build"] = True
36b328f2 598 else:
392371f7
MT
599 kwargs["release_build"] = False
600
601 if self.args.private_network:
602 kwargs["private_network"] = True
36b328f2 603
91f20fe4 604 p = self.create_pakfire()
392371f7 605 p.build(pkg, **kwargs)
47a4cb89
MT
606
607 def handle_shell(self):
042266f3
MT
608 pkg = None
609
47a4cb89 610 # Get the package descriptor from the command line options
042266f3 611 if self.args.package:
ad1b844f 612 pkg = self.args.package
47a4cb89 613
7c8f2953
MT
614 # Check, if we got a regular file
615 if os.path.exists(pkg):
616 pkg = os.path.abspath(pkg)
47a4cb89 617
7c8f2953
MT
618 else:
619 raise FileNotFoundError, pkg
47a4cb89 620
36b328f2
MT
621 if self.args.mode == "release":
622 release_build = True
623 else:
624 release_build = False
625
91f20fe4 626 p = self.create_pakfire()
392371f7
MT
627
628 kwargs = {
629 "release_build" : release_build,
630 }
631
632 # Private network
633 if self.args.private_network:
634 kwargs["private_network"] = True
635
636 p.shell(pkg, **kwargs)
47a4cb89
MT
637
638 def handle_dist(self):
e412b8dc
MT
639 # Get the packages from the command line options
640 pkgs = []
47a4cb89 641
e412b8dc
MT
642 for pkg in self.args.package:
643 # Check, if we got a regular file
644 if os.path.exists(pkg):
645 pkg = os.path.abspath(pkg)
7c8f2953 646 pkgs.append(pkg)
47a4cb89 647
e412b8dc 648 else:
7c8f2953
MT
649 raise FileNotFoundError, pkg
650
7d40ac70
MT
651 # Put packages to where the user said or our
652 # current working directory.
653 resultdir = self.args.resultdir or os.getcwd()
654
685cb819 655 p = self.create_pakfire()
7d40ac70 656 for pkg in pkgs:
36b328f2 657 p.dist(pkg, resultdir=resultdir)
47a4cb89 658
c605d735 659 def handle_provides(self):
e313dac1 660 Cli.handle_provides(self, long=True)
c605d735 661
47a4cb89 662
3ad4bb5a 663class CliServer(Cli):
36b328f2
MT
664 pakfire = base.PakfireServer
665
677ff42a
MT
666 def __init__(self):
667 self.parser = argparse.ArgumentParser(
3ad4bb5a 668 description = _("Pakfire server command line interface."),
677ff42a
MT
669 )
670
671 self.parse_common_arguments()
672
673 # Add sub-commands.
674 self.sub_commands = self.parser.add_subparsers()
675
a52f536c 676 self.parse_command_build()
677ff42a 677 self.parse_command_keepalive()
8276111d 678 self.parse_command_repoupdate()
df9c4f62 679 self.parse_command_repo()
aad6f600 680 self.parse_command_info()
677ff42a
MT
681
682 # Finally parse all arguments from the command line and save them.
683 self.args = self.parser.parse_args()
684
27296963 685 #self.server = server.Server(**self.pakfire_args)
677ff42a
MT
686
687 self.action2func = {
8276111d 688 "build" : self.handle_build,
aad6f600 689 "info" : self.handle_info,
8276111d
MT
690 "keepalive" : self.handle_keepalive,
691 "repoupdate" : self.handle_repoupdate,
df9c4f62 692 "repo_create": self.handle_repo_create,
677ff42a
MT
693 }
694
6557ff4c
MT
695 @property
696 def pakfire_args(self):
36b328f2 697 ret = {}
6557ff4c 698
98733451
MT
699 if hasattr(self.args, "offline") and self.args.offline:
700 ret["downloader"] = {
701 "offline" : self.args.offline,
702 }
6a509182 703
6557ff4c
MT
704 return ret
705
a52f536c
MT
706 def parse_command_build(self):
707 # Implement the "build" command.
c62d93f1
MT
708 sub_build = self.sub_commands.add_parser("build",
709 help=_("Send a scrach build job to the server."))
710 sub_build.add_argument("package", nargs=1,
711 help=_("Give name of at least one package to build."))
712 sub_build.add_argument("--arch", "-a",
713 help=_("Limit build to only these architecture(s)."))
714 sub_build.add_argument("action", action="store_const", const="build")
a52f536c 715
677ff42a
MT
716 def parse_command_keepalive(self):
717 # Implement the "keepalive" command.
718 sub_keepalive = self.sub_commands.add_parser("keepalive",
719 help=_("Send a keepalive to the server."))
720 sub_keepalive.add_argument("action", action="store_const",
721 const="keepalive")
722
8276111d
MT
723 def parse_command_repoupdate(self):
724 # Implement the "repoupdate" command.
725 sub_repoupdate = self.sub_commands.add_parser("repoupdate",
726 help=_("Update all repositories."))
727 sub_repoupdate.add_argument("action", action="store_const",
728 const="repoupdate")
729
df9c4f62
MT
730 def parse_command_repo(self):
731 sub_repo = self.sub_commands.add_parser("repo",
732 help=_("Repository management commands."))
733
734 sub_repo_commands = sub_repo.add_subparsers()
735
736 self.parse_command_repo_create(sub_repo_commands)
737
738 def parse_command_repo_create(self, sub_commands):
739 sub_create = sub_commands.add_parser("create",
740 help=_("Create a new repository index."))
68c0e769
MT
741 sub_create.add_argument("path", nargs=1,
742 help=_("Path to the packages."))
743 sub_create.add_argument("inputs", nargs="+",
744 help=_("Path to input packages."))
745 sub_create.add_argument("--key", "-k", nargs="?",
746 help=_("Key to sign the repository with."))
df9c4f62
MT
747 sub_create.add_argument("action", action="store_const", const="repo_create")
748
aad6f600
MT
749 def parse_command_info(self):
750 sub_info = self.sub_commands.add_parser("info",
751 help=_("Dump some information about this machine."))
752 sub_info.add_argument("action", action="store_const", const="info")
753
677ff42a 754 def handle_keepalive(self):
3ad4bb5a 755 self.server.update_info()
9613a111 756
a52f536c 757 def handle_build(self):
c62d93f1
MT
758 # Arch.
759 if self.args.arch:
760 arches = self.args.arch.split()
761
762 (package,) = self.args.package
763
764 self.server.create_scratch_build({})
765 return
766
767 # Temporary folter for source package.
768 tmpdir = "/tmp/pakfire-%s" % util.random_string()
769
770 try:
771 os.makedirs(tmpdir)
772
773 pakfire.dist(package, resultdir=[tmpdir,])
774
775 for file in os.listdir(tmpdir):
776 file = os.path.join(tmpdir, file)
777
778 print file
779
780 finally:
781 if os.path.exists(tmpdir):
782 util.rm(tmpdir)
8276111d
MT
783
784 def handle_repoupdate(self):
785 self.server.update_repositories()
df9c4f62
MT
786
787 def handle_repo_create(self):
788 path = self.args.path[0]
789
3a1ddabb 790 p = self.create_pakfire()
36b328f2 791 p.repo_create(path, self.args.inputs, key_id=self.args.key)
c07a3ca7 792
aad6f600
MT
793 def handle_info(self):
794 info = self.server.info()
795
796 print "\n".join(info)
797
c07a3ca7 798
9b875540 799class CliBuilderIntern(Cli):
c07a3ca7
MT
800 def __init__(self):
801 self.parser = argparse.ArgumentParser(
802 description = _("Pakfire builder command line interface."),
803 )
804
805 self.parse_common_arguments()
806
807 # Add sub-commands.
808 self.sub_commands = self.parser.add_subparsers()
809
810 self.parse_command_build()
811
812 # Finally parse all arguments from the command line and save them.
813 self.args = self.parser.parse_args()
814
815 self.action2func = {
816 "build" : self.handle_build,
817 }
818
819 def parse_command_build(self):
820 # Implement the "build" command.
821 sub_build = self.sub_commands.add_parser("build",
822 help=_("Build one or more packages."))
823 sub_build.add_argument("package", nargs=1,
824 help=_("Give name of at least one package to build."))
825 sub_build.add_argument("action", action="store_const", const="build")
826
827 sub_build.add_argument("-a", "--arch",
828 help=_("Build the package for the given architecture."))
829 sub_build.add_argument("--resultdir", nargs="?",
830 help=_("Path were the output files should be copied to."))
831 sub_build.add_argument("-m", "--mode", nargs="?", default="development",
832 help=_("Mode to run in. Is either 'release' or 'development' (default)."))
833 sub_build.add_argument("--nodeps", action="store_true",
834 help=_("Do not verify build dependencies."))
47230b23
MT
835 sub_build.add_argument("--prepare", action="store_true",
836 help=_("Only run the prepare stage."))
c07a3ca7
MT
837
838 def handle_build(self):
839 # Get the package descriptor from the command line options
840 pkg = self.args.package[0]
841
842 # Check, if we got a regular file
843 if os.path.exists(pkg):
844 pkg = os.path.abspath(pkg)
845 else:
846 raise FileNotFoundError, pkg
847
013eb9f2
MT
848 # Create pakfire instance.
849 c = config.ConfigBuilder()
850 p = base.Pakfire(arch = self.args.arch, config = c)
854d8ccf 851
013eb9f2 852 # Disable all repositories.
8fe602a7 853 if self.args.nodeps:
013eb9f2
MT
854 p.repos.disable_repo("*")
855
856 # Limit stages that are to be run.
857 if self.args.prepare:
858 stages = ["prepare"]
8fe602a7 859 else:
013eb9f2 860 stages = None
4fffe3c4 861
013eb9f2 862 p.build(pkg, resultdir=self.args.resultdir, stages=stages)
c62d93f1
MT
863
864
865class CliClient(Cli):
7af1fde4
MT
866 pakfire = base.PakfireClient
867
c62d93f1
MT
868 def __init__(self):
869 self.parser = argparse.ArgumentParser(
870 description = _("Pakfire client command line interface."),
871 )
872
56278400 873 self.parse_common_arguments(offline_switch=True)
c62d93f1
MT
874
875 # Add sub-commands.
876 self.sub_commands = self.parser.add_subparsers()
877
878 self.parse_command_build()
879 self.parse_command_connection_check()
880 self.parse_command_info()
25a98632
MT
881 self.parse_command_jobs()
882 self.parse_command_builds()
37ff3f8f 883 self.parse_command_test()
c62d93f1
MT
884
885 # Finally parse all arguments from the command line and save them.
886 self.args = self.parser.parse_args()
887
888 self.action2func = {
889 "build" : self.handle_build,
890 "conn-check" : self.handle_connection_check,
891 "info" : self.handle_info,
25a98632
MT
892 "jobs_show" : self.handle_jobs_show,
893 "jobs_active" : self.handle_jobs_active,
894 "jobs_latest" : self.handle_jobs_latest,
895 "builds_show" : self.handle_builds_show,
37ff3f8f 896 "test" : self.handle_test,
c62d93f1
MT
897 }
898
aa14071d 899 # Read configuration.
7af1fde4 900 self.config = config.ConfigClient()
c62d93f1
MT
901
902 # Create connection to pakfire hub.
aa14071d 903 self.client = client.PakfireClient(self.config)
c62d93f1 904
7af1fde4
MT
905 @property
906 def pakfire_args(self):
907 return {
908 "config" : self.config,
909 }
910
c62d93f1
MT
911 def parse_command_build(self):
912 # Parse "build" command.
913 sub_build = self.sub_commands.add_parser("build",
914 help=_("Build a package remotely."))
915 sub_build.add_argument("package", nargs=1,
916 help=_("Give name of a package to build."))
917 sub_build.add_argument("action", action="store_const", const="build")
918
919 sub_build.add_argument("-a", "--arch",
920 help=_("Build the package for the given architecture."))
921
922 def parse_command_info(self):
923 # Implement the "info" command.
924 sub_info = self.sub_commands.add_parser("info",
925 help=_("Print some information about this host."))
926 sub_info.add_argument("action", action="store_const", const="info")
927
928 def parse_command_connection_check(self):
929 # Implement the "conn-check" command.
930 sub_conn_check = self.sub_commands.add_parser("conn-check",
931 help=_("Check the connection to the hub."))
932 sub_conn_check.add_argument("action", action="store_const", const="conn-check")
933
25a98632
MT
934 def parse_command_jobs(self):
935 sub_jobs = self.sub_commands.add_parser("jobs",
936 help=_("Show information about build jobs."))
937
938 sub_jobs_commands = sub_jobs.add_subparsers()
939
940 self.parse_command_jobs_active(sub_jobs_commands)
941 self.parse_command_jobs_latest(sub_jobs_commands)
942 self.parse_command_jobs_show(sub_jobs_commands)
943
944 def parse_command_jobs_active(self, sub_commands):
945 sub_active = sub_commands.add_parser("active",
946 help=_("Show a list of all active jobs."))
947 sub_active.add_argument("action", action="store_const", const="jobs_active")
948
949 def parse_command_jobs_latest(self, sub_commands):
950 sub_latest = sub_commands.add_parser("latest",
951 help=_("Show a list of all recently finished of failed build jobs."))
952 sub_latest.add_argument("action", action="store_const", const="jobs_latest")
953
954 def parse_command_jobs_show(self, sub_commands):
955 sub_show = sub_commands.add_parser("show",
956 help=_("Show details about given build job."))
957 sub_show.add_argument("job_id", nargs=1, help=_("The ID of the build job."))
958 sub_show.add_argument("action", action="store_const", const="jobs_show")
959
960 def parse_command_builds(self):
961 sub_builds = self.sub_commands.add_parser("builds",
962 help=_("Show information about builds."))
963
964 sub_builds_commands = sub_builds.add_subparsers()
965
966 self.parse_command_builds_show(sub_builds_commands)
967
968 def parse_command_builds_show(self, sub_commands):
969 sub_show = sub_commands.add_parser("show",
970 help=_("Show details about the given build."))
971 sub_show.add_argument("build_id", nargs=1, help=_("The ID of the build."))
972 sub_show.add_argument("action", action="store_const", const="builds_show")
973
37ff3f8f
MT
974 def parse_command_test(self):
975 sub_test = self.sub_commands.add_parser("test",
976 help=_("Test the connection to the hub."))
977 sub_test.add_argument("error_code", nargs=1, help=_("Error code to test."))
978 sub_test.add_argument("action", action="store_const", const="test")
979
c62d93f1
MT
980 def handle_build(self):
981 (package,) = self.args.package
982
983 # XXX just for now, we do only upload source pfm files.
984 assert os.path.exists(package)
985
b913e798
MT
986 # Create a temporary directory.
987 temp_dir = tempfile.mkdtemp()
988
989 try:
990 if package.endswith(".%s" % MAKEFILE_EXTENSION):
36b328f2 991 pakfire_args = {}
b913e798
MT
992
993 # Create a source package from the makefile.
36b328f2
MT
994 p = self.pakfire(**self.pakfire_args)
995 package = p.dist(package, temp_dir)
b913e798
MT
996
997 elif package.endswith(".%s" % PACKAGE_EXTENSION):
998 pass
c62d93f1 999
b913e798
MT
1000 else:
1001 raise Exception, "Unknown filetype: %s" % package
1002
1003 # Format arches.
1004 if self.args.arch:
aa14071d 1005 arches = self.args.arch.split(",")
b913e798
MT
1006 else:
1007 arches = None
c62d93f1 1008
b913e798 1009 # Create a new build on the server.
aa14071d
MT
1010 build_id = self.client.build_create(package, build_type="scratch",
1011 arches=arches)
b913e798
MT
1012
1013 finally:
1014 # Cleanup the temporary directory and all files.
1015 if os.path.exists(temp_dir):
1016 shutil.rmtree(temp_dir, ignore_errors=True)
c62d93f1 1017
aa14071d
MT
1018 # Monitor the build.
1019 if build_id:
1020 self.watch_build(build_id)
1021
c62d93f1
MT
1022 def handle_info(self):
1023 ret = []
1024
1025 ret.append("")
1026 ret.append(" PAKFIRE %s" % PAKFIRE_VERSION)
1027 ret.append("")
1028 ret.append(" %-20s: %s" % (_("Hostname"), system.hostname))
7af1fde4
MT
1029 ret.append(" %-20s: %s" % (_("Pakfire hub"), self.config.get("client", "server")))
1030 if self.config.get("client", "username") and self.config.get("client", "password"):
c62d93f1 1031 ret.append(" %-20s: %s" % \
7af1fde4 1032 (_("Username"), self.config.get("client", "username")))
c62d93f1
MT
1033 ret.append("")
1034
1035 # Hardware information
1036 ret.append(" %s:" % _("Hardware information"))
1037 ret.append(" %-16s: %s" % (_("CPU model"), system.cpu_model))
1038 ret.append(" %-16s: %s" % (_("Memory"), util.format_size(system.memory)))
cae35096 1039 ret.append(" %-16s: %s" % (_("Parallelism"), system.parallelism))
c62d93f1 1040 ret.append("")
790a44cc
MT
1041 ret.append(" %-16s: %s" % (_("Native arch"), system.native_arch))
1042 if not system.arch == system.native_arch:
1043 ret.append(" %-16s: %s" % (_("Default arch"), system.arch))
c62d93f1
MT
1044
1045 header = _("Supported arches")
1046 for arch in system.supported_arches:
1047 ret.append(" %-16s: %s" % (header, arch))
1048 header = ""
1049 ret.append("")
1050
1051 for line in ret:
1052 print line
1053
1054 def handle_connection_check(self):
1055 ret = []
1056
1057 address = self.client.get_my_address()
1058 ret.append(" %-20s: %s" % (_("Your IP address"), address))
1059 ret.append("")
1060
1061 authenticated = self.client.check_auth()
1062 if authenticated:
1063 ret.append(" %s" % _("You are authenticated to the build service:"))
1064
1065 user = self.client.get_user_profile()
1066 assert user, "Could not fetch user infomation"
1067
1068 keys = [
1069 ("name", _("User name")),
1070 ("realname", _("Real name")),
1071 ("email", _("Email address")),
1072 ("registered", _("Registered")),
1073 ]
1074
1075 for key, desc in keys:
1076 ret.append(" %-18s: %s" % (desc, user.get(key)))
1077
1078 else:
1079 ret.append(_("You could not be authenticated to the build service."))
1080
1081 for line in ret:
1082 print line
1083
25a98632
MT
1084 def _print_jobs(self, jobs, heading=None):
1085 if heading:
1086 print "%s:" % heading
1087 print
1088
1089 for job in jobs:
1090 line = " [%(type)8s] %(name)-30s: %(state)s"
1091
1092 print line % job
1093
1094 print # Empty line at the end.
1095
1096 def handle_jobs_active(self):
1097 jobs = self.client.get_active_jobs()
1098
1099 if not jobs:
1100 print _("No ongoing jobs found.")
1101 return
1102
1103 self._print_jobs(jobs, _("Active build jobs"))
1104
1105 def handle_jobs_latest(self):
1106 jobs = self.client.get_latest_jobs()
1107
1108 if not jobs:
1109 print _("No jobs found.")
1110 return
1111
1112 self._print_jobs(jobs, _("Recently processed build jobs"))
1113
1114 def handle_builds_show(self):
1115 (build_id,) = self.args.build_id
1116
1117 build = self.client.get_build(build_id)
1118 if not build:
1119 print _("A build with ID %s could not be found.") % build_id
1120 return
1121
1122 print _("Build: %(name)s") % build
1123
1124 fmt = "%-14s: %s"
1125 lines = [
1126 fmt % (_("State"), build["state"]),
1127 fmt % (_("Priority"), build["priority"]),
1128 ]
1129
1130 lines.append("%s:" % _("Jobs"))
1131 for job in build["jobs"]:
1132 lines.append(" * [%(uuid)s] %(name)-30s: %(state)s" % job)
1133
1134 for line in lines:
1135 print " ", line
1136 print
1137
1138 def handle_jobs_show(self):
1139 (job_id,) = self.args.job_id
1140
1141 job = self.client.get_job(job_id)
1142 if not job:
1143 print _("A job with ID %s could not be found.") % job_id
1144 return
1145
1146 builder = None
1147 if job["builder_id"]:
1148 builder = self.client.get_builder(job["builder_id"])
1149
1150 print _("Job: %(name)s") % job
1151
1152 fmt = "%-14s: %s"
1153 lines = [
1154 fmt % (_("State"), job["state"]),
1155 fmt % (_("Arch"), job["arch"]),
1156 ]
1157
1158 if builder:
1159 lines += [
1160 fmt % (_("Build host"), builder["name"]),
1161 "",
1162 ]
1163
1164 lines += [
1165 fmt % (_("Time created"), job["time_created"]),
1166 fmt % (_("Time started"), job["time_started"]),
1167 fmt % (_("Time finished"), job["time_finished"]),
1168 fmt % (_("Duration"), job["duration"]),
1169 ]
1170
1171 if job["packages"]:
1172 lines += ["", "%s:" % _("Packages")]
1173
1174 for pkg in job["packages"]:
1175 pkg_lines = [
1176 "* %(friendly_name)s" % pkg,
1177 " %(uuid)s" % pkg,
1178 "",
1179 ]
1180
1181 lines += [" %s" % line for line in pkg_lines]
1182
1183 for line in lines:
1184 print " ", line
1185 print # New line.
1186
37ff3f8f
MT
1187 def handle_test(self):
1188 error_code = self.args.error_code[0]
1189
1190 try:
1191 error_code = int(error_code)
1192 except ValueError:
1193 error_code = 0
1194
1195 if error_code < 100 or error_code > 999:
1196 raise Error, _("Invalid error code given.")
1197
1198 res = self.client.test_code(error_code)
1199 print _("Reponse from the server: %s") % res
1200
aa14071d
MT
1201 def watch_build(self, build_id):
1202 print self.client.build_get(build_id)
1203 # XXX TODO
1204 print build_id
1205
c62d93f1
MT
1206
1207class CliDaemon(Cli):
1208 def __init__(self):
1209 self.parser = argparse.ArgumentParser(
1210 description = _("Pakfire daemon command line interface."),
1211 )
1212
56278400 1213 self.parse_common_arguments(offline_switch=True)
c62d93f1
MT
1214
1215 # Finally parse all arguments from the command line and save them.
1216 self.args = self.parser.parse_args()
1217
1218 def run(self):
1219 """
1220 Runs the pakfire daemon with provided settings.
1221 """
1222 # Read the configuration file for the daemon.
aa14071d
MT
1223 self.config = config.ConfigDaemon()
1224 logger.setup_logging(self.config)
c62d93f1
MT
1225
1226 # Create daemon instance.
aa14071d 1227 d = daemon.PakfireDaemon(self.config)
c62d93f1
MT
1228 try:
1229 d.run()
1230
1231 # We cannot just kill the daemon, it needs a smooth shutdown.
1232 except (SystemExit, KeyboardInterrupt):
1233 d.shutdown()
68c0e769
MT
1234
1235
1236class CliKey(Cli):
1f6c466e
MT
1237 pakfire = base.PakfireKey
1238
68c0e769
MT
1239 def __init__(self):
1240 self.parser = argparse.ArgumentParser(
1241 description = _("Pakfire key command line interface."),
1242 )
1243
56278400 1244 self.parse_common_arguments(offline_switch=True)
68c0e769
MT
1245
1246 # Add sub-commands.
1247 self.sub_commands = self.parser.add_subparsers()
1248
68c0e769
MT
1249 self.parse_command_generate()
1250 self.parse_command_import()
1251 self.parse_command_export()
eaf999ef 1252 self.parse_command_delete()
68c0e769
MT
1253 self.parse_command_list()
1254 self.parse_command_sign()
1255 self.parse_command_verify()
1256
1257 # Finally parse all arguments from the command line and save them.
1258 self.args = self.parser.parse_args()
1259
68c0e769 1260 self.action2func = {
68c0e769
MT
1261 "generate" : self.handle_generate,
1262 "import" : self.handle_import,
1263 "export" : self.handle_export,
eaf999ef 1264 "delete" : self.handle_delete,
68c0e769
MT
1265 "list" : self.handle_list,
1266 "sign" : self.handle_sign,
1267 "verify" : self.handle_verify,
1268 }
1269
1270 @property
1271 def pakfire_args(self):
36b328f2 1272 return {}
68c0e769 1273
68c0e769
MT
1274 def parse_command_generate(self):
1275 # Parse "generate" command.
1276 sub_gen = self.sub_commands.add_parser("generate",
1277 help=_("Import a key from file."))
1278 sub_gen.add_argument("--realname", nargs=1,
1279 help=_("The real name of the owner of this key."))
1280 sub_gen.add_argument("--email", nargs=1,
1281 help=_("The email address of the owner of this key."))
1282 sub_gen.add_argument("action", action="store_const", const="generate")
1283
1284 def parse_command_import(self):
1285 # Parse "import" command.
1286 sub_import = self.sub_commands.add_parser("import",
1287 help=_("Import a key from file."))
1288 sub_import.add_argument("filename", nargs=1,
1289 help=_("Filename of that key to import."))
1290 sub_import.add_argument("action", action="store_const", const="import")
1291
1292 def parse_command_export(self):
1293 # Parse "export" command.
1294 sub_export = self.sub_commands.add_parser("export",
1295 help=_("Export a key to a file."))
1296 sub_export.add_argument("keyid", nargs=1,
1297 help=_("The ID of the key to export."))
1298 sub_export.add_argument("filename", nargs=1,
1299 help=_("Write the key to this file."))
1300 sub_export.add_argument("action", action="store_const", const="export")
1301
eaf999ef
MT
1302 def parse_command_delete(self):
1303 # Parse "delete" command.
1304 sub_del = self.sub_commands.add_parser("delete",
1305 help=_("Delete a key from the local keyring."))
1306 sub_del.add_argument("keyid", nargs=1,
1307 help=_("The ID of the key to delete."))
1308 sub_del.add_argument("action", action="store_const", const="delete")
1309
68c0e769
MT
1310 def parse_command_list(self):
1311 # Parse "list" command.
1312 sub_list = self.sub_commands.add_parser("list",
1313 help=_("List all imported keys."))
1314 sub_list.add_argument("action", action="store_const", const="list")
1315
1316 def parse_command_sign(self):
1317 # Implement the "sign" command.
1318 sub_sign = self.sub_commands.add_parser("sign",
1319 help=_("Sign one or more packages."))
1320 sub_sign.add_argument("--key", "-k", nargs=1,
1321 help=_("Key that is used sign the package(s)."))
1322 sub_sign.add_argument("package", nargs="+",
1323 help=_("Package(s) to sign."))
1324 sub_sign.add_argument("action", action="store_const", const="sign")
1325
1326 def parse_command_verify(self):
1327 # Implement the "verify" command.
1328 sub_verify = self.sub_commands.add_parser("verify",
1329 help=_("Verify one or more packages."))
1330 #sub_verify.add_argument("--key", "-k", nargs=1,
1331 # help=_("Key that is used verify the package(s)."))
1332 sub_verify.add_argument("package", nargs="+",
1333 help=_("Package(s) to verify."))
1334 sub_verify.add_argument("action", action="store_const", const="verify")
1335
68c0e769
MT
1336 def handle_generate(self):
1337 realname = self.args.realname[0]
1338 email = self.args.email[0]
1339
1340 print _("Generating the key may take a moment...")
1341 print
1342
1343 # Generate the key.
3a1ddabb 1344 p = self.create_pakfire()
1f6c466e 1345 p.keyring.gen_key(realname, email)
68c0e769
MT
1346
1347 def handle_import(self):
1348 filename = self.args.filename[0]
1349
1350 # Simply import the file.
3a1ddabb 1351 p = self.create_pakfire()
1f6c466e 1352 p.keyring.import_key(filename)
68c0e769
MT
1353
1354 def handle_export(self):
1355 keyid = self.args.keyid[0]
1356 filename = self.args.filename[0]
1357
3a1ddabb 1358 p = self.create_pakfire()
1f6c466e 1359 p.keyring.export_key(keyid, filename)
68c0e769 1360
eaf999ef
MT
1361 def handle_delete(self):
1362 keyid = self.args.keyid[0]
1363
3a1ddabb 1364 p = self.create_pakfire()
1f6c466e 1365 p.keyring.delete_key(keyid)
eaf999ef 1366
68c0e769 1367 def handle_list(self):
3a1ddabb 1368 p = self.create_pakfire()
1f6c466e 1369 for line in p.keyring.list_keys():
68c0e769
MT
1370 print line
1371
1372 def handle_sign(self):
1373 # Get the files from the command line options
1374 files = []
1375
1376 for file in self.args.package:
1377 # Check, if we got a regular file
1378 if os.path.exists(file):
1379 file = os.path.abspath(file)
1380 files.append(file)
1381
1382 else:
1383 raise FileNotFoundError, file
1384
1385 key = self.args.key[0]
1386
36b328f2 1387 # Create pakfire instance.
3a1ddabb 1388 p = self.create_pakfire()
36b328f2 1389
68c0e769
MT
1390 for file in files:
1391 # Open the package.
36b328f2 1392 pkg = packages.open(p, None, file)
68c0e769
MT
1393
1394 print _("Signing %s...") % pkg.friendly_name
1395 pkg.sign(key)
1396
1397 def handle_verify(self):
1398 # Get the files from the command line options
1399 files = []
1400
1401 for file in self.args.package:
1402 # Check, if we got a regular file
1403 if os.path.exists(file) and not os.path.isdir(file):
1404 file = os.path.abspath(file)
1405 files.append(file)
1406
36b328f2 1407 # Create pakfire instance.
3a1ddabb 1408 p = self.create_pakfire()
36b328f2 1409
68c0e769
MT
1410 for file in files:
1411 # Open the package.
36b328f2 1412 pkg = packages.open(p, None, file)
68c0e769
MT
1413
1414 print _("Verifying %s...") % pkg.friendly_name
1415 sigs = pkg.verify()
1416
1417 for sig in sigs:
3a1ddabb 1418 key = p.keyring.get_key(sig.fpr)
68c0e769
MT
1419 if key:
1420 subkey = key.subkeys[0]
1421
1422 print " %s %s" % (subkey.fpr[-16:], key.uids[0].uid)
1423 if sig.validity:
1424 print " %s" % _("This signature is valid.")
1425
1426 else:
1427 print " %s <%s>" % (sig.fpr, _("Unknown key"))
1428 print " %s" % _("Could not check if this signature is valid.")
1429
1430 created = datetime.datetime.fromtimestamp(sig.timestamp)
1431 print " %s" % _("Created: %s") % created
1432
1433 if sig.exp_timestamp:
1434 expires = datetime.datetime.fromtimestamp(sig.exp_timestamp)
1435 print " %s" % _("Expires: %s") % expires
1436
1437 print # Empty line