def error_from_dose3_report(report): def fixup_relation(rel): for o in rel: for d in o: if d['version']: try: newoperator = {'<': '<<', '>': '>>'}[d['version'][0]] except KeyError: pass else: d['version'] = (newoperator, d['version'][1]) packages = [entry["package"] for entry in report] assert packages == ["sbuild-build-depends-main-dummy"] if report[0]["status"] != "broken": return None missing = [] conflict = [] for reason in report[0]["reasons"]: if "missing" in reason: relation = PkgRelation.parse_relations( reason["missing"]["pkg"]["unsat-dependency"]) fixup_relation(relation) missing.extend(relation) if "conflict" in reason: relation = PkgRelation.parse_relations( reason["conflict"]["pkg1"]["unsat-conflict"]) fixup_relation(relation) conflict.extend(relation) if missing: return UnsatisfiedAptDependencies(missing) if conflict: return UnsatisfiedAptConflicts(conflict)
def update_deps(control, field, package, min_version, epoch=None): bdi = PkgRelation.parse_relations(control[field]) if epoch is not None: epoch = "%d:" % epoch else: epoch = "" update_relation(bdi, package, ">=", epoch + "%d.%d.%d~" % min_version) control[field] = PkgRelation.str(bdi)
def relationship_builder(relationship_line, getter): """Parse relationship_line into a IPackageRelationshipSet. 'relationship_line' is parsed via PkgRelation.parse_relations. It also looks up the corresponding URL via the given 'getter'. Return empty list if no line is given. """ relationship_set = PackageRelationshipSet() if not relationship_line: return relationship_set parsed_relationships = [ token[0] for token in PkgRelation.parse_relations(relationship_line) ] for rel in parsed_relationships: name = rel['name'] target_object = getter(name) if target_object is not None: url = canonical_url(target_object) else: url = None if rel['version'] is None: operator = u'' version = u'' else: operator, version = rel['version'] relationship_set.add(name, operator, version, url) return relationship_set
def install(self, requirements): missing = [] for req in requirements: try: if not req.met(self.apt.session): missing.append(req) except NotImplementedError: missing.append(req) if not missing: return still_missing = [] apt_requirements = [] for m in missing: apt_req = self.resolve(m) if apt_req is None: still_missing.append(m) else: apt_requirements.append(apt_req) if apt_requirements: self.apt.satisfy([ PkgRelation.str(chain(*[r.relations for r in apt_requirements])) ]) if still_missing: raise UnsatisfiedRequirements(still_missing)
def add_build_dependency(context, requirement: AptRequirement): if not isinstance(requirement, AptRequirement): raise TypeError(requirement) control_path = context.abspath("debian/control") try: with ControlEditor(path=control_path) as updater: for binary in updater.binaries: if requirement.touches_package(binary["Package"]): raise CircularDependency(binary["Package"]) for rel in requirement.relations: updater.source["Build-Depends"] = ensure_relation( updater.source.get("Build-Depends", ""), PkgRelation.str([rel])) except FormattingUnpreservable as e: logging.info("Unable to edit %s in a way that preserves formatting.", e.path) return False desc = requirement.pkg_relation_str() if not updater.changed: logging.info("Giving up; dependency %s was already present.", desc) return False logging.info("Adding build dependency: %s", desc) return context.commit("Add missing build dependency on %s." % desc)
def add_test_dependency(context, testname, requirement): if not isinstance(requirement, AptRequirement): raise TypeError(requirement) tests_control_path = context.abspath("debian/tests/control") # TODO(jelmer): If requirement is for one of our binary packages # but "@" is already present then don't do anything. try: with Deb822Editor(path=tests_control_path) as updater: command_counter = 1 for control in updater.paragraphs: try: name = control["Tests"] except KeyError: name = "command%d" % command_counter command_counter += 1 if name != testname: continue for rel in requirement.relations: control["Depends"] = ensure_relation( control.get("Depends", ""), PkgRelation.str([rel])) except FormattingUnpreservable as e: logging.info("Unable to edit %s in a way that preserves formatting.", e.path) return False if not updater.changed: return False desc = requirement.pkg_relation_str() logging.info("Adding dependency to test %s: %s", testname, desc) return context.commit( "Add missing dependency for test %s on %s." % (testname, desc), )
def binary_pkg_matches(entry, binary): # TODO(jelmer): check versions if entry['name'] == binary['Package']: return True for provides_top in PkgRelation.parse_relations( binary.get('Provides', '')): for provides in provides_top: if entry['name'] == provides['name']: return True return False
def validate_relations(value): """ Package Lists """ relations = PkgRelation.parse_relations(value) for relation in relations: for rel in relation: if len(rel) == 3: raise ValidationError( _("Cannot parse package relationship \"%s\"") % rel.get("name", "untitled"))
def rep_dbgsym_migration(m): rep = m.group(2).strip(b'"').strip(b"'").decode() if '$' in rep: # too complicated return m.group(0) rep = PkgRelation.parse_relations(rep) if migration_done(rep): issue = LintianIssue( 'source', 'debug-symbol-migration-possibly-complete', '%s (line XX)' % (m.group(0).decode().strip())) if issue.should_fix(): issue.report_fixed() return b'' return m.group(0)
def explain(self, requirements): apt_requirements = [] for r in requirements: apt_req = self.resolve(r) if apt_req is not None: apt_requirements.append((r, apt_req)) if apt_requirements: yield ( self.apt.satisfy_command([ PkgRelation.str( chain(*[r.relations for o, r in apt_requirements])) ]), [o for o, r in apt_requirements], )
def targeted_python_versions(tree: Tree, subpath: str) -> List[str]: with tree.get_file(os.path.join(subpath, "debian/control")) as f: control = Deb822(f) build_depends = PkgRelation.parse_relations( control.get("Build-Depends", "")) all_build_deps: Set[str] = set() for or_deps in build_depends: all_build_deps.update(or_dep["name"] for or_dep in or_deps) targeted = [] if any(x.startswith("python3-") for x in all_build_deps): targeted.append("python3") if any(x.startswith("pypy") for x in all_build_deps): targeted.append("pypy") if any(x.startswith("python-") for x in all_build_deps): targeted.append("python") return targeted
def update_deps(control, field, package, min_version): bdi = PkgRelation.parse_relations(control[field]) update_relation(bdi, package, ">=", "%d.%d.%d~" % min_version) control[field] = PkgRelation.str(bdi)
def __str__(self): return "Unsatisfied APT dependencies: %s" % PkgRelation.str( self.relations)
def generate_debian_package(args, config): debfile = Deb822( open("debian/control"), fields=["Build-Depends", "Build-Depends-Indep"]) rel_str = debfile.get("Build-Depends") if debfile.has_key("Build-Depends-Indep"): rel_str = rel_str + "," + debfile.get("Build-Depends-Indep") relations = PkgRelation.parse_relations(rel_str) cache = Cache() # Check if all required packages are installed for dep in relations: if not check_deb_dependency_installed(cache, dep): # Install not found dependencies print("Dependency not matched: " + str(dep)) if not install_dependency(cache, dep): print("Dependency cannot be installed: " + PkgRelation.str([dep ])) exit(1) changelog = Changelog(open("debian/changelog")) old_changelog = Changelog(open("debian/changelog")) dist = os.popen("lsb_release -c").read() dist = dist[dist.rfind(":") + 1::].replace("\n", "").replace( "\t", "").replace(" ", "") new_version = get_debian_version(args, dist) changelog.new_block(version=new_version, package=changelog.package, distributions="testing", changes=["\n Generating new package version\n"], author=changelog.author, date=strftime("%a, %d %b %Y %H:%M:%S %z"), urgency=changelog.urgency) changelog.write_to_open_file(open("debian/changelog", 'w')) # Execute commands defined in config: if config.has_key("prebuild-command"): print("Executing prebuild-command: " + str(config["prebuild-command"])) if os.system(config["prebuild-command"]) != 0: print("Failed to execute prebuild command") exit(1) if os.system("dpkg-buildpackage -uc -us") != 0: print("Error generating package") exit(1) if os.system("sudo dpkg -i ../*" + new_version + "_*.deb") != 0: print("Packages are not installable") exit(1) files = glob.glob("../*" + new_version + "_*.deb") if args.command == "upload": for f in files: if f is files[-1]: is_last = True else: is_last = False if new_version.find("~") == -1: upload_package(args, config, dist, f) upload_package(args, config, dist + "-dev", f, publish=is_last) if args.clean: files = glob.glob("../*" + new_version + "*") for f in files: os.remove(f) # Write old changelog to let everything as it was old_changelog.write_to_open_file(open("debian/changelog", 'w'))
def verify(self): """Verify the uploaded .dsc file. This method is an error generator, i.e, it returns an iterator over all exceptions that are generated while processing DSC file checks. """ for error in SourceUploadFile.verify(self): yield error # Check size and checksum of the DSC file itself try: self.checkSizeAndCheckSum() except UploadError as error: yield error try: raw_files = parse_and_merge_file_lists(self._dict, changes=False) except UploadError as e: yield e return files = [] for attr in raw_files: filename, hashes, size = attr if not re_issource.match(filename): # DSC files only really hold on references to source # files; they are essentially a description of a source # package. Anything else is crack. yield UploadError("%s: File %s does not look sourceful." % (self.filename, filename)) continue filepath = os.path.join(self.dirname, filename) try: file_instance = DSCUploadedFile(filepath, hashes, size, self.policy, self.logger) except UploadError as error: yield error else: files.append(file_instance) self.files = files if not re_valid_pkg_name.match(self.source): yield UploadError("%s: invalid source name %s" % (self.filename, self.source)) if not re_valid_version.match(self.dsc_version): yield UploadError("%s: invalid version %s" % (self.filename, self.dsc_version)) if not self.policy.distroseries.isSourcePackageFormatPermitted( self.format): yield UploadError( "%s: format '%s' is not permitted in %s." % (self.filename, self.format, self.policy.distroseries.name)) # Validate the build dependencies for field_name in ['Build-Depends', 'Build-Depends-Indep']: field = self._dict.get(field_name, None) if field is not None: if field.startswith("ARRAY"): yield UploadError( "%s: invalid %s field produced by a broken version " "of dpkg-dev (1.10.11)" % (self.filename, field_name)) try: with warnings.catch_warnings(): warnings.simplefilter("error") PkgRelation.parse_relations(field) except Warning as error: yield UploadError( "%s: invalid %s field; cannot be parsed by deb822: %s" % (self.filename, field_name, error)) # Verify if version declared in changesfile is the same than that # in DSC (including epochs). if self.dsc_version != self.version: yield UploadError( "%s: version ('%s') in .dsc does not match version " "('%s') in .changes." % (self.filename, self.dsc_version, self.version)) for error in self.checkFiles(): yield error
def from_str(cls, text): return cls(PkgRelation.parse_relations(text))
def pkg_relation_str(self): return PkgRelation.str(self.relations)
def __repr__(self): return "%s.from_str(%r)" % ( type(self).__name__, PkgRelation.str(self.relations), )
def __str__(self): return "Unsatisfied APT conflicts: %s" % PkgRelation.str( self.relations)