def system(cmd, show=False, stage=None, sandbox=None): cfg = conf.LPMSConfig() if sandbox is None: sandbox = True if cfg.sandbox else False # override 'sandbox' variable if the user wants to modifiy from cli if lpms.getopt('--enable-sandbox'): sandbox = True elif lpms.getopt('--disable-sandbox'): sandbox = False if lpms.getopt("--verbose"): ret, output, err = run_cmd(cmd, True) elif (not cfg.print_output or lpms.getopt("--quiet")) \ and not show: ret, output, err = run_cmd(cmd, show=False, enable_sandbox=sandbox) else: ret, output, err = run_cmd(cmd, show=True, enable_sandbox=sandbox) if ret != 0: if not conf.LPMSConfig().print_output or lpms.getopt("--quiet"): out.brightred("\n>> error messages:\n") out.write(err) out.warn("command failed: %s" % out.color(cmd, "red")) if stage and output and err: return False, output + err return False return True
def system(cmd, show=False, stage=None, sandbox=None): cfg = conf.LPMSConfig() if sandbox is None: sandbox = True if cfg.sandbox else False # override 'sandbox' variable if the user wants to modifiy from cli if lpms.getopt("--enable-sandbox"): sandbox = True elif lpms.getopt("--disable-sandbox"): sandbox = False if lpms.getopt("--verbose"): ret, output, err = run_cmd(cmd, True) elif (not cfg.print_output or lpms.getopt("--quiet")) and not show: ret, output, err = run_cmd(cmd, show=False, enable_sandbox=sandbox) else: ret, output, err = run_cmd(cmd, show=True, enable_sandbox=sandbox) if ret != 0: if not conf.LPMSConfig().print_output or lpms.getopt("--quiet"): out.brightred("\n>> error messages:\n") out.write(err) out.warn("command failed: %s" % out.color(cmd, "red")) if stage and output and err: return False, output + err return False return True
def run_cmd(cmd, show=True, enable_sandbox=True): stdout = None stderr = None if enable_sandbox: # FIXME: getopt should not do this. # the verbosity of messages, defaults to 1 # 1 - error # 2 - warning # 3 - normal # 4 - verbose # 5 - debug # 6 - crazy debug log_level = lpms.getopt("--sandbox-log-level", like=True) if log_level is None: log_level = "1" if not log_level in ("1", "2", "3", "4", "5", "6"): out.warn("%s is an invalid sandbox log level." % log_level) cmd = "%s --config=%s --log-level=%s --log-file=%s -- %s" % ( cst.sandbox_app, cst.sandbox_config, log_level, cst.sandbox_log, cmd, ) if not show: stdout = subprocess.PIPE stderr = subprocess.PIPE result = subprocess.Popen(cmd, shell=True, stdout=stdout, stderr=stderr) output, err = result.communicate() return result.returncode, output, err
def run(self): if lpms.getopt("--help") or len(self.params) == 0: self.usage() for param in self.params: param = param.split("/") if len(param) == 3: myrepo, mycategory, myname = param packages = self.repodb.find_package( package_name=myname, package_repo=myrepo, package_category=mycategory ) elif len(param) == 2: mycategory, myname = param packages = self.repodb.find_package(package_name=myname, package_category=mycategory) elif len(param) == 1: packages = self.repodb.find_package(package_name=param[0]) else: out.error("%s seems invalid." % out.color("/".join(param), "brightred")) lpms.terminate() if not packages: out.error("%s not found!" % out.color("/".join(param), "brightred")) lpms.terminate() # Show time! self.show_package(packages)
def run_cmd(cmd, show=True, enable_sandbox=True): stdout = None stderr = None if enable_sandbox: # FIXME: getopt should not do this. # the verbosity of messages, defaults to 1 # 1 - error # 2 - warning # 3 - normal # 4 - verbose # 5 - debug # 6 - crazy debug log_level = lpms.getopt("--sandbox-log-level", like=True) if log_level is None: log_level = "1" if not log_level in ('1', '2', '3', '4', '5', '6'): out.warn("%s is an invalid sandbox log level." % log_level) cmd = "%s --config=%s --log-level=%s --log-file=%s -- %s" % (cst.sandbox_app, cst.sandbox_config, \ log_level, cst.sandbox_log, cmd) if not show: stdout = subprocess.PIPE stderr = subprocess.PIPE result = subprocess.Popen(cmd, shell=True, stdout=stdout, stderr=stderr) output, err = result.communicate() return result.returncode, output, err
def run(self): if lpms.getopt("--help") or len(self.params) == 0: self.usage() for param in self.params: param = param.split("/") if len(param) == 3: myrepo, mycategory, myname = param packages = self.repodb.find_package(package_name=myname, \ package_repo=myrepo, package_category=mycategory) elif len(param) == 2: mycategory, myname = param packages = self.repodb.find_package(package_name=myname, \ package_category=mycategory) elif len(param) == 1: packages = self.repodb.find_package(package_name=param[0]) else: out.error("%s seems invalid." % out.color("/".join(param), "brightred")) lpms.terminate() if not packages: out.error("%s not found!" % out.color("/".join(param), "brightred")) lpms.terminate() # Show time! self.show_package(packages)
def sync(self): if self.git_repo(): os.chdir(self.repo_path) if lpms.getopt("--reset"): out.warn("forcing git to overwrite local files") shelltools.system("%s reset --hard HEAD" % self.git_binary, sandbox=False) shelltools.system("%s clean -f -d" % self.git_binary, sandbox=False) shelltools.system("%s pull -f -u origin" % self.git_binary, sandbox=False) else: os.chdir(os.path.dirname(self.repo_path)) shelltools.system("%s clone %s %s" % (self.git_binary, self.remote, self.repo), sandbox=False)
def update_repository(self, repo_name): exceptions = ['scripts', 'licenses', 'news', 'info', 'libraries', '.git', '.svn'] # fistly, drop the repo self.repodb.database.delete_repository(repo_name, commit=True) repo_path = os.path.join(cst.repos, repo_name) for category in os.listdir(repo_path): target_directory = os.path.join(repo_path, category) if category in exceptions or not os.path.isdir(target_directory): continue packages = os.listdir(target_directory) try: packages.remove("info.xml") except ValueError: pass if lpms.getopt("--verbose"): out.notify("%s" % out.color(category, "brightwhite")) for my_pkg in packages: try: self.update_package(repo_path, category, my_pkg) except IntegrityError: continue
def update_repository(self, repo_name): exceptions = [ 'scripts', 'licenses', 'news', 'info', 'libraries', '.git', '.svn' ] # fistly, drop the repo self.repodb.database.delete_repository(repo_name, commit=True) repo_path = os.path.join(cst.repos, repo_name) for category in os.listdir(repo_path): target_directory = os.path.join(repo_path, category) if category in exceptions or not os.path.isdir(target_directory): continue packages = os.listdir(target_directory) try: packages.remove("info.xml") except ValueError: pass if lpms.getopt("--verbose"): out.notify("%s" % out.color(category, "brightwhite")) for my_pkg in packages: try: self.update_package(repo_path, category, my_pkg) except IntegrityError: continue
def color(msg, cl): if lpms.getopt("--no-color") or lpms.getopt( "-n") or not conf.LPMSConfig().colorize: return msg return colors[cl] + msg + colors['default']
def color(msg, cl): if lpms.getopt("--no-color") or lpms.getopt("-n") or not conf.LPMSConfig().colorize: return msg return colors[cl] + msg + colors['default']
if not self.is_installed(category, name, version): raise NotInstalled("%s/%s-%s is not installed." % (category, name, version)) filesdb_cursor = self.cursor(category, name, version) return filesdb_cursor.content def has_path(self, category, name, version, path): '''Checks given package for given path''' if not self.is_installed(category, name, version): raise NotInstalled("%s/%s-%s is not installed." % (category, name, version)) filesdb_cursor = self.cursor(category, name, version) return filesdb_cursor.has_path(path) if lpms.getopt("--help"): print( "A script that to migrate old xml based files database to new sql based one" ) lpms.terminate() installdb = dbapi.InstallDB() fapi = FilesAPI() shelltools.remove_file("/var/db/lpms/filesdb.db") _filesdb = dbapi.FilesDB() i = 0 for pkg in installdb.get_all_names(): repo, category, name = pkg versions = installdb.get_version(name, repo_name=repo,
def update_package(self, repo_path, category, my_pkg, my_version = None, update = False): dataset = LCollect() # Register some variables to use after self.env.repo = os.path.basename(repo_path) self.env.category = category dataset.repo = self.env.repo dataset.category = category os.chdir(os.path.join(repo_path, category, my_pkg)) for pkg in glob.glob("*"+cst.spec_suffix): script_path = os.path.join(repo_path, category, my_pkg, pkg) self.env.name, self.env.version = utils.parse_pkgname(pkg.split(cst.spec_suffix)[0]) dataset.name = self.env.name dataset.version = self.env.version # FIXME: We must develop a upper-class or environment to # use that cases to prevent code duplication # Begins code duplication interphase = re.search(r'-r[0-9][0-9]', self.env.version) if not interphase: interphase = re.search(r'-r[0-9]', self.env.version) self.env.raw_version = self.env.version self.env.revision = "" # Now, set real values of these variables if package revisioned. if interphase is not None and interphase.group(): self.env.raw_version = self.env.version.replace(interphase.group(), "") self.env.revision = interphase.group() # End of code duplication self.env.__dict__["fullname"] = self.env.name+"-"+self.env.version if not self.import_script(script_path): out.error("an error occured while processing the spec: %s" \ % out.color(script_path, "red")) out.error("please report the above error messages to the package maintainer.") continue metadata = utils.metadata_parser(self.env.metadata) metadata.update({"name": self.env.name, "version": self.env.version}) # This method checks metadata integrity. # It warn the user and pass the spec if a spec is broken self.check_metadata_integrity(metadata) # These values are optional if not "options" in metadata: metadata.update({"options": None}) if not "slot" in metadata: metadata.update({"slot": "0"}) if not "src_url" in metadata: metadata.update({"src_url": None}) if lpms.getopt("--verbose"): out.write(" %s-%s\n" % (self.env.name, self.env.version)) try: dataset.summary = metadata['summary'] dataset.homepage = metadata['homepage'] dataset.license = metadata['license'] dataset.src_uri = metadata['src_url'] if metadata['options'] is None: dataset.options = None else: dataset.options = metadata['options'].split(" ") dataset.slot = metadata['slot'] except KeyError as err: out.error("%s/%s/%s-%s: invalid metadata" % (repo_name, category, \ self.env.name, self.env.version)) out.warn("repository update was failed and the repository database was removed.") out.warn("you can run 'lpms --reload-previous-repodb' command to reload previous db version.") lpms.terminate("good luck!") if update: self.repodb.delete_package(package_repo=dataset.repo, package_category=dataset.category, \ package_name=self.env.name, package_version=self.env.version) static_depends_runtime = []; static_depends_build = []; static_depends_postmerge = []; static_depends_conflict = [] if 'depends' in self.env.__dict__.keys(): deps = utils.depends_parser(self.env.depends) if 'runtime' in deps: static_depends_runtime.extend(deps['runtime']) if 'build' in deps: static_depends_build.extend(deps['build']) if 'common' in deps: static_depends_runtime.extend(deps['common']) static_depends_build.extend(deps['common']) if 'postmerge' in deps: static_depends_postmerge.extend(deps['postmerge']) if 'conflict' in deps: static_depends_conflict.extend(deps['conflict']) optional_depends_runtime = []; optional_depends_build = []; optional_depends_postmerge = []; optional_depends_conflict = [] for opt in ('opt_common', 'opt_conflict', 'opt_postmerge', 'opt_runtime', 'opt_build'): try: deps = utils.parse_opt_deps(getattr(self.env, opt)) if opt.split("_")[1] == "runtime": optional_depends_runtime.append(deps) elif opt.split("_")[1] == "build": optional_depends_build.append(deps) elif opt.split("_")[1] == "common": optional_depends_build.append(deps) optional_depends_runtime.append(deps) elif opt.split("_")[1] == "postmerge": optional_depends_postmerge.append(deps) elif opt.split("_")[1] == "conflict": optional_depends_conflict.append(deps) del deps except AttributeError: continue dataset.optional_depends_runtime = optional_depends_runtime dataset.optional_depends_build = optional_depends_build dataset.optional_depends_postmerge = optional_depends_postmerge dataset.optional_depends_conflict = optional_depends_conflict dataset.static_depends_runtime = static_depends_runtime dataset.static_depends_build = static_depends_build dataset.static_depends_postmerge = static_depends_postmerge dataset.static_depends_conflict = static_depends_conflict if metadata['arch'] is not None: arches = metadata['arch'].split(" ") for arch in arches: dataset.arch = arch self.repodb.insert_package(dataset) else: dataset.arch = None self.repodb.insert_package(dataset) # remove optional keys for key in ('depends', 'options', 'opt_runtime', 'opt_build', \ 'opt_conflict', 'opt_common', 'opt_postmerge'): try: del self.env.__dict__[key] except KeyError: pass self.packages_num += 1
def remove_package(pkgnames, instruction): '''Triggers remove operation for given packages''' if instruction.like: # handle shortened package names database = dbapi.InstallDB() for item in instruction.like: query = database.db.cursor.execute("SELECT name FROM package where name LIKE ?", (item,)) results = query.fetchall() if results: for result in results: pkgnames.append(result[0]) del database file_relationsdb = dbapi.FileRelationsDB() #try: packages = [GetPackage(pkgname, installdb=True).select() for pkgname in pkgnames] #except PackageNotFound as package_name: # out.error("%s seems not installed." % package_name) # lpms.terminate() instruction.count = len(packages); index = 0; # FIXME: I must create a new reverse dependency handler implementation #if instruct["show-reverse-depends"]: # instruct["ask"] = True # # WARNING: the mechanism only shows directly reverse dependencies # # supposing that if A is a reverse dependency of B and C is depends on A. # # when the user removes B, A and C will be broken. But lpms will warn the user about A. # broken_packages = [] # reversedb = dbapi.ReverseDependsDB() # out.normal("resolving primary reverse dependencies...\n") # for package in packages: # category, name, version = package[1:] # if lpms.getopt("--use-file-relations"): # broken_packages.extend(file_relations.get_packages(category, name, version)) # else: # broken_packages.extend(reversedb.get_reverse_depends(category, name)) # if broken_packages: # out.warn("the following packages will be broken:\n") # for broken_package in broken_packages: # broken_repo, broken_category, broken_name, broken_version = broken_package # out.write(" %s %s/%s/%s-%s\n" % (out.color(">", "brightred"), broken_repo, broken_category, \ # broken_name, broken_version)) # else: # out.warn("no reverse dependency found.") if instruction.ask: out.write("\n") for package in packages: out.write(" %s %s/%s/%s-%s\n" % (out.color(">", "brightgreen"), out.color(package.repo, "green"), out.color(package.category, "green"), out.color(package.name, "green"), out.color(package.version, "green"))) utils.xterm_title("lpms: confirmation request") out.write("\nTotal %s package will be removed.\n\n" % out.color(str(instruction.count), "green")) if not utils.confirm("Would you like to continue?"): out.write("quitting...\n") utils.xterm_title_reset() lpms.terminate() realroot = instruction.new_root if instruction.new_root else cst.root config = conf.LPMSConfig() for package in packages: fdb = file_collisions.CollisionProtect(package.category, package.name, \ package.slot, version=package.version, real_root=realroot) fdb.handle_collisions() if fdb.collisions: out.write(out.color(" > ", "brightyellow")+"file collisions detected while removing %s/%s/%s-%s\n\n" \ % (package.repo, package.category, package.name, package.version)) for (c_package, c_path) in fdb.collisions: c_category, c_name, c_slot, c_version = c_package out.write(out.color(" -- ", "red")+c_category+"/"+c_name+"-"\ +c_version+":"+c_slot+" -> "+c_path+"\n") if fdb.collisions and config.collision_protect and not \ lpms.getopt('--force-file-collision'): out.write("\nquitting... use '--force-file-collision' to continue.\n") lpms.terminate() index += 1; instruction.index = index if not initpreter.InitializeInterpreter(package, instruction, ['remove'], remove=True).initialize(): out.warn("an error occured during remove operation: %s/%s/%s-%s" % (package.repo, package.category, \ package.name, package.version)) else: file_relationsdb.delete_item_by_pkgdata(package.category, package.name, package.version, commit=True)
def search(self): if not list(self.keyword) and lpms.getopt("--only-installed"): total = 0 for package in self.instdb.get_all_names(): repo, category, name = package version_data = self.instdb.get_version(name, repo_name=repo, \ pkg_category=category) total += 1 for slot in version_data: out.notify("%s/%s/%s [slot:%s] -> %s" % (repo, category, name, \ slot, ", ".join(version_data[slot]))) out.write("\npackage count: %d\n" % total) lpms.terminate() if lpms.getopt("--help") or len(self.keyword) == 0: self.usage() available = True results = [] if not lpms.getopt("--in-summary") and not lpms.getopt("--in-name"): self.cursor.execute( '''SELECT repo, category, name, version, summary, slot FROM \ package WHERE name LIKE (?) OR summary LIKE (?)''', ("%" + self.keyword + "%", "%" + self.keyword + "%")) results.extend(self.cursor.fetchall()) elif lpms.getopt("--in-summary"): self.cursor.execute( '''SELECT repo, category, name, version, summary, slot FROM \ package WHERE summary LIKE (?)''', ("%" + self.keyword + "%", )) results.extend(self.cursor.fetchall()) else: self.cursor.execute( '''SELECT repo, category, name, version, summary, slot FROM \ package WHERE name LIKE (?)''', ("%" + self.keyword + "%", )) results.extend(self.cursor.fetchall()) if not results: # if no result, search given keyword in installed packages database connection = sqlite3.connect(cst.installdb_path) cursor = connection.cursor() cursor.execute( '''SELECT repo, category, name, version, summary, slot FROM \ package WHERE name LIKE (?) OR summary LIKE (?)''', ("%" + self.keyword + "%", "%" + self.keyword + "%")) results.extend(cursor.fetchall()) if results: out.notify( "these packages are installed but no longer available.") available = False packages = self.classificate_packages(results) for index, package in enumerate(packages, 1): category, name = package if lpms.getopt("--interactive"): out.write("[" + str(index) + "] " + out.color(category, "green") + "/" + out.color(name, "green") + " - ") else: out.write( out.color(category, "green") + "/" + out.color(name, "green") + " - ") items = {} for item in packages[package]: if item[0] in items: items[item[0]].append(item[3]) else: items[item[0]] = [item[3]] for item in items: out.write( out.color(item, "yellow") + "(" + ", ".join(items[item]) + ") ") out.write("\n") out.write(" " + packages[package][0][4] + "\n") # shows a dialogue, selects the packages and triggers api's build function if results and lpms.getopt("--interactive"): my_packages = [] def ask(): out.write("\ngive number(s):\n") out.write( "in order to select more than one package, use space between numbers:\n" ) out.write("to exit, press Q or q.\n") while True: ask() answers = sys.stdin.readline().strip() if answers == "Q" or answers == "q": lpms.terminate() else: targets = set() for answer in answers.split(" "): if not answer.isdigit(): out.warn("%s is invalid. please give a number!" % out.color(answer, "red")) continue else: targets.add(answer) try: my_items = packages.keys() for target in targets: my_packages.append("/".join(my_items[int(target) - 1])) break except (IndexError, ValueError): out.warn("invalid command.") continue if my_packages: api.pkgbuild(my_packages, self.instruct)
def update_package(self, repo_path, category, my_pkg, my_version=None, update=False): dataset = LCollect() # Register some variables to use after self.env.repo = os.path.basename(repo_path) self.env.category = category dataset.repo = self.env.repo dataset.category = category os.chdir(os.path.join(repo_path, category, my_pkg)) for pkg in glob.glob("*" + cst.spec_suffix): script_path = os.path.join(repo_path, category, my_pkg, pkg) self.env.name, self.env.version = utils.parse_pkgname( pkg.split(cst.spec_suffix)[0]) dataset.name = self.env.name dataset.version = self.env.version # FIXME: We must develop a upper-class or environment to # use that cases to prevent code duplication # Begins code duplication interphase = re.search(r'-r[0-9][0-9]', self.env.version) if not interphase: interphase = re.search(r'-r[0-9]', self.env.version) self.env.raw_version = self.env.version self.env.revision = "" # Now, set real values of these variables if package revisioned. if interphase is not None and interphase.group(): self.env.raw_version = self.env.version.replace( interphase.group(), "") self.env.revision = interphase.group() # End of code duplication self.env.__dict__[ "fullname"] = self.env.name + "-" + self.env.version if not self.import_script(script_path): out.error("an error occured while processing the spec: %s" \ % out.color(script_path, "red")) out.error( "please report the above error messages to the package maintainer." ) continue metadata = utils.metadata_parser(self.env.metadata) metadata.update({ "name": self.env.name, "version": self.env.version }) # This method checks metadata integrity. # It warn the user and pass the spec if a spec is broken self.check_metadata_integrity(metadata) # These values are optional if not "options" in metadata: metadata.update({"options": None}) if not "slot" in metadata: metadata.update({"slot": "0"}) if not "src_url" in metadata: metadata.update({"src_url": None}) if lpms.getopt("--verbose"): out.write(" %s-%s\n" % (self.env.name, self.env.version)) try: dataset.summary = metadata['summary'] dataset.homepage = metadata['homepage'] dataset.license = metadata['license'] dataset.src_uri = metadata['src_url'] if metadata['options'] is None: dataset.options = None else: dataset.options = metadata['options'].split(" ") dataset.slot = metadata['slot'] except KeyError as err: out.error("%s/%s/%s-%s: invalid metadata" % (repo_name, category, \ self.env.name, self.env.version)) out.warn( "repository update was failed and the repository database was removed." ) out.warn( "you can run 'lpms --reload-previous-repodb' command to reload previous db version." ) lpms.terminate("good luck!") if update: self.repodb.delete_package(package_repo=dataset.repo, package_category=dataset.category, \ package_name=self.env.name, package_version=self.env.version) static_depends_runtime = [] static_depends_build = [] static_depends_postmerge = [] static_depends_conflict = [] if 'depends' in self.env.__dict__.keys(): deps = utils.depends_parser(self.env.depends) if 'runtime' in deps: static_depends_runtime.extend(deps['runtime']) if 'build' in deps: static_depends_build.extend(deps['build']) if 'common' in deps: static_depends_runtime.extend(deps['common']) static_depends_build.extend(deps['common']) if 'postmerge' in deps: static_depends_postmerge.extend(deps['postmerge']) if 'conflict' in deps: static_depends_conflict.extend(deps['conflict']) optional_depends_runtime = [] optional_depends_build = [] optional_depends_postmerge = [] optional_depends_conflict = [] for opt in ('opt_common', 'opt_conflict', 'opt_postmerge', 'opt_runtime', 'opt_build'): try: deps = utils.parse_opt_deps(getattr(self.env, opt)) if opt.split("_")[1] == "runtime": optional_depends_runtime.append(deps) elif opt.split("_")[1] == "build": optional_depends_build.append(deps) elif opt.split("_")[1] == "common": optional_depends_build.append(deps) optional_depends_runtime.append(deps) elif opt.split("_")[1] == "postmerge": optional_depends_postmerge.append(deps) elif opt.split("_")[1] == "conflict": optional_depends_conflict.append(deps) del deps except AttributeError: continue dataset.optional_depends_runtime = optional_depends_runtime dataset.optional_depends_build = optional_depends_build dataset.optional_depends_postmerge = optional_depends_postmerge dataset.optional_depends_conflict = optional_depends_conflict dataset.static_depends_runtime = static_depends_runtime dataset.static_depends_build = static_depends_build dataset.static_depends_postmerge = static_depends_postmerge dataset.static_depends_conflict = static_depends_conflict if metadata['arch'] is not None: arches = metadata['arch'].split(" ") for arch in arches: dataset.arch = arch self.repodb.insert_package(dataset) else: dataset.arch = None self.repodb.insert_package(dataset) # remove optional keys for key in ('depends', 'options', 'opt_runtime', 'opt_build', \ 'opt_conflict', 'opt_common', 'opt_postmerge'): try: del self.env.__dict__[key] except KeyError: pass self.packages_num += 1
def create_operation_plan(self): '''Resolve dependencies and prepares a convenient operation plan''' single_packages = PackageItem() for package in self.packages: self.parent_package = package self.current_package = None self.package_heap[package.id] = package dependencies = [] package_dependencies = self.collect_dependencies(package) if not package_dependencies: single_packages.add(package) continue # Create a list that consists of parent and child items for dependency in package_dependencies: dependency.parent = package.category+"/"+package.name+"/"+package.slot dependencies.append((package.id, dependency)) while True: buff = [] for parent, dependency in dependencies: self.current_package = dependency self.parent_package = None self.package_query.append((dependency.id, parent)) if dependency.id in self.processed: if self.processed[dependency.id] == self.package_options.get(dependency.id, None): # This package was processed and it has no option changes continue # Keep the package options to prevent extra transaction self.processed[dependency.id] = self.package_options.get(dependency.id, None) # Keep the package information for the next operations. # We don't want to create a new transaction for it. self.package_heap[dependency.id] = dependency # Get its dependencies package_collection = self.collect_dependencies(dependency) if not package_collection: # The item has no dependency continue # Create a list that consists of parent and child items for item in package_collection: item.parent = package.category+"/"+package.name+"/"+package.slot buff.append((dependency.id, item)) if not buff: # End of the node break dependencies = buff try: # Sort packages for building operation plan = sorter.topsort(self.package_query) except sorter.CycleError as err: answer, num_parents, children = err out.brightred("Circular dependency detected:\n") for items in sorter.find_cycles(parent_children=children): for item in items: package = self.repodb.find_package(package_id=item).get(0) out.write(package.repo+"/"+package.category+"/"+package.name+"-"\ +package.version+":"+package.slot+" ") out.write("\n") raise DependencyError # This part detects inline option conflicts removed = {} option_conflict = set() for package_id in self.inline_option_targets: for target in self.inline_option_targets[package_id]: for option in self.inline_option_targets[package_id][target]: if option.startswith("-"): if option in removed: removed[option].add((package_id, target)) else: removed[option] = set([(package_id, target)]) else: if "-"+option in removed: for (my_pkg_id, my_target) in removed["-"+option]: if my_target == target: option_conflict.add((my_target, \ self.package_heap[package_id], \ self.package_heap[my_pkg_id],\ option)) if option_conflict: out.error("option conflict detected:\n") for (pkg, add, remove, option)in option_conflict: out.error(out.color(option, "red")+" option on "+pkg+"\n") out.warn("%s/%s/%s/%s adds the option." % (add.repo, add.category, \ add.name, add.version)) out.warn("%s/%s/%s/%s removes the option." % (remove.repo, remove.category, \ remove.name, remove.version)) lpms.terminate() self.conditional_versions = {} for (key, values) in self.conditional_packages.items(): for value in values: target_package = self.package_heap[key] my_item = { "type": value["type"], "version": value["version"], "target": target_package.category+"/"+target_package.name+\ "/"+target_package.slot, } if not value["owner_id"] in self.conditional_versions: self.conditional_versions[value["owner_id"]] = [my_item] else: self.conditional_versions[value["owner_id"]].append(my_item) # TODO: I think I must use most professional way for ignore-depends feature. if lpms.getopt("--ignore-deps"): result = LCollect() result.packages = self.packages result.dependencies = self.package_dependencies result.options = self.package_options result.inline_option_targets = self.inline_option_targets result.conditional_versions = self.conditional_versions result.conflicts = self.conflicts return result # Workaround for postmerge dependencies for (id_dependency, id_package) in self.postmerge_dependencies: plan.remove(id_dependency) plan.insert(plan.index(id_package)+1, id_dependency) final_plan = PackageItem() required_package_ids = [package.id for package in self.packages] for package_id in plan: package = self.package_heap[package_id] continue_conditional = False # If a package has a conditional decision point, # we should consider the condition if package.id not in self.conditional_packages: for c_package_id in self.conditional_packages: c_package = self.package_heap[c_package_id] if package.pk == c_package.pk: continue_conditional = True if package_id in required_package_ids: final_plan.add_by_pk(c_package) break if package_id in required_package_ids: if continue_conditional is False: final_plan.add_by_pk(package) if continue_conditional: continue installed_package = self.instdb.find_package( package_category=package.category, package_name=package.name, package_slot=package.slot ) if installed_package: if package.id in self.inline_options: if installed_package.get(0).applied_options is None: final_plan.add_by_pk(package) continue continue_inline = False for inline_option in self.inline_options[package.id]: if not inline_option in installed_package.get(0).applied_options: final_plan.add_by_pk(package) continue_inline = True break if continue_inline: continue try: conditional_versions_query = self.instdb.find_conditional_versions( target=package.category+"/"+package.name+"/"+package.slot) if conditional_versions_query: for item in conditional_versions_query: item.decision_point["package_id"]=item.package_id if package.id in self.conditional_packages: if not item.decision_point in self.conditional_packages[package.id]: self.conditional_packages[package.id].append(item.decision_point) else: self.conditional_packages[package.id] = [item.decision_point] if package.id in self.conditional_packages: decision_points = self.conditional_packages[package.id] for decision_point in decision_points: comparison = utils.vercmp(installed_package.get(0).version, \ decision_point["version"]) if decision_point["type"] == ">=": if self.handle_condition_conflict(decision_point, final_plan, \ package.pk, ("<", ">"), (0, 1)) is False: continue if not comparison in (1, 0) or package.id in required_package_ids: final_plan.add_by_pk(package) elif decision_point["type"] == "<": if self.handle_condition_conflict(decision_point, final_plan, \ package.pk, (">", "<"), (0, -1)) is False: continue if comparison != -1: final_plan.add_by_pk(package) elif decision_point["type"] == ">": if self.handle_condition_conflict(decision_point, final_plan, \ package.pk, ("<", ">"), (0, 1)) is False: continue if comparison != 1 or package.id in required_package_ids: final_plan.add_by_pk(package) elif decision_point["type"] == "<=": if self.handle_condition_conflict(decision_point, final_plan, \ package.pk, (">", "<"), (0, -1)) is False: continue if not comparison in (-1, 0) or package.id in required_package_ids: final_plan.add_by_pk(package) elif decision_point["type"] == "==": if comparison != 0 or package.id in required_package_ids: final_plan.add_by_pk(package) except ConditionConflict: if not "owner_package" in decision_point: conflict_package = self.instdb.find_package(package_id=\ decision_point["package_id"]).get(0) decision_point["owner_package"] = conflict_package.repo+"/"+ \ conflict_package.category+"/"+ \ conflict_package.name+"/"+ \ conflict_package.version out.error("while selecting a convenient version of %s, a conflict detected:\n" % \ out.color(package.pk, "red")) out.notify(decision_point["owner_package"]+" wants "+\ decision_point["type"]+decision_point["version"]) out.notify(self.conflict_point["owner_package"]+" wants "+\ self.conflict_point["type"]+self.conflict_point["version"]) lpms.terminate("\nplease contact the package maintainers.") # Use new options if the package is effected if self.use_new_options and not package in final_plan: if package.id in self.package_options: for option in self.package_options[package.id]: if not option in installed_package.get(0).applied_options: final_plan.add_by_pk(package) break else: final_plan.add_by_pk(package) # Oh my god! Some packages have no dependency. if single_packages: for single_package in single_packages: for item_id in plan: if self.package_heap[item_id].pk == single_package.pk: single_packages.remove(single_package) break for single_package in single_packages: final_plan.insert_into(0, single_package) # Create LCollect object to manage package dependency data operation_plan = LCollect() operation_plan.packages = final_plan operation_plan.dependencies = self.package_dependencies operation_plan.options = self.package_options operation_plan.inline_option_targets = self.inline_option_targets operation_plan.conditional_versions = self.conditional_versions operation_plan.conflicts = self.conflicts return operation_plan
def remove_package(pkgnames, instruction): '''Triggers remove operation for given packages''' if instruction.like: # handle shortened package names database = dbapi.InstallDB() for item in instruction.like: query = database.db.cursor.execute( "SELECT name FROM package where name LIKE ?", (item, )) results = query.fetchall() if results: for result in results: pkgnames.append(result[0]) del database file_relationsdb = dbapi.FileRelationsDB() #try: packages = [ GetPackage(pkgname, installdb=True).select() for pkgname in pkgnames ] #except PackageNotFound as package_name: # out.error("%s seems not installed." % package_name) # lpms.terminate() instruction.count = len(packages) index = 0 # FIXME: I must create a new reverse dependency handler implementation #if instruct["show-reverse-depends"]: # instruct["ask"] = True # # WARNING: the mechanism only shows directly reverse dependencies # # supposing that if A is a reverse dependency of B and C is depends on A. # # when the user removes B, A and C will be broken. But lpms will warn the user about A. # broken_packages = [] # reversedb = dbapi.ReverseDependsDB() # out.normal("resolving primary reverse dependencies...\n") # for package in packages: # category, name, version = package[1:] # if lpms.getopt("--use-file-relations"): # broken_packages.extend(file_relations.get_packages(category, name, version)) # else: # broken_packages.extend(reversedb.get_reverse_depends(category, name)) # if broken_packages: # out.warn("the following packages will be broken:\n") # for broken_package in broken_packages: # broken_repo, broken_category, broken_name, broken_version = broken_package # out.write(" %s %s/%s/%s-%s\n" % (out.color(">", "brightred"), broken_repo, broken_category, \ # broken_name, broken_version)) # else: # out.warn("no reverse dependency found.") if instruction.ask: out.write("\n") for package in packages: out.write( " %s %s/%s/%s-%s\n" % (out.color( ">", "brightgreen"), out.color(package.repo, "green"), out.color(package.category, "green"), out.color(package.name, "green"), out.color(package.version, "green"))) utils.xterm_title("lpms: confirmation request") out.write("\nTotal %s package will be removed.\n\n" % out.color(str(instruction.count), "green")) if not utils.confirm("Would you like to continue?"): out.write("quitting...\n") utils.xterm_title_reset() lpms.terminate() realroot = instruction.new_root if instruction.new_root else cst.root config = conf.LPMSConfig() for package in packages: fdb = file_collisions.CollisionProtect(package.category, package.name, \ package.slot, version=package.version, real_root=realroot) fdb.handle_collisions() if fdb.collisions: out.write(out.color(" > ", "brightyellow")+"file collisions detected while removing %s/%s/%s-%s\n\n" \ % (package.repo, package.category, package.name, package.version)) for (c_package, c_path) in fdb.collisions: c_category, c_name, c_slot, c_version = c_package out.write(out.color(" -- ", "red")+c_category+"/"+c_name+"-"\ +c_version+":"+c_slot+" -> "+c_path+"\n") if fdb.collisions and config.collision_protect and not \ lpms.getopt('--force-file-collision'): out.write( "\nquitting... use '--force-file-collision' to continue.\n" ) lpms.terminate() index += 1 instruction.index = index if not initpreter.InitializeInterpreter( package, instruction, ['remove'], remove=True).initialize(): out.warn("an error occured during remove operation: %s/%s/%s-%s" % (package.repo, package.category, \ package.name, package.version)) else: file_relationsdb.delete_item_by_pkgdata(package.category, package.name, package.version, commit=True)