aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'g_octave/cli.py')
-rw-r--r--g_octave/cli.py406
1 files changed, 406 insertions, 0 deletions
diff --git a/g_octave/cli.py b/g_octave/cli.py
new file mode 100644
index 0000000..0e18a09
--- /dev/null
+++ b/g_octave/cli.py
@@ -0,0 +1,406 @@
+# -*- coding: utf-8 -*-
+
+"""
+ g_octave.cli
+ ~~~~~~~~~~~~
+
+ This module implements a command-line interface for g-octave.
+
+ :copyright: (c) 2010 by Rafael Goncalves Martins
+ :license: GPL-2, see LICENSE for more details.
+"""
+
+from __future__ import absolute_import, print_function
+
+import argparse
+import getpass
+import os
+import portage
+import tempfile
+import traceback
+import shutil
+import sys
+
+from .checksum import sha1_check_db
+from .config import Config
+from .description_tree import DescriptionTree
+from .ebuild import Ebuild
+from .exception import GOctaveError
+from .fetch import fetch
+from .log import Log
+from .overlay import create_overlay
+from .package_manager import get_by_name
+
+config = Config()
+log = Log('g_octave.cli')
+out = portage.output.EOutput()
+
+
+class Cli:
+
+ bug_tracker = 'https://bugs.gentoo.org/'
+
+ def __init__(self):
+ log.info('Initializing g-octave.')
+
+ self.parser = argparse.ArgumentParser(
+ description='A tool that generates and installs ebuilds for the octave-forge packages'
+ )
+
+ self.parser.set_defaults(
+ action=self.merge,
+ scm=(config.use_scm.lower() == 'true')
+ )
+
+ self.actions = self.parser.add_mutually_exclusive_group()
+ self.scm = self.parser.add_mutually_exclusive_group()
+
+ self.actions.add_argument(
+ '--sync',
+ action = 'store_const',
+ const = self.sync,
+ dest = 'action',
+ help = 'search for updates of the package database, patches and auxiliary files.'
+ )
+
+ self.actions.add_argument(
+ '-l', '--list',
+ action = 'store_const',
+ const = self.list,
+ dest = 'action',
+ help = 'show a list of packages available to install (separed by categories) and exit.'
+ )
+
+ self.actions.add_argument(
+ '--list-raw',
+ action = 'store_const',
+ const = self.list_raw,
+ dest = 'action',
+ help = 'show a list of packages available to install (a package per line, without colors) and exit.'
+ )
+
+ self.actions.add_argument(
+ '-i', '--info',
+ action = 'store_const',
+ const = self.info,
+ dest = 'action',
+ help = 'show a description of the required package and exit.'
+ )
+
+ self.actions.add_argument(
+ '-u', '--update',
+ action = 'store_const',
+ const = self.update,
+ dest = 'action',
+ help = 'try to update a package or all the installed packages, if no atom provided.'
+ )
+
+ self.actions.add_argument(
+ '-s', '--search',
+ action = 'store_const',
+ const = self.search,
+ dest = 'action',
+ help = 'package search (regular expressions allowed).'
+ )
+
+ self.actions.add_argument(
+ '-C', '--unmerge',
+ action = 'store_const',
+ const = self.unmerge,
+ dest = 'action',
+ help = 'try to unmerge a package, instead of merge.'
+ )
+
+ self.actions.add_argument(
+ '--config',
+ action = 'store_const',
+ const = self.config,
+ dest = 'action',
+ help = 'return a value from the configuration file (/etc/g-octave.cfg)'
+ )
+
+ self.parser.add_argument(
+ '-p', '--pretend',
+ action = 'store_true',
+ dest = 'pretend',
+ help = 'don\'t (un)merge packages, only create ebuilds and solve the dependencies'
+ )
+
+ self.parser.add_argument(
+ '-a', '--ask',
+ action = 'store_true',
+ dest = 'ask',
+ help = 'ask for confirmation before perform (un)merges'
+ )
+
+ self.parser.add_argument(
+ '-v', '--verbose',
+ action = 'store_true',
+ dest = 'verbose',
+ help = 'package manager\'s makes a lot of noise.'
+ )
+
+ self.parser.add_argument(
+ '-1', '--oneshot',
+ action = 'store_true',
+ dest = 'oneshot',
+ help = 'do not add the packages to the world file for later updating.'
+ )
+
+ self.scm.add_argument(
+ '--scm',
+ action = 'store_true',
+ dest = 'scm',
+ help = 'enable the installation of the current live version of a package, if disabled on the configuration file'
+ )
+
+ self.scm.add_argument(
+ '--no-scm',
+ action = 'store_false',
+ dest = 'scm',
+ help = 'disable the installation of the current live version of a package, if enabled on the configuration file'
+ )
+
+ self.parser.add_argument(
+ '--force',
+ action = 'store_true',
+ dest = 'force',
+ help = 'forces the recreation of the ebuilds'
+ )
+
+ self.parser.add_argument(
+ '--force-all',
+ action = 'store_true',
+ dest = 'force_all',
+ help = 'forces the recreation of the overlay and of the ebuilds'
+ )
+
+ self.parser.add_argument(
+ '--no-colors',
+ action = 'store_false',
+ dest = 'colors',
+ help = 'don\'t use colors on the CLI'
+ )
+
+ self.parser.add_argument(
+ 'atom',
+ metavar='ATOM',
+ type=str,
+ nargs='?',
+ help='Package atom or regular expression (for search) or configuration key'
+ )
+
+ def _init_tree(self):
+ log.info('Initializing DescriptionTree.')
+ self.tree = DescriptionTree()
+
+ def _required_atom(self):
+ if self.args.atom is None:
+ self.parser.error('You need to provide a positional argument')
+
+ def _init_pkg_manager(self):
+ log.info('Initializing Package Manager.')
+ pm = get_by_name(config.package_manager)
+ if pm is None:
+ raise GOctaveError('Invalid package manager: %s' % config.package_manager)
+ self.pkg_manager = pm(self.args.ask, self.args.verbose, self.args.pretend,
+ self.args.oneshot, not self.args.colors)
+
+ # checking if the package manager is installed
+ if not self.pkg_manager.is_installed():
+ raise GOctaveError('Package manager not installed: %s' % config.package_manager)
+
+ current_user = getpass.getuser()
+ if current_user not in self.pkg_manager.allowed_users():
+ raise GOctaveError(
+ 'The current user (%s) can\'t run the current selected '
+ 'package manager (%s)' % (current_user, config.package_manager)
+ )
+
+ # checking if the overlay is properly configured
+ self.pkg_manager.check_overlay(config.overlay, out):
+ raise GOctaveError('Overlay not properly configured.')
+
+ def _init_ebuild(self):
+ log.info('Initializing Ebuild: %s' % self.args.atom)
+ self._required_atom()
+ self._init_pkg_manager()
+ self._init_overlay()
+ self.ebuild = Ebuild(self.args.atom, self.args.force, self.args.scm, \
+ self.pkg_manager)
+ self.pkgatom = '=g-octave/' + self.ebuild.description.P
+ self.catpkg = 'g-octave/' + self.ebuild.description.PN
+
+ def _init_overlay(self):
+ log.info('Initializing Overlay.')
+ create_overlay(self.args.force_all)
+
+ def list(self):
+ log.info('Listing packages.')
+ self._init_tree()
+ print()
+ print(portage.output.blue('Available packages:'))
+ print()
+ packages = self.tree.list()
+ for category in packages:
+ print(
+ portage.output.blue('Category:'),
+ portage.output.white(category)
+ )
+ print()
+ for pkg in packages[category]:
+ print(
+ portage.output.green(' Package:'),
+ portage.output.white(pkg)
+ )
+ print(
+ portage.output.green(' Available versions:'),
+ portage.output.red(', '.join(packages[category][pkg]))
+ )
+ print()
+
+ def list_raw(self):
+ log.info('Listing packages (raw mode).')
+ self._init_tree()
+ packages = self.tree.list()
+ for cat in packages:
+ for pkg in packages[cat]:
+ print(pkg)
+
+ def info(self):
+ log.info('Listing description of a package.')
+ self._init_ebuild()
+ pkg = self.ebuild.description
+ print(portage.output.blue('Package:'), portage.output.white(str(pkg.name)))
+ print(portage.output.blue('Version:'), portage.output.white(str(pkg.version)))
+ print(portage.output.blue('Date:'), portage.output.white(str(pkg.date)))
+ print(portage.output.blue('Maintainer:'), portage.output.white(str(pkg.maintainer)))
+ print(portage.output.blue('Description:'), portage.output.white(str(pkg.description)))
+ print(portage.output.blue('Categories:'), portage.output.white(str(pkg.categories)))
+ print(portage.output.blue('License:'), portage.output.white(str(pkg.license)))
+ print(portage.output.blue('Url:'), portage.output.white(str(pkg.url)))
+
+ def update(self):
+ self._init_pkg_manager()
+ if self.args.atom is not None:
+ log.info('Calling the package manager to update the package.')
+ self._init_ebuild()
+ ret = self.pkg_manager.update_package(self.pkgatom, self.catpkg)
+ else:
+ log.info('Calling the package manager to update all the installed packages.')
+ ret = self.pkg_manager.update_package()
+ if ret != os.EX_OK:
+ raise GOctaveError('Update failed!')
+
+ def search(self):
+ self._init_tree()
+ self._init_overlay()
+ self._required_atom()
+ log.info('Searching for packages: %s' % self.args.atom)
+ print(
+ portage.output.blue('Search results for '),
+ portage.output.white(self.args.atom),
+ portage.output.blue(':\n'),
+ sep = ''
+ )
+ packages = self.tree.search(self.args.atom)
+ for pkg in packages:
+ print(
+ portage.output.green('Package:'),
+ portage.output.white(pkg)
+ )
+ print(
+ portage.output.green('Available versions:'),
+ portage.output.red(', '.join(packages[pkg]))
+ )
+ print()
+
+ def merge(self):
+ self._init_pkg_manager()
+ self._init_ebuild()
+ self._required_atom()
+ log.info('Merging package: %s' % self.args.atom)
+ self.ebuild.create()
+ ret = self.pkg_manager.install_package(self.pkgatom, self.catpkg)
+ if ret != os.EX_OK:
+ raise GOctaveError('Merge failed!')
+
+ def unmerge(self):
+ self._init_pkg_manager()
+ self._init_ebuild()
+ self._required_atom()
+ log.info('Unmerging package: %s' % self.args.atom)
+ self.ebuild.create()
+ ret = self.pkg_manager.uninstall_package(self.pkgatom, self.catpkg)
+ if ret != os.EX_OK:
+ raise GOctaveError('Unmerge failed!')
+
+ def sync(self):
+ log.info('Searching updates ...')
+ out.einfo('Searching updates ...')
+
+ if self.args.force and os.path.exists(config.db):
+ shutil.rmtree(config.db)
+
+ if not self.updates.fetch_db():
+ log.info('No updates available')
+ out.einfo('No updates available')
+ else:
+ self.updates.extract()
+ log.info('Checking SHA1 checksums ...')
+ out.ebegin('Checking SHA1 checksums')
+ self._init_tree()
+ if sha1_check_db(self.tree):
+ out.eend(0)
+ else:
+ out.eend(1)
+ if os.path.exists(config.db):
+ shutil.rmtree(config.db)
+ raise GOctaveError('Package database SHA1 checksum failed!')
+
+ def config(self):
+ log.info('Retrieving configuration option.')
+ self._required_atom()
+ print(config.__getattr__(self.args.atom))
+
+ def _run(self):
+ log.info('Running the command-line interface.')
+ self.args = self.parser.parse_args()
+ if not self.args.colors:
+ portage.output.nocolor()
+
+ self.updates = fetch()
+
+ # validating the db_mirror
+ if self.updates is None:
+ raise GOctaveError('Your db_mirror value is invalid. Fix it, or leave empty to use the default.')
+
+ # checking if we have a package database
+ if self.updates.need_update() and self.args.action != self.sync:
+ raise GOctaveError('No package database found! Please run `g-octave --sync`')
+
+ self.args.action()
+ return os.EX_OK
+
+ def run(self):
+ try:
+ return self._run()
+ except GOctaveError as err:
+ log.error(unicode(err))
+ out.eerror(unicode(err))
+ return os.EX_USAGE
+ except Exception as err:
+ tb = traceback.format_exc()
+ log.error(tb)
+ out.eerror('Unknown error - ' + unicode(err))
+ fd, filename = tempfile.mkstemp(prefix='g-octave-', suffix='.log')
+ error_log = 'Command: ' + ' '.join(sys.argv) + '\n\n' + tb
+ if os.write(fd, error_log) != len(error_log):
+ out.eerror('Failed to save the traceback!')
+ else:
+ out.eerror('Traceback saved to: ' + filename)
+ out.eerror('Please report a bug with traceback and `emerge --info` attached.')
+ out.eerror('Bug tracker: ' + self.bug_tracker)
+ os.fchmod(fd, 0o777)
+ os.close(fd)
+ return os.EX_SOFTWARE