Merge branch 'master' of https://github.com/safaariman/pisi
This commit is contained in:
@@ -0,0 +1,59 @@
|
|||||||
|
# -*- coding:utf-8 -*-
|
||||||
|
#
|
||||||
|
# Copyright (C) 2014, marcin.bojara (at) gmail.com
|
||||||
|
#
|
||||||
|
# This program is free software; you can redistribute it and/or modify it under
|
||||||
|
# the terms of the GNU General Public License as published by the Free
|
||||||
|
# Software Foundation; either version 2 of the License, or (at your option)
|
||||||
|
# any later version.
|
||||||
|
#
|
||||||
|
# Please read the COPYING file.
|
||||||
|
#
|
||||||
|
|
||||||
|
import gettext
|
||||||
|
import optparse
|
||||||
|
|
||||||
|
import pisi.cli.command as command
|
||||||
|
import pisi.context as ctx
|
||||||
|
import pisi.db
|
||||||
|
import pisi.util as util
|
||||||
|
|
||||||
|
__trans = gettext.translation('pisi', fallback=True)
|
||||||
|
_ = __trans.gettext
|
||||||
|
|
||||||
|
|
||||||
|
class ListOrphaned(command.Command, metaclass=command.autocommand):
|
||||||
|
__doc__ = _("""List orphaned packages
|
||||||
|
|
||||||
|
Usage: list-orphaned
|
||||||
|
|
||||||
|
Lists packages installed as dependency, but no longer needed by any other installed package.
|
||||||
|
""")
|
||||||
|
|
||||||
|
def __init__(self, args):
|
||||||
|
super(ListOrphaned, self).__init__(args)
|
||||||
|
self.installdb = pisi.db.installdb.InstallDB()
|
||||||
|
|
||||||
|
name = ("list-orphaned", "lo")
|
||||||
|
|
||||||
|
def options(self):
|
||||||
|
|
||||||
|
group = optparse.OptionGroup(self.parser, _("list-orphaned options"))
|
||||||
|
group.add_option("-a", "--all", action="store_true",
|
||||||
|
default=False, help=_("Show all packages without reverse dependencies"))
|
||||||
|
group.add_option("-x", "--exclude", action="append",
|
||||||
|
default=None, help=_("Ignore packages and components whose basenames match pattern."))
|
||||||
|
self.parser.add_option_group(group)
|
||||||
|
|
||||||
|
def run(self):
|
||||||
|
|
||||||
|
self.init(database = True, write = False)
|
||||||
|
orphaned = self.installdb.get_no_rev_deps() if self.options.all else self.installdb.get_orphaned()
|
||||||
|
|
||||||
|
if self.options.exclude:
|
||||||
|
orphaned = pisi.blacklist.exclude(orphaned, ctx.get_option('exclude'))
|
||||||
|
|
||||||
|
if orphaned:
|
||||||
|
ctx.ui.info(_("Orphaned packages:"))
|
||||||
|
ctx.ui.info(util.format_by_columns(sorted(orphaned)))
|
||||||
|
else: ctx.ui.info(_("No orphaned packages"))
|
||||||
+20
-15
@@ -10,55 +10,59 @@
|
|||||||
# Please read the COPYING file.
|
# Please read the COPYING file.
|
||||||
#
|
#
|
||||||
|
|
||||||
import sys
|
|
||||||
import optparse
|
|
||||||
|
|
||||||
import gettext
|
import gettext
|
||||||
__trans = gettext.translation('pisi', fallback=True)
|
import optparse
|
||||||
_ = __trans.gettext
|
import sys
|
||||||
|
|
||||||
import pisi
|
import pisi
|
||||||
import pisi.cli
|
import pisi.cli
|
||||||
import pisi.cli.command as command
|
|
||||||
import pisi.cli.addrepo
|
import pisi.cli.addrepo
|
||||||
import pisi.cli.blame
|
import pisi.cli.blame
|
||||||
import pisi.cli.build
|
import pisi.cli.build
|
||||||
import pisi.cli.check
|
import pisi.cli.check
|
||||||
import pisi.cli.clean
|
import pisi.cli.clean
|
||||||
|
import pisi.cli.command as command
|
||||||
import pisi.cli.configurepending
|
import pisi.cli.configurepending
|
||||||
import pisi.cli.deletecache
|
import pisi.cli.deletecache
|
||||||
import pisi.cli.delta
|
import pisi.cli.delta
|
||||||
|
import pisi.cli.disablerepo
|
||||||
import pisi.cli.emerge
|
import pisi.cli.emerge
|
||||||
|
import pisi.cli.enablerepo
|
||||||
import pisi.cli.fetch
|
import pisi.cli.fetch
|
||||||
import pisi.cli.graph
|
import pisi.cli.graph
|
||||||
|
import pisi.cli.history
|
||||||
import pisi.cli.index
|
import pisi.cli.index
|
||||||
import pisi.cli.info
|
import pisi.cli.info
|
||||||
import pisi.cli.install
|
import pisi.cli.install
|
||||||
import pisi.cli.history
|
|
||||||
import pisi.cli.listnewest
|
|
||||||
import pisi.cli.listavailable
|
import pisi.cli.listavailable
|
||||||
import pisi.cli.listcomponents
|
import pisi.cli.listcomponents
|
||||||
import pisi.cli.listinstalled
|
import pisi.cli.listinstalled
|
||||||
|
import pisi.cli.listnewest
|
||||||
|
import pisi.cli.listorphaned
|
||||||
import pisi.cli.listpending
|
import pisi.cli.listpending
|
||||||
import pisi.cli.listrepo
|
import pisi.cli.listrepo
|
||||||
import pisi.cli.listsources
|
import pisi.cli.listsources
|
||||||
import pisi.cli.listupgrades
|
import pisi.cli.listupgrades
|
||||||
import pisi.cli.rebuilddb
|
import pisi.cli.rebuilddb
|
||||||
import pisi.cli.remove
|
import pisi.cli.remove
|
||||||
|
import pisi.cli.removeorphaned
|
||||||
import pisi.cli.removerepo
|
import pisi.cli.removerepo
|
||||||
import pisi.cli.enablerepo
|
|
||||||
import pisi.cli.disablerepo
|
|
||||||
import pisi.cli.searchfile
|
|
||||||
import pisi.cli.search
|
import pisi.cli.search
|
||||||
|
import pisi.cli.searchfile
|
||||||
import pisi.cli.updaterepo
|
import pisi.cli.updaterepo
|
||||||
import pisi.cli.upgrade
|
import pisi.cli.upgrade
|
||||||
|
|
||||||
#FIXME: why does this has to be imported last
|
# FIXME: why does this has to be imported last
|
||||||
import pisi.cli.help
|
import pisi.cli.help
|
||||||
|
|
||||||
|
__trans = gettext.translation('pisi', fallback=True)
|
||||||
|
_ = __trans.gettext
|
||||||
|
|
||||||
|
|
||||||
class ParserError(pisi.Exception):
|
class ParserError(pisi.Exception):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
class PreParser(optparse.OptionParser):
|
class PreParser(optparse.OptionParser):
|
||||||
"""consumes any options, and finds arguments from command line"""
|
"""consumes any options, and finds arguments from command line"""
|
||||||
|
|
||||||
@@ -68,11 +72,11 @@ class PreParser(optparse.OptionParser):
|
|||||||
def error(self, msg):
|
def error(self, msg):
|
||||||
raise ParserError(msg)
|
raise ParserError(msg)
|
||||||
|
|
||||||
def parse_args(self, args=None):
|
def parse_args(self, args=None, values=None):
|
||||||
self.opts = []
|
self.opts = []
|
||||||
self.rargs = self._get_args(args)
|
self.rargs = self._get_args(args)
|
||||||
self._process_args()
|
self._process_args()
|
||||||
return (self.opts, self.args)
|
return self.opts, self.args
|
||||||
|
|
||||||
def _process_args(self):
|
def _process_args(self):
|
||||||
args = []
|
args = []
|
||||||
@@ -81,6 +85,7 @@ class PreParser(optparse.OptionParser):
|
|||||||
first_arg = False
|
first_arg = False
|
||||||
while rargs:
|
while rargs:
|
||||||
arg = rargs[0]
|
arg = rargs[0]
|
||||||
|
|
||||||
def option():
|
def option():
|
||||||
if not self.allow_interspersed_args and first_arg:
|
if not self.allow_interspersed_args and first_arg:
|
||||||
self.error(_('Options must precede non-option arguments'))
|
self.error(_('Options must precede non-option arguments'))
|
||||||
@@ -118,7 +123,7 @@ class PisiCLI(object):
|
|||||||
self.parser = PreParser(version="%prog " + pisi.__version__)
|
self.parser = PreParser(version="%prog " + pisi.__version__)
|
||||||
try:
|
try:
|
||||||
opts, args = self.parser.parse_args(args=orig_args)
|
opts, args = self.parser.parse_args(args=orig_args)
|
||||||
if len(args)==0: # more explicit than using IndexError
|
if len(args) == 0: # more explicit than using IndexError
|
||||||
if 'version' in opts:
|
if 'version' in opts:
|
||||||
self.parser.print_version()
|
self.parser.print_version()
|
||||||
sys.exit(0)
|
sys.exit(0)
|
||||||
|
|||||||
@@ -0,0 +1,55 @@
|
|||||||
|
# -*- coding:utf-8 -*-
|
||||||
|
#
|
||||||
|
# Copyright (C) 2014, marcin.bojara (at) gmail.com
|
||||||
|
#
|
||||||
|
# This program is free software; you can redistribute it and/or modify it under
|
||||||
|
# the terms of the GNU General Public License as published by the Free
|
||||||
|
# Software Foundation; either version 2 of the License, or (at your option)
|
||||||
|
# any later version.
|
||||||
|
#
|
||||||
|
# Please read the COPYING file.
|
||||||
|
#
|
||||||
|
|
||||||
|
import gettext
|
||||||
|
import optparse
|
||||||
|
|
||||||
|
import pisi.api
|
||||||
|
import pisi.cli.command as command
|
||||||
|
import pisi.context as ctx
|
||||||
|
import pisi.db
|
||||||
|
|
||||||
|
__trans = gettext.translation('pisi', fallback=True)
|
||||||
|
_ = __trans.gettext
|
||||||
|
|
||||||
|
|
||||||
|
class RemoveOrphaned(command.PackageOp, metaclass=command.autocommand):
|
||||||
|
__doc__ = _("""Remove orphaned packages
|
||||||
|
|
||||||
|
Usage: remove-orphaned
|
||||||
|
|
||||||
|
Remove all orphaned packages from the system.
|
||||||
|
""")
|
||||||
|
|
||||||
|
def __init__(self,args):
|
||||||
|
super(RemoveOrphaned, self).__init__(args)
|
||||||
|
self.installdb = pisi.db.installdb.InstallDB()
|
||||||
|
|
||||||
|
name = ("remove-orphaned", "ro")
|
||||||
|
|
||||||
|
def options(self):
|
||||||
|
group = optparse.OptionGroup(self.parser, _("remove-orphaned options"))
|
||||||
|
|
||||||
|
super(RemoveOrphaned, self).options(group)
|
||||||
|
group.add_option("-x", "--exclude", action="append",
|
||||||
|
default=None, help=_("When removing orphaned, ignore packages and components whose basenames match pattern."))
|
||||||
|
|
||||||
|
self.parser.add_option_group(group)
|
||||||
|
|
||||||
|
def run(self):
|
||||||
|
|
||||||
|
self.init(database = True, write = False)
|
||||||
|
orphaned = self.installdb.get_orphaned()
|
||||||
|
if ctx.get_option('exclude'):
|
||||||
|
orphaned = pisi.blacklist.exclude(orphaned, ctx.get_option('exclude'))
|
||||||
|
|
||||||
|
pisi.api.remove(orphaned)
|
||||||
+3
-2
@@ -36,8 +36,9 @@ def is_char_valid(char):
|
|||||||
|
|
||||||
def is_method_missing(exception):
|
def is_method_missing(exception):
|
||||||
"""Tells if exception is about missing method in COMAR script"""
|
"""Tells if exception is about missing method in COMAR script"""
|
||||||
if exception._dbus_error_name in ("tr.org.pardus.comar.python.missing",
|
if exception.get_dbus_name() in ("tr.org.pardus.comar.python.missing", "tr.org.pardus.comar.Missing"):
|
||||||
"tr.org.pardus.comar.Missing"):
|
return True
|
||||||
|
if exception.__context__.get_dbus_name() in ("tr.org.pardus.comar.python.missing", "tr.org.pardus.comar.Missing"):
|
||||||
return True
|
return True
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|||||||
@@ -95,6 +95,7 @@ class Constants(metaclass=Singleton):
|
|||||||
self.__c.needs_reboot = "needsreboot"
|
self.__c.needs_reboot = "needsreboot"
|
||||||
self.__c.files_db = "files.db"
|
self.__c.files_db = "files.db"
|
||||||
self.__c.repos = "repos"
|
self.__c.repos = "repos"
|
||||||
|
self.__c.installed_extra = "installedextra"
|
||||||
|
|
||||||
#file/directory permissions
|
#file/directory permissions
|
||||||
self.__c.umask = 0o022
|
self.__c.umask = 0o022
|
||||||
|
|||||||
@@ -67,6 +67,15 @@ class InstallDB(lazydb.LazyDB):
|
|||||||
def init(self):
|
def init(self):
|
||||||
self.installed_db = self.__generate_installed_pkgs()
|
self.installed_db = self.__generate_installed_pkgs()
|
||||||
self.rev_deps_db = self.__generate_revdeps()
|
self.rev_deps_db = self.__generate_revdeps()
|
||||||
|
self.installed_extra = self.__generate_installed_extra()
|
||||||
|
|
||||||
|
def __generate_installed_extra(self):
|
||||||
|
ie = []
|
||||||
|
ie_path = os.path.join(ctx.config.info_dir(), ctx.const.installed_extra)
|
||||||
|
if os.path.isfile(ie_path):
|
||||||
|
with open(ie_path) as ie_file:
|
||||||
|
ie.extend(ie_file.read().strip().split("\n"))
|
||||||
|
return ie
|
||||||
|
|
||||||
def __generate_installed_pkgs(self):
|
def __generate_installed_pkgs(self):
|
||||||
def split_name(dirname):
|
def split_name(dirname):
|
||||||
@@ -249,6 +258,19 @@ class InstallDB(lazydb.LazyDB):
|
|||||||
|
|
||||||
return rev_deps
|
return rev_deps
|
||||||
|
|
||||||
|
def get_orphaned(self):
|
||||||
|
"""
|
||||||
|
get list of packages installed as extra dependency,
|
||||||
|
but without reverse dependencies now.
|
||||||
|
"""
|
||||||
|
return [x for x in self.installed_extra if not self.get_rev_deps(x)]
|
||||||
|
|
||||||
|
def get_no_rev_deps(self):
|
||||||
|
"""
|
||||||
|
get installed packages list which haven't reverse dependencies.
|
||||||
|
"""
|
||||||
|
return [x for x in self.installed_db if not self.get_rev_deps(x)]
|
||||||
|
|
||||||
def pkg_dir(self, pkg, version, release):
|
def pkg_dir(self, pkg, version, release):
|
||||||
return pisi.util.join_path(ctx.config.packages_dir(), pkg + '-' + version + '-' + release)
|
return pisi.util.join_path(ctx.config.packages_dir(), pkg + '-' + version + '-' + release)
|
||||||
|
|
||||||
|
|||||||
+3
-1
@@ -20,10 +20,12 @@ import string
|
|||||||
# lower borks for international locales. What we want is ascii lower.
|
# lower borks for international locales. What we want is ascii lower.
|
||||||
lower_map = str.maketrans(string.ascii_uppercase, string.ascii_lowercase)
|
lower_map = str.maketrans(string.ascii_uppercase, string.ascii_lowercase)
|
||||||
|
|
||||||
|
|
||||||
class Singleton(object):
|
class Singleton(object):
|
||||||
_the_instances = {}
|
_the_instances = {}
|
||||||
|
|
||||||
def __new__(type):
|
def __new__(type):
|
||||||
if not type.__name__ in Singleton._the_instances:
|
if type.__name__ not in Singleton._the_instances:
|
||||||
Singleton._the_instances[type.__name__] = object.__new__(type)
|
Singleton._the_instances[type.__name__] = object.__new__(type)
|
||||||
return Singleton._the_instances[type.__name__]
|
return Singleton._the_instances[type.__name__]
|
||||||
|
|
||||||
|
|||||||
@@ -27,7 +27,8 @@ import pisi.pgraph as pgraph
|
|||||||
import pisi.ui as ui
|
import pisi.ui as ui
|
||||||
import pisi.db
|
import pisi.db
|
||||||
|
|
||||||
def install_pkg_names(A, reinstall = False):
|
|
||||||
|
def install_pkg_names(A, reinstall=False, extra=False):
|
||||||
"""This is the real thing. It installs packages from
|
"""This is the real thing. It installs packages from
|
||||||
the repository, trying to perform a minimum number of
|
the repository, trying to perform a minimum number of
|
||||||
installs"""
|
installs"""
|
||||||
@@ -78,7 +79,8 @@ def install_pkg_names(A, reinstall = False):
|
|||||||
if ctx.get_option('dry_run'):
|
if ctx.get_option('dry_run'):
|
||||||
return True
|
return True
|
||||||
|
|
||||||
if set(order) - A_0:
|
extra_packages = set(order) - A_0
|
||||||
|
if extra_packages:
|
||||||
if not ctx.ui.confirm(_('There are extra packages due to dependencies. Do you want to continue?')):
|
if not ctx.ui.confirm(_('There are extra packages due to dependencies. Do you want to continue?')):
|
||||||
return False
|
return False
|
||||||
|
|
||||||
@@ -91,10 +93,18 @@ def install_pkg_names(A, reinstall = False):
|
|||||||
conflicts = operations.helper.check_conflicts(order, packagedb)
|
conflicts = operations.helper.check_conflicts(order, packagedb)
|
||||||
|
|
||||||
paths = []
|
paths = []
|
||||||
|
extra_paths = {}
|
||||||
for x in order:
|
for x in order:
|
||||||
ctx.ui.info(util.colorize(_("Downloading %d / %d") % (order.index(x)+1, len(order)), "yellow"))
|
ctx.ui.info(util.colorize(_("Downloading %d / %d") % (order.index(x)+1, len(order)), "yellow"))
|
||||||
install_op = atomicoperations.Install.from_name(x)
|
install_op = atomicoperations.Install.from_name(x)
|
||||||
paths.append(install_op.package_fname)
|
paths.append(install_op.package_fname)
|
||||||
|
if x in extra_packages or (extra and x in A):
|
||||||
|
extra_paths[install_op.package_fname] = x
|
||||||
|
elif reinstall and x in installdb.installed_extra:
|
||||||
|
installdb.installed_extra.remove(x)
|
||||||
|
with open(os.path.join(ctx.config.info_dir(), ctx.const.installed_extra), "w") as ie_file:
|
||||||
|
ie_file.write("\n".join(installdb.installed_extra) + ("\n" if installdb.installed_extra else ""))
|
||||||
|
|
||||||
|
|
||||||
# fetch to be installed packages but do not install them.
|
# fetch to be installed packages but do not install them.
|
||||||
if ctx.get_option('fetch_only'):
|
if ctx.get_option('fetch_only'):
|
||||||
@@ -107,6 +117,12 @@ def install_pkg_names(A, reinstall = False):
|
|||||||
ctx.ui.info(util.colorize(_("Installing %d / %d") % (paths.index(path)+1, len(paths)), "yellow"))
|
ctx.ui.info(util.colorize(_("Installing %d / %d") % (paths.index(path)+1, len(paths)), "yellow"))
|
||||||
install_op = atomicoperations.Install(path)
|
install_op = atomicoperations.Install(path)
|
||||||
install_op.install(False)
|
install_op.install(False)
|
||||||
|
try:
|
||||||
|
with open(os.path.join(ctx.config.info_dir(), ctx.const.installed_extra), "a") as ie_file:
|
||||||
|
ie_file.write("%s\n" % extra_paths[path])
|
||||||
|
installdb.installed_extra.append(extra_paths[path])
|
||||||
|
except KeyError:
|
||||||
|
pass
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
@@ -199,7 +215,7 @@ def install_pkg_files(package_URIs, reinstall = False):
|
|||||||
ctx.ui.info(util.format_by_columns(sorted(extra_packages)))
|
ctx.ui.info(util.format_by_columns(sorted(extra_packages)))
|
||||||
if not ctx.ui.confirm(_('Do you want to continue?')):
|
if not ctx.ui.confirm(_('Do you want to continue?')):
|
||||||
raise pisi.Error(_('External dependencies not satisfied'))
|
raise pisi.Error(_('External dependencies not satisfied'))
|
||||||
install_pkg_names(extra_packages, reinstall=True)
|
install_pkg_names(extra_packages, reinstall=True, extra=True)
|
||||||
|
|
||||||
class PackageDB:
|
class PackageDB:
|
||||||
def get_package(self, key, repo = None):
|
def get_package(self, key, repo = None):
|
||||||
|
|||||||
@@ -10,19 +10,20 @@
|
|||||||
# Please read the COPYING file.
|
# Please read the COPYING file.
|
||||||
#
|
#
|
||||||
|
|
||||||
|
import gettext
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
import gettext
|
import pisi
|
||||||
|
import pisi.atomicoperations as atomicoperations
|
||||||
|
import pisi.context as ctx
|
||||||
|
import pisi.db
|
||||||
|
import pisi.pgraph as pgraph
|
||||||
|
import pisi.ui as ui
|
||||||
|
import pisi.util as util
|
||||||
|
|
||||||
__trans = gettext.translation('pisi', fallback=True)
|
__trans = gettext.translation('pisi', fallback=True)
|
||||||
_ = __trans.gettext
|
_ = __trans.gettext
|
||||||
|
|
||||||
import pisi
|
|
||||||
import pisi.context as ctx
|
|
||||||
import pisi.atomicoperations as atomicoperations
|
|
||||||
import pisi.pgraph as pgraph
|
|
||||||
import pisi.util as util
|
|
||||||
import pisi.ui as ui
|
|
||||||
import pisi.db
|
|
||||||
|
|
||||||
def remove(A, ignore_dep = False, ignore_safety = False):
|
def remove(A, ignore_dep = False, ignore_safety = False):
|
||||||
"""remove set A of packages from system (A is a list of package names)"""
|
"""remove set A of packages from system (A is a list of package names)"""
|
||||||
@@ -81,6 +82,10 @@ in the respective order to satisfy dependencies:
|
|||||||
for x in order:
|
for x in order:
|
||||||
if installdb.has_package(x):
|
if installdb.has_package(x):
|
||||||
atomicoperations.remove_single(x)
|
atomicoperations.remove_single(x)
|
||||||
|
if x in installdb.installed_extra:
|
||||||
|
installdb.installed_extra.remove(x)
|
||||||
|
with open(os.path.join(ctx.config.info_dir(), ctx.const.installed_extra), "w") as ie_file:
|
||||||
|
ie_file.write("\n".join(installdb.installed_extra) + ("\n" if installdb.installed_extra else ""))
|
||||||
else:
|
else:
|
||||||
ctx.ui.info(_('Package %s is not installed. Cannot remove.') % x)
|
ctx.ui.info(_('Package %s is not installed. Cannot remove.') % x)
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user