]> git.ipfire.org Git - pakfire.git/blob - python/pakfire/cli.py
Bigger changes in the way we read configuration.
[pakfire.git] / python / pakfire / cli.py
1 #!/usr/bin/python
2 ###############################################################################
3 # #
4 # Pakfire - The IPFire package management system #
5 # Copyright (C) 2011 Pakfire development team #
6 # #
7 # This program is free software: you can redistribute it and/or modify #
8 # it under the terms of the GNU General Public License as published by #
9 # the Free Software Foundation, either version 3 of the License, or #
10 # (at your option) any later version. #
11 # #
12 # This program is distributed in the hope that it will be useful, #
13 # but WITHOUT ANY WARRANTY; without even the implied warranty of #
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
15 # GNU General Public License for more details. #
16 # #
17 # You should have received a copy of the GNU General Public License #
18 # along with this program. If not, see <http://www.gnu.org/licenses/>. #
19 # #
20 ###############################################################################
21
22 import argparse
23 import os
24 import shutil
25 import sys
26 import tempfile
27
28 import pakfire.api as pakfire
29
30 import client
31 import config
32 import logger
33 import packages
34 import repository
35 import server
36 import util
37
38 from system import system
39 from constants import *
40 from i18n import _
41
42 # Initialize a very simple logging that is removed when a Pakfire instance
43 # is started.
44 logger.setup_logging()
45
46 class Cli(object):
47 def __init__(self):
48 self.parser = argparse.ArgumentParser(
49 description = _("Pakfire command line interface."),
50 )
51
52 self.parse_common_arguments()
53
54 self.parser.add_argument("--root", metavar="PATH",
55 default="/",
56 help=_("The path where pakfire should operate in."))
57
58 # Add sub-commands.
59 self.sub_commands = self.parser.add_subparsers()
60
61 self.parse_command_install()
62 self.parse_command_localinstall()
63 self.parse_command_reinstall()
64 self.parse_command_remove()
65 self.parse_command_info()
66 self.parse_command_search()
67 self.parse_command_check_update()
68 self.parse_command_update()
69 self.parse_command_downgrade()
70 self.parse_command_provides()
71 self.parse_command_grouplist()
72 self.parse_command_groupinstall()
73 self.parse_command_repolist()
74 self.parse_command_clean()
75 self.parse_command_check()
76 self.parse_command_resolvdep()
77
78 # Finally parse all arguments from the command line and save them.
79 self.args = self.parser.parse_args()
80
81 self.action2func = {
82 "install" : self.handle_install,
83 "localinstall" : self.handle_localinstall,
84 "reinstall" : self.handle_reinstall,
85 "remove" : self.handle_remove,
86 "check_update" : self.handle_check_update,
87 "update" : self.handle_update,
88 "downgrade" : self.handle_downgrade,
89 "info" : self.handle_info,
90 "search" : self.handle_search,
91 "provides" : self.handle_provides,
92 "grouplist" : self.handle_grouplist,
93 "groupinstall" : self.handle_groupinstall,
94 "repolist" : self.handle_repolist,
95 "clean_all" : self.handle_clean_all,
96 "check" : self.handle_check,
97 "resolvdep" : self.handle_resolvdep,
98 }
99
100 @property
101 def pakfire_args(self):
102 ret = { "mode" : "normal" }
103
104 if hasattr(self.args, "root"):
105 ret["path"] = self.args.root
106
107 if hasattr(self.args, "disable_repo"):
108 ret["disable_repos"] = self.args.disable_repo
109
110 if hasattr(self.args, "enable_repo"):
111 ret["enable_repos"] = self.args.enable_repo
112
113 if hasattr(self.args, "offline"):
114 ret["offline"] = self.args.offline
115
116 return ret
117
118 def parse_common_arguments(self, repo_manage_switches=True, offline_switch=True):
119 self.parser.add_argument("--version", action="version",
120 version="%(prog)s " + PAKFIRE_VERSION)
121
122 self.parser.add_argument("-v", "--verbose", action="store_true",
123 help=_("Enable verbose output."))
124
125 self.parser.add_argument("-c", "--config", nargs="?",
126 help=_("Path to a configuration file to load."))
127
128 if repo_manage_switches:
129 self.parser.add_argument("--disable-repo", nargs="*", metavar="REPO",
130 help=_("Disable a repository temporarily."))
131
132 self.parser.add_argument("--enabled-repo", nargs="*", metavar="REPO",
133 help=_("Enable a repository temporarily."))
134
135 if offline_switch:
136 self.parser.add_argument("--offline", action="store_true",
137 help=_("Run pakfire in offline mode."))
138
139 def parse_command_install(self):
140 # Implement the "install" command.
141 sub_install = self.sub_commands.add_parser("install",
142 help=_("Install one or more packages to the system."))
143 sub_install.add_argument("package", nargs="+",
144 help=_("Give name of at least one package to install."))
145 sub_install.add_argument("action", action="store_const", const="install")
146
147 def parse_command_localinstall(self):
148 # Implement the "localinstall" command.
149 sub_install = self.sub_commands.add_parser("localinstall",
150 help=_("Install one or more packages from the filesystem."))
151 sub_install.add_argument("package", nargs="+",
152 help=_("Give filename of at least one package."))
153 sub_install.add_argument("action", action="store_const", const="localinstall")
154
155 def parse_command_reinstall(self):
156 # Implement the "reinstall" command.
157 sub_install = self.sub_commands.add_parser("reinstall",
158 help=_("Reinstall one or more packages."))
159 sub_install.add_argument("package", nargs="+",
160 help=_("Give name of at least one package to reinstall."))
161 sub_install.add_argument("action", action="store_const", const="reinstall")
162
163 def parse_command_remove(self):
164 # Implement the "remove" command.
165 sub_remove = self.sub_commands.add_parser("remove",
166 help=_("Remove one or more packages from the system."))
167 sub_remove.add_argument("package", nargs="+",
168 help=_("Give name of at least one package to remove."))
169 sub_remove.add_argument("action", action="store_const", const="remove")
170
171 @staticmethod
172 def _parse_command_update(parser):
173 parser.add_argument("package", nargs="*",
174 help=_("Give a name of a package to update or leave emtpy for all."))
175 parser.add_argument("--exclude", "-x", nargs="+",
176 help=_("Exclude package from update."))
177 parser.add_argument("--allow-vendorchange", action="store_true",
178 help=_("Allow changing the vendor of packages."))
179 parser.add_argument("--allow-archchange", action="store_true",
180 help=_("Allow changing the architecture of packages."))
181
182 def parse_command_update(self):
183 # Implement the "update" command.
184 sub_update = self.sub_commands.add_parser("update",
185 help=_("Update the whole system or one specific package."))
186 sub_update.add_argument("action", action="store_const", const="update")
187 self._parse_command_update(sub_update)
188
189 def parse_command_check_update(self):
190 # Implement the "check-update" command.
191 sub_check_update = self.sub_commands.add_parser("check-update",
192 help=_("Check, if there are any updates available."))
193 sub_check_update.add_argument("action", action="store_const", const="check_update")
194 self._parse_command_update(sub_check_update)
195
196 def parse_command_downgrade(self):
197 # Implement the "downgrade" command.
198 sub_downgrade = self.sub_commands.add_parser("downgrade",
199 help=_("Downgrade one or more packages."))
200 sub_downgrade.add_argument("package", nargs="*",
201 help=_("Give a name of a package to downgrade."))
202 sub_downgrade.add_argument("--allow-vendorchange", action="store_true",
203 help=_("Allow changing the vendor of packages."))
204 sub_downgrade.add_argument("--allow-archchange", action="store_true",
205 help=_("Allow changing the architecture of packages."))
206 sub_downgrade.add_argument("action", action="store_const", const="downgrade")
207
208 def parse_command_info(self):
209 # Implement the "info" command.
210 sub_info = self.sub_commands.add_parser("info",
211 help=_("Print some information about the given package(s)."))
212 sub_info.add_argument("package", nargs="+",
213 help=_("Give at least the name of one package."))
214 sub_info.add_argument("action", action="store_const", const="info")
215
216 def parse_command_search(self):
217 # Implement the "search" command.
218 sub_search = self.sub_commands.add_parser("search",
219 help=_("Search for a given pattern."))
220 sub_search.add_argument("pattern",
221 help=_("A pattern to search for."))
222 sub_search.add_argument("action", action="store_const", const="search")
223
224 def parse_command_provides(self):
225 # Implement the "provides" command
226 sub_provides = self.sub_commands.add_parser("provides",
227 help=_("Get a list of packages that provide a given file or feature."))
228 sub_provides.add_argument("pattern", nargs="+",
229 help=_("File or feature to search for."))
230 sub_provides.add_argument("action", action="store_const", const="provides")
231
232 def parse_command_grouplist(self):
233 # Implement the "grouplist" command
234 sub_grouplist = self.sub_commands.add_parser("grouplist",
235 help=_("Get list of packages that belong to the given group."))
236 sub_grouplist.add_argument("group", nargs=1,
237 help=_("Group name to search for."))
238 sub_grouplist.add_argument("action", action="store_const", const="grouplist")
239
240 def parse_command_groupinstall(self):
241 # Implement the "grouplist" command
242 sub_groupinstall = self.sub_commands.add_parser("groupinstall",
243 help=_("Install all packages that belong to the given group."))
244 sub_groupinstall.add_argument("group", nargs=1,
245 help=_("Group name."))
246 sub_groupinstall.add_argument("action", action="store_const", const="groupinstall")
247
248 def parse_command_repolist(self):
249 # Implement the "repolist" command
250 sub_repolist = self.sub_commands.add_parser("repolist",
251 help=_("List all currently enabled repositories."))
252 sub_repolist.add_argument("action", action="store_const", const="repolist")
253
254 def parse_command_clean(self):
255 sub_clean = self.sub_commands.add_parser("clean", help=_("Cleanup commands."))
256
257 sub_clean_commands = sub_clean.add_subparsers()
258
259 self.parse_command_clean_all(sub_clean_commands)
260
261 def parse_command_clean_all(self, sub_commands):
262 sub_create = sub_commands.add_parser("all",
263 help=_("Cleanup all temporary files."))
264 sub_create.add_argument("action", action="store_const", const="clean_all")
265
266 def parse_command_check(self):
267 # Implement the "check" command
268 sub_check = self.sub_commands.add_parser("check",
269 help=_("Check the system for any errors."))
270 sub_check.add_argument("action", action="store_const", const="check")
271
272 def parse_command_resolvdep(self):
273 # Implement the "resolvdep" command.
274 sub_resolvdep = self.sub_commands.add_parser("resolvdep",
275 help=_("Check the dependencies for a particular package."))
276 sub_resolvdep.add_argument("package", nargs="+",
277 help=_("Give name of at least one package to check."))
278 sub_resolvdep.add_argument("action", action="store_const", const="resolvdep")
279
280 def run(self):
281 action = self.args.action
282
283 try:
284 func = self.action2func[action]
285 except KeyError:
286 raise Exception, "Unhandled action: %s" % action
287
288 return func()
289
290 def handle_info(self, long=False):
291 pkgs = pakfire.info(self.args.package, **self.pakfire_args)
292
293 for pkg in pkgs:
294 print pkg.dump(long=long)
295
296 def handle_search(self):
297 pkgs = pakfire.search(self.args.pattern, **self.pakfire_args)
298
299 for pkg in pkgs:
300 print pkg.dump(short=True)
301
302 def handle_update(self, **args):
303 args.update(self.pakfire_args)
304
305 pakfire.update(self.args.package, excludes=self.args.exclude,
306 allow_vendorchange=self.args.allow_vendorchange,
307 allow_archchange=self.args.allow_archchange,
308 **args)
309
310 def handle_check_update(self):
311 self.handle_update(check=True)
312
313 def handle_downgrade(self, **args):
314 args.update(self.pakfire_args)
315
316 pakfire.downgrade(self.args.package,
317 allow_vendorchange=self.args.allow_vendorchange,
318 allow_archchange=self.args.allow_archchange,
319 **args)
320
321 def handle_install(self):
322 pakfire.install(self.args.package, **self.pakfire_args)
323
324 def handle_localinstall(self):
325 pakfire.localinstall(self.args.package, **self.pakfire_args)
326
327 def handle_reinstall(self):
328 pakfire.reinstall(self.args.package, **self.pakfire_args)
329
330 def handle_remove(self):
331 pakfire.remove(self.args.package, **self.pakfire_args)
332
333 def handle_provides(self):
334 pkgs = pakfire.provides(self.args.pattern, **self.pakfire_args)
335
336 for pkg in pkgs:
337 print pkg.dump()
338
339 def handle_grouplist(self):
340 pkgs = pakfire.grouplist(self.args.group[0], **self.pakfire_args)
341
342 for pkg in pkgs:
343 print " * %s" % pkg
344
345 def handle_groupinstall(self):
346 pakfire.groupinstall(self.args.group[0], **self.pakfire_args)
347
348 def handle_repolist(self):
349 repos = pakfire.repo_list(**self.pakfire_args)
350
351 FORMAT = " %-20s %8s %12s %12s "
352
353 title = FORMAT % (_("Repository"), _("Enabled"), _("Priority"), _("Packages"))
354 print title
355 print "=" * len(title) # spacing line
356
357 for repo in repos:
358 # Skip the installed repository.
359 if repo.name == "installed":
360 continue
361
362 print FORMAT % (repo.name, repo.enabled, repo.priority, len(repo))
363
364 def handle_clean_all(self):
365 print _("Cleaning up everything...")
366
367 pakfire.clean_all(**self.pakfire_args)
368
369 def handle_check(self):
370 pakfire.check(**self.pakfire_args)
371
372 def handle_resolvdep(self):
373 pakfire.resolvdep(self.args.package, **self.pakfire_args)
374
375
376 class CliBuilder(Cli):
377 def __init__(self):
378 # Check if we are already running in a pakfire container. In that
379 # case, we cannot start another pakfire-builder.
380 if os.environ.get("container", None) == "pakfire-builder":
381 raise PakfireContainerError, _("You cannot run pakfire-builder in a pakfire chroot.")
382
383 self.parser = argparse.ArgumentParser(
384 description = _("Pakfire builder command line interface."),
385 )
386
387 self.parse_common_arguments()
388
389 # Add sub-commands.
390 self.sub_commands = self.parser.add_subparsers()
391
392 self.parse_command_build()
393 self.parse_command_dist()
394 self.parse_command_info()
395 self.parse_command_search()
396 self.parse_command_shell()
397 self.parse_command_update()
398 self.parse_command_provides()
399 self.parse_command_grouplist()
400 self.parse_command_repolist()
401 self.parse_command_clean()
402 self.parse_command_resolvdep()
403 self.parse_command_cache()
404
405 # Finally parse all arguments from the command line and save them.
406 self.args = self.parser.parse_args()
407
408 self.action2func = {
409 "build" : self.handle_build,
410 "dist" : self.handle_dist,
411 "update" : self.handle_update,
412 "info" : self.handle_info,
413 "search" : self.handle_search,
414 "shell" : self.handle_shell,
415 "provides" : self.handle_provides,
416 "grouplist" : self.handle_grouplist,
417 "repolist" : self.handle_repolist,
418 "clean_all" : self.handle_clean_all,
419 "resolvdep" : self.handle_resolvdep,
420 "cache_create": self.handle_cache_create,
421 "cache_cleanup": self.handle_cache_cleanup,
422 }
423
424 @property
425 def pakfire_args(self):
426 ret = { "mode" : "builder" }
427
428 if hasattr(self.args, "disable_repo"):
429 ret["disable_repos"] = self.args.disable_repo
430
431 if hasattr(self.args, "enable_repo"):
432 ret["enable_repos"] = self.args.enable_repo
433
434 if hasattr(self.args, "offline"):
435 ret["offline"] = self.args.offline
436
437 return ret
438
439 def parse_command_update(self):
440 # Implement the "update" command.
441 sub_update = self.sub_commands.add_parser("update",
442 help=_("Update the package indexes."))
443 sub_update.add_argument("action", action="store_const", const="update")
444
445 def parse_command_build(self):
446 # Implement the "build" command.
447 sub_build = self.sub_commands.add_parser("build",
448 help=_("Build one or more packages."))
449 sub_build.add_argument("package", nargs=1,
450 help=_("Give name of at least one package to build."))
451 sub_build.add_argument("action", action="store_const", const="build")
452
453 sub_build.add_argument("-a", "--arch",
454 help=_("Build the package for the given architecture."))
455 sub_build.add_argument("--resultdir", nargs="?",
456 help=_("Path were the output files should be copied to."))
457 sub_build.add_argument("-m", "--mode", nargs="?", default="development",
458 help=_("Mode to run in. Is either 'release' or 'development' (default)."))
459 sub_build.add_argument("--after-shell", action="store_true",
460 help=_("Run a shell after a successful build."))
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."))
466 sub_shell.add_argument("package", nargs="?",
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."))
472 sub_shell.add_argument("-m", "--mode", nargs="?", default="development",
473 help=_("Mode to run in. Is either 'release' or 'development' (default)."))
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."))
479 sub_dist.add_argument("package", nargs="+",
480 help=_("Give name(s) of a package(s)."))
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
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
507 def handle_info(self):
508 Cli.handle_info(self, long=True)
509
510 def handle_build(self):
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
518 else:
519 raise FileNotFoundError, pkg
520
521 pakfire.build(pkg, builder_mode=self.args.mode,
522 arch=self.args.arch, resultdirs=[self.args.resultdir,],
523 shell=True, after_shell=self.args.after_shell, **self.pakfire_args)
524
525 def handle_shell(self):
526 pkg = None
527
528 # Get the package descriptor from the command line options
529 if self.args.package:
530 pkg = self.args.package
531
532 # Check, if we got a regular file
533 if os.path.exists(pkg):
534 pkg = os.path.abspath(pkg)
535
536 else:
537 raise FileNotFoundError, pkg
538
539 pakfire.shell(pkg, builder_mode=self.args.mode,
540 arch=self.args.arch, **self.pakfire_args)
541
542 def handle_dist(self):
543 # Get the packages from the command line options
544 pkgs = []
545
546 for pkg in self.args.package:
547 # Check, if we got a regular file
548 if os.path.exists(pkg):
549 pkg = os.path.abspath(pkg)
550 pkgs.append(pkg)
551
552 else:
553 raise FileNotFoundError, pkg
554
555 # Put packages to where the user said or our
556 # current working directory.
557 resultdir = self.args.resultdir or os.getcwd()
558
559 # Change the default pakfire configuration, because
560 # packaging source packages can be done in server mode.
561 pakfire_args = self.pakfire_args
562 pakfire_args["mode"] = "server"
563
564 for pkg in pkgs:
565 pakfire.dist(pkg, resultdir=resultdir, **pakfire_args)
566
567 def handle_provides(self):
568 pkgs = pakfire.provides(self.args.pattern, **self.pakfire_args)
569
570 for pkg in pkgs:
571 print pkg.dump(long=True)
572
573 def handle_cache_create(self):
574 pakfire.cache_create(**self.pakfire_args)
575
576 def handle_cache_cleanup(self):
577 for env in os.listdir(CACHE_ENVIRON_DIR):
578 if not env.endswith(".cache"):
579 continue
580
581 print _("Removing environment cache file: %s..." % env)
582 env = os.path.join(CACHE_ENVIRON_DIR, env)
583
584 try:
585 os.unlink(env)
586 except OSError:
587 print _("Could not remove file: %s") % env
588
589
590 class CliServer(Cli):
591 def __init__(self):
592 self.parser = argparse.ArgumentParser(
593 description = _("Pakfire server command line interface."),
594 )
595
596 self.parse_common_arguments()
597
598 # Add sub-commands.
599 self.sub_commands = self.parser.add_subparsers()
600
601 self.parse_command_build()
602 self.parse_command_keepalive()
603 self.parse_command_repoupdate()
604 self.parse_command_repo()
605 self.parse_command_info()
606
607 # Finally parse all arguments from the command line and save them.
608 self.args = self.parser.parse_args()
609
610 self.server = server.Server(**self.pakfire_args)
611
612 self.action2func = {
613 "build" : self.handle_build,
614 "info" : self.handle_info,
615 "keepalive" : self.handle_keepalive,
616 "repoupdate" : self.handle_repoupdate,
617 "repo_create": self.handle_repo_create,
618 }
619
620 @property
621 def pakfire_args(self):
622 ret = { "mode" : "server" }
623
624 if hasattr(self.args, "offline"):
625 ret["offline"] = self.args.offline
626
627 return ret
628
629 def parse_command_build(self):
630 # Implement the "build" command.
631 sub_build = self.sub_commands.add_parser("build",
632 help=_("Send a scrach build job to the server."))
633 sub_build.add_argument("package", nargs=1,
634 help=_("Give name of at least one package to build."))
635 sub_build.add_argument("--arch", "-a",
636 help=_("Limit build to only these architecture(s)."))
637 sub_build.add_argument("action", action="store_const", const="build")
638
639 def parse_command_keepalive(self):
640 # Implement the "keepalive" command.
641 sub_keepalive = self.sub_commands.add_parser("keepalive",
642 help=_("Send a keepalive to the server."))
643 sub_keepalive.add_argument("action", action="store_const",
644 const="keepalive")
645
646 def parse_command_repoupdate(self):
647 # Implement the "repoupdate" command.
648 sub_repoupdate = self.sub_commands.add_parser("repoupdate",
649 help=_("Update all repositories."))
650 sub_repoupdate.add_argument("action", action="store_const",
651 const="repoupdate")
652
653 def parse_command_repo(self):
654 sub_repo = self.sub_commands.add_parser("repo",
655 help=_("Repository management commands."))
656
657 sub_repo_commands = sub_repo.add_subparsers()
658
659 self.parse_command_repo_create(sub_repo_commands)
660
661 def parse_command_repo_create(self, sub_commands):
662 sub_create = sub_commands.add_parser("create",
663 help=_("Create a new repository index."))
664 sub_create.add_argument("path", nargs=1, help=_("Path to the packages."))
665 sub_create.add_argument("inputs", nargs="+", help=_("Path to input packages."))
666 sub_create.add_argument("action", action="store_const", const="repo_create")
667
668 def parse_command_info(self):
669 sub_info = self.sub_commands.add_parser("info",
670 help=_("Dump some information about this machine."))
671 sub_info.add_argument("action", action="store_const", const="info")
672
673 def handle_keepalive(self):
674 self.server.update_info()
675
676 def handle_build(self):
677 # Arch.
678 if self.args.arch:
679 arches = self.args.arch.split()
680
681 (package,) = self.args.package
682
683 self.server.create_scratch_build({})
684 return
685
686 # Temporary folter for source package.
687 tmpdir = "/tmp/pakfire-%s" % util.random_string()
688
689 try:
690 os.makedirs(tmpdir)
691
692 pakfire.dist(package, resultdir=[tmpdir,])
693
694 for file in os.listdir(tmpdir):
695 file = os.path.join(tmpdir, file)
696
697 print file
698
699 finally:
700 if os.path.exists(tmpdir):
701 util.rm(tmpdir)
702
703 def handle_repoupdate(self):
704 self.server.update_repositories()
705
706 def handle_repo_create(self):
707 path = self.args.path[0]
708
709 pakfire.repo_create(path, self.args.inputs, **self.pakfire_args)
710
711 def handle_info(self):
712 info = self.server.info()
713
714 print "\n".join(info)
715
716
717 class CliBuilderIntern(Cli):
718 def __init__(self):
719 self.parser = argparse.ArgumentParser(
720 description = _("Pakfire builder command line interface."),
721 )
722
723 self.parse_common_arguments()
724
725 # Add sub-commands.
726 self.sub_commands = self.parser.add_subparsers()
727
728 self.parse_command_build()
729
730 # Finally parse all arguments from the command line and save them.
731 self.args = self.parser.parse_args()
732
733 self.action2func = {
734 "build" : self.handle_build,
735 }
736
737 def parse_command_build(self):
738 # Implement the "build" command.
739 sub_build = self.sub_commands.add_parser("build",
740 help=_("Build one or more packages."))
741 sub_build.add_argument("package", nargs=1,
742 help=_("Give name of at least one package to build."))
743 sub_build.add_argument("action", action="store_const", const="build")
744
745 sub_build.add_argument("-a", "--arch",
746 help=_("Build the package for the given architecture."))
747 sub_build.add_argument("--resultdir", nargs="?",
748 help=_("Path were the output files should be copied to."))
749 sub_build.add_argument("-m", "--mode", nargs="?", default="development",
750 help=_("Mode to run in. Is either 'release' or 'development' (default)."))
751 sub_build.add_argument("--nodeps", action="store_true",
752 help=_("Do not verify build dependencies."))
753
754 def handle_build(self):
755 # Get the package descriptor from the command line options
756 pkg = self.args.package[0]
757
758 # Check, if we got a regular file
759 if os.path.exists(pkg):
760 pkg = os.path.abspath(pkg)
761 else:
762 raise FileNotFoundError, pkg
763
764 pakfire._build(pkg, builder_mode=self.args.mode,
765 arch=self.args.arch, resultdir=self.args.resultdir,)
766
767
768 class CliClient(Cli):
769 def __init__(self):
770 self.parser = argparse.ArgumentParser(
771 description = _("Pakfire client command line interface."),
772 )
773
774 self.parse_common_arguments(repo_manage_switches=True, offline_switch=True)
775
776 # Add sub-commands.
777 self.sub_commands = self.parser.add_subparsers()
778
779 self.parse_command_build()
780 self.parse_command_connection_check()
781 self.parse_command_info()
782
783 # Finally parse all arguments from the command line and save them.
784 self.args = self.parser.parse_args()
785
786 self.action2func = {
787 "build" : self.handle_build,
788 "conn-check" : self.handle_connection_check,
789 "info" : self.handle_info,
790 }
791
792 # Read configuration for the pakfire client.
793 self.conf = conf = config.ConfigClient()
794
795 # Create connection to pakfire hub.
796 self.client = client.PakfireUserClient(
797 conf.get("client", "server"),
798 conf.get("client", "username"),
799 conf.get("client", "password"),
800 )
801
802 def parse_command_build(self):
803 # Parse "build" command.
804 sub_build = self.sub_commands.add_parser("build",
805 help=_("Build a package remotely."))
806 sub_build.add_argument("package", nargs=1,
807 help=_("Give name of a package to build."))
808 sub_build.add_argument("action", action="store_const", const="build")
809
810 sub_build.add_argument("-a", "--arch",
811 help=_("Build the package for the given architecture."))
812
813 def parse_command_info(self):
814 # Implement the "info" command.
815 sub_info = self.sub_commands.add_parser("info",
816 help=_("Print some information about this host."))
817 sub_info.add_argument("action", action="store_const", const="info")
818
819 def parse_command_connection_check(self):
820 # Implement the "conn-check" command.
821 sub_conn_check = self.sub_commands.add_parser("conn-check",
822 help=_("Check the connection to the hub."))
823 sub_conn_check.add_argument("action", action="store_const", const="conn-check")
824
825 def handle_build(self):
826 (package,) = self.args.package
827
828 # XXX just for now, we do only upload source pfm files.
829 assert os.path.exists(package)
830
831 # Create a temporary directory.
832 temp_dir = tempfile.mkdtemp()
833
834 try:
835 if package.endswith(".%s" % MAKEFILE_EXTENSION):
836 pakfire_args = { "mode" : "server" }
837
838 # Create a source package from the makefile.
839 package = pakfire.dist(package, temp_dir, **pakfire_args)
840
841 elif package.endswith(".%s" % PACKAGE_EXTENSION):
842 pass
843
844 else:
845 raise Exception, "Unknown filetype: %s" % package
846
847 # Format arches.
848 if self.args.arch:
849 arches = self.args.arch.replace(",", " ")
850 else:
851 arches = None
852
853 # Create a new build on the server.
854 build = self.client.build_create(package, arches=arches)
855
856 # XXX Print the resulting build.
857 print build
858
859 finally:
860 # Cleanup the temporary directory and all files.
861 if os.path.exists(temp_dir):
862 shutil.rmtree(temp_dir, ignore_errors=True)
863
864 def handle_info(self):
865 ret = []
866
867 ret.append("")
868 ret.append(" PAKFIRE %s" % PAKFIRE_VERSION)
869 ret.append("")
870 ret.append(" %-20s: %s" % (_("Hostname"), system.hostname))
871 ret.append(" %-20s: %s" % (_("Pakfire hub"), self.conf.get("client", "server")))
872 if self.conf.get("client", "username") and self.conf.get("client", "password"):
873 ret.append(" %-20s: %s" % \
874 (_("Username"), self.conf.get("client", "username")))
875 ret.append("")
876
877 # Hardware information
878 ret.append(" %s:" % _("Hardware information"))
879 ret.append(" %-16s: %s" % (_("CPU model"), system.cpu_model))
880 ret.append(" %-16s: %s" % (_("Memory"), util.format_size(system.memory)))
881 ret.append("")
882 ret.append(" %-16s: %s" % (_("Native arch"), system.native_arch))
883 if not system.arch == system.native_arch:
884 ret.append(" %-16s: %s" % (_("Default arch"), system.arch))
885
886 header = _("Supported arches")
887 for arch in system.supported_arches:
888 ret.append(" %-16s: %s" % (header, arch))
889 header = ""
890 ret.append("")
891
892 for line in ret:
893 print line
894
895 def handle_connection_check(self):
896 ret = []
897
898 address = self.client.get_my_address()
899 ret.append(" %-20s: %s" % (_("Your IP address"), address))
900 ret.append("")
901
902 authenticated = self.client.check_auth()
903 if authenticated:
904 ret.append(" %s" % _("You are authenticated to the build service:"))
905
906 user = self.client.get_user_profile()
907 assert user, "Could not fetch user infomation"
908
909 keys = [
910 ("name", _("User name")),
911 ("realname", _("Real name")),
912 ("email", _("Email address")),
913 ("registered", _("Registered")),
914 ]
915
916 for key, desc in keys:
917 ret.append(" %-18s: %s" % (desc, user.get(key)))
918
919 else:
920 ret.append(_("You could not be authenticated to the build service."))
921
922 for line in ret:
923 print line
924
925
926 class CliDaemon(Cli):
927 def __init__(self):
928 self.parser = argparse.ArgumentParser(
929 description = _("Pakfire daemon command line interface."),
930 )
931
932 self.parse_common_arguments(repo_manage_switches=True, offline_switch=True)
933
934 # Finally parse all arguments from the command line and save them.
935 self.args = self.parser.parse_args()
936
937 def run(self):
938 """
939 Runs the pakfire daemon with provided settings.
940 """
941 # Read the configuration file for the daemon.
942 conf = config.ConfigDaemon()
943
944 # Create daemon instance.
945 d = pakfire.client.PakfireDaemon(
946 server = conf.get("daemon", "server"),
947 hostname = conf.get("daemon", "hostname"),
948 secret = conf.get("daemon", "secret"),
949 )
950
951 try:
952 d.run()
953
954 # We cannot just kill the daemon, it needs a smooth shutdown.
955 except (SystemExit, KeyboardInterrupt):
956 d.shutdown()