def get_magic_tag_to_remove(version): """Returns magic tag or True if all of them should be removed.""" i = Interpreter('python') map_ = {} for v in SUPPORTED: try: map_[v] = i.magic_tag(v) except Exception: log.debug('magic tag for %s not recognized', vrepr(v), exc_info=True) if version not in map_: try: map_[version] = i.magic_tag(version) except Exception as e: log.error('cannot find magic tag for Python %s: %s', vrepr(version), e) exit(4) tag = map_[version] # skip shared tags for v, t in map_.items(): if v == version: continue if t == tag: log.info('magic tag(s) used by python%s. Nothing to remove.', vrepr(v)) exit(0) log.debug('magic tags to remove: %s', tag) return tag
def guess_dependency(req, version=None): log.debug('trying to guess dependency for %s (python=%s)', req, vrepr(version) if version else None) if isinstance(version, basestring): version = getver(version) # some upstreams have weird ideas for distribution name... name, rest = re.compile('([^!><= \[]+)(.*)').match(req).groups() req = safe_name(name) + rest data = load() req_d = REQUIRES_RE.match(req) if not req_d: log.info('please ask dh_python2 author to fix REQUIRES_RE ' 'or your upstream author to fix requires.txt') raise Exception('requirement is not valid: %s' % req) req_d = req_d.groupdict() name = req_d['name'] details = data.get(name.lower()) if details: for item in details: if version and version not in item.get('versions', version): # rule doesn't match version, try next one continue if not item['dependency']: return # this requirement should be ignored if item['dependency'].endswith(')'): # no need to translate versions if version is hardcoded in # Debian dependency return item['dependency'] if req_d['version'] and (item['standard'] or item['rules']) and\ req_d['operator'] not in (None, '=='): v = _translate(req_d['version'], item['rules'], item['standard']) return "%s (%s %s)" % (item['dependency'], req_d['operator'], v) else: return item['dependency'] # try dpkg -S query = "'*/%s-?*\.egg-info'" % ci_regexp( safe_name(name)) # TODO: .dist-info if version: query = "%s | grep '/python%s/\|/pyshared/'" % \ (query, vrepr(version)) else: query = "%s | grep '/python2\../\|/pyshared/'" % query log.debug("invoking dpkg -S %s", query) process = Popen("/usr/bin/dpkg -S %s" % query, \ shell=True, stdout=PIPE, stderr=PIPE) stdout, stderr = process.communicate() if process.returncode == 0: result = set() for line in stdout.split('\n'): if not line.strip(): continue result.add(line.split(':')[0]) if len(result) > 1: log.error('more than one package name found for %s dist', name) else: return result.pop() else: log.debug('dpkg -S did not find package for %s: %s', name, stderr) # fall back to python-distname pname = sensible_pname(name) log.info( 'Cannot find installed package that provides %s. ' 'Using %s as package name. Please add "%s correct_package_name" ' 'line to debian/pydist-overrides to override it if this is incorrect.', name, pname, safe_name(name)) return pname
def guess_dependency(req, version=None): log.debug('trying to guess dependency for %s (python=%s)', req, vrepr(version) if version else None) if isinstance(version, basestring): version = getver(version) # some upstreams have weird ideas for distribution name... name, rest = re.compile('([^><= \[]+)(.*)').match(req).groups() req = safe_name(name) + rest data = load() req_dict = REQUIRES_RE.match(req) if not req_dict: log.info('please ask dh_python2 author to fix REQUIRES_RE ' 'or your upstream author to fix requires.txt') raise Exception('requirement is not valid: %s' % req) req_dict = req_dict.groupdict() name = req_dict['name'] details = data.get(name.lower()) if details: for item in details: if version and version not in item.get('versions', version): # rule doesn't match version, try next one continue if not item['dependency']: return # this requirement should be ignored if item['dependency'].endswith(')'): # no need to translate versions if version is hardcoded in Debian # dependency return item['dependency'] if req_dict['version']: # FIXME: translate it (rules, versions) return item['dependency'] else: return item['dependency'] # try dpkg -S query = "'*/%s-?*\.egg-info'" % ci_regexp(safe_name(name)) # TODO: .dist-info if version: query = "%s | grep '/python%s/\|/pyshared/'" % \ (query, vrepr(version)) else: query = "%s | grep '/python2\../\|/pyshared/'" % query log.debug("invoking dpkg -S %s", query) process = Popen("/usr/bin/dpkg -S %s" % query, \ shell=True, stdout=PIPE, stderr=PIPE) stdout, stderr = process.communicate() if process.returncode == 0: result = set() for line in stdout.split('\n'): if not line.strip(): continue result.add(line.split(':')[0]) if len(result) > 1: log.error('more than one package name found for %s dist', name) else: return result.pop() else: log.debug('dpkg -S did not find package for %s: %s', name, stderr) # fall back to python-distname pname = sensible_pname(name) log.warn('Cannot find installed package that provides %s. ' 'Using %s as package name. Please add "%s correct_package_name" ' 'line to debian/pydist-overrides to override it if this is incorrect.', name, pname, safe_name(name)) return pname
def parse(self, stats, options): log.debug('generating dependencies for package %s', self.package) pub_vers = sorted(stats['public_vers'].union(stats['ext'])) if pub_vers: dbgpkg = self.package.endswith('-dbg') tpl = 'python-dbg' if dbgpkg else 'python' minv = pub_vers[0] maxv = pub_vers[-1] if dbgpkg: tpl2 = 'python%d.%d-dbg' else: tpl2 = 'python%d.%d' self.depend(' | '.join(tpl2 % i for i in debsorted(pub_vers))) # additional Depends to block python package transitions if minv <= DEFAULT: self.depend("%s (>= %d.%d)" % \ (tpl, minv[0], minv[1])) if maxv >= DEFAULT: self.depend("%s (<< %d.%d)" % \ (tpl, maxv[0], maxv[1] + 1)) # make sure pycompile binary is available if stats['compile']: self.depend(MINPYCDEP) if not options.ignore_shebangs: for interpreter, version in stats['shebangs']: self.depend(interpreter) for private_dir, details in stats['private_dirs'].iteritems(): if options.ignore_shebangs: versions = [] else: versions = list(v for i, v in details.get('shebangs', []) if v) for v in versions: if v in SUPPORTED: self.depend("python%d.%d" % v) else: log.warn( 'dependency on python%s (from shebang) ignored' ' - it\'s not supported anymore', vrepr(v)) # /usr/bin/python shebang → add python to Depends if any(True for i, v in details.get('shebangs', []) if v is None): self.depend('python') if details.get('compile', False): self.depend(MINPYCDEP) args = '' vr = options.vrange if len(versions) == 1: # only one version from shebang args += "-V %s" % vrepr(versions[0]) elif vr: # if there are no hardcoded versions in shebang or there # are scripts for different Python versions: compile with # default Python version (or the one requested via X-P-V) args += "-V %s" % vrange_str(vr) if vr[0]: # minimum version specified self.depend("python (>= %s)" % vrepr(vr[0])) if vr[1]: # maximum version specified self.depend("python (<< %s)" % vrepr(vr[1])) for pattern in options.regexpr or []: args += " -X '%s'" % pattern.replace("'", r"'\''") self.rtscript((private_dir, args)) if options.guess_deps: for fn in stats['requires.txt']: # TODO: should options.recommends and options.suggests be # removed from requires.txt? for i in parse_pydep(fn): self.depend(i) # add dependencies from --depends for item in options.depends or []: self.depend(guess_dependency(item)) # add dependencies from --recommends for item in options.recommends or []: self.recommend(guess_dependency(item)) # add dependencies from --suggests for item in options.suggests or []: self.suggest(guess_dependency(item)) log.debug(self)
def parse(self, stats, options): log.debug('generating dependencies for package %s', self.package) pub_vers = sorted(stats['public_vers'].union(stats['ext'])) if pub_vers: dbgpkg = self.package.endswith('-dbg') tpl = 'python-dbg' if dbgpkg else 'python' minv = pub_vers[0] maxv = pub_vers[-1] # generating "python2.X | python2.Y | python2.Z" dependencies # disabled (see #625740): #if dbgpkg: # tpl2 = 'python%d.%d-dbg' #else: # tpl2 = 'python%d.%d' #self.depend(' | '.join(tpl2 % i for i in debsorted(pub_vers))) # additional Depends to block python package transitions if minv <= DEFAULT: self.depend("%s (>= %d.%d)" % \ (tpl, minv[0], minv[1])) if maxv >= DEFAULT: self.depend("%s (<< %d.%d)" % \ (tpl, maxv[0], maxv[1] + 1)) # make sure pycompile binary is available if stats['compile']: self.depend(MINPYCDEP) for interpreter, version in stats['shebangs']: self.depend("%s:any" % interpreter) for private_dir, details in stats['private_dirs'].iteritems(): versions = list(v for i, v in details.get('shebangs', []) if v) for v in versions: if v in SUPPORTED: self.depend("python%d.%d:any" % v) else: log.info('dependency on python%s (from shebang) ignored' ' - it\'s not supported anymore', vrepr(v)) # /usr/bin/python shebang → add python to Depends if any(True for i, v in details.get('shebangs', []) if v is None): self.depend('python:any') if details.get('compile', False): self.depend(MINPYCDEP) args = '' vr = options.vrange if len(versions) == 1: # only one version from shebang args += "-V %s" % vrepr(versions[0]) elif vr: # if there are no hardcoded versions in shebang or there # are scripts for different Python versions: compile with # default Python version (or the one requested via X-P-V) args += "-V %s" % vrange_str(vr) if vr == (None, None): pass elif vr[0] == vr[1]: self.depend("python%s:any" % vrepr(vr[0])) else: if vr[0]: # minimum version specified self.depend("python:any (>= %s)" % vrepr(vr[0])) if vr[1]: # maximum version specified self.depend("python:any (<< %d.%d)" % \ (vr[1][0], vr[1][1] + 1)) for pattern in options.regexpr or []: args += " -X '%s'" % pattern.replace("'", r"'\''") self.rtscript((private_dir, args)) if options.guess_deps: for fn in stats['requires.txt']: # TODO: should options.recommends and options.suggests be # removed from requires.txt? for i in parse_pydep(fn): self.depend(i) # add dependencies from --depends for item in options.depends or []: self.depend(guess_dependency(item)) # add dependencies from --recommends for item in options.recommends or []: self.recommend(guess_dependency(item)) # add dependencies from --suggests for item in options.suggests or []: self.suggest(guess_dependency(item)) log.debug(self)
def parse(self, stats, options): log.debug("generating dependencies for package %s", self.package) pub_vers = sorted(stats["public_vers"].union(stats["ext"])) if pub_vers: dbgpkg = self.package.endswith("-dbg") tpl = "python-dbg" if dbgpkg else "python" minv = pub_vers[0] maxv = pub_vers[-1] if dbgpkg: tpl2 = "python%d.%d-dbg" else: tpl2 = "python%d.%d" self.depend(" | ".join(tpl2 % i for i in debsorted(pub_vers))) # additional Depends to block python package transitions if minv <= DEFAULT: self.depend("%s (>= %d.%d)" % (tpl, minv[0], minv[1])) if maxv >= DEFAULT: self.depend("%s (<< %d.%d)" % (tpl, maxv[0], maxv[1] + 1)) # make sure pycompile binary is available if stats["compile"]: self.depend(MINPYCDEP) if not options.ignore_shebangs: for interpreter, version in stats["shebangs"]: self.depend(interpreter) for private_dir, details in stats["private_dirs"].iteritems(): if options.ignore_shebangs: versions = [] else: versions = list(v for i, v in details.get("shebangs", []) if v) for v in versions: if v in SUPPORTED: self.depend("python%d.%d" % v) else: log.warn("dependency on python%s (from shebang) ignored" " - it's not supported anymore", vrepr(v)) # /usr/bin/python shebang → add python to Depends if any(True for i, v in details.get("shebangs", []) if v is None): self.depend("python") if details.get("compile", False): self.depend(MINPYCDEP) args = "" vr = options.vrange if len(versions) == 1: # only one version from shebang args += "-V %s" % vrepr(versions[0]) elif vr: # if there are no hardcoded versions in shebang or there # are scripts for different Python versions: compile with # default Python version (or the one requested via X-P-V) args += "-V %s" % vrange_str(vr) if vr[0] == vr[1]: self.depend("python%s" % vrepr(vr[0])) else: if vr[0]: # minimum version specified self.depend("python (>= %s)" % vrepr(vr[0])) if vr[1]: # maximum version specified self.depend("python (<< %s)" % vrepr((vr[1][0], int(vr[1][1]) + 1))) for pattern in options.regexpr or []: args += " -X '%s'" % pattern.replace("'", r"'\''") self.rtscript((private_dir, args)) if options.guess_deps: for fn in stats["requires.txt"]: # TODO: should options.recommends and options.suggests be # removed from requires.txt? for i in parse_pydep(fn): self.depend(i) # add dependencies from --depends for item in options.depends or []: self.depend(guess_dependency(item)) # add dependencies from --recommends for item in options.recommends or []: self.recommend(guess_dependency(item)) # add dependencies from --suggests for item in options.suggests or []: self.suggest(guess_dependency(item)) log.debug(self)
def parse(self, stats, options): log.debug('generating dependencies for package %s', self.package) pub_vers = sorted(stats['public_vers'].union(stats['public_ext'])) if pub_vers: dbgpkg = self.package.endswith('-dbg') tpl = 'python-dbg' if dbgpkg else 'python' supported = sorted(SUPPORTED) min_supp = supported[0] max_supp = supported[-1] minv = pub_vers[0] maxv = pub_vers[-1] if dbgpkg: tpl2 = 'python%d.%d-dbg' else: tpl2 = 'python%d.%d' self.depend(' | '.join(tpl2 % i for i in debsorted(pub_vers))) # additional Breaks/Depends to block python package transitions if self.use_breaks: if minv <= min_supp: self.break_("%s (<< %d.%d)" % \ (tpl, minv[0], minv[1])) if maxv >= max_supp: self.break_("%s (>= %d.%d)" % \ (tpl, maxv[0], maxv[1] + 1)) else: if minv <= DEFAULT: self.depend("%s (>= %d.%d)" % \ (tpl, minv[0], minv[1])) if maxv >= DEFAULT: self.depend("%s (<< %d.%d)" % \ (tpl, maxv[0], maxv[1] + 1)) # make sure pycompile binary is available if stats['compile']: self.depend(MINPYCDEP) for interpreter, version in stats['shebangs']: self.depend(interpreter) for private_dir, details in stats['private_dirs'].iteritems(): versions = list(v for i, v in details.get('shebangs', []) if v) if len(versions) > 1: log.error('more than one Python dependency from shebangs' '(%s shebang versions: %s)', private_dir, versions) exit(13) elif len(versions) == 1: # one hardcoded version self.depend("python%d.%d" % versions[0]) # TODO: if versions[0] not in requested_versions: FTBFS elif details.get('compile', False): # no hardcoded versions, but there's something to compile self.depend(MINPYCDEP) args = '' vr = options.vrange if vr: args += "-V %s" % vrange_str(vr) if vr[0]: # minimum version specified self.depend("python (>= %s)" % vrepr(vr[0])) if vr[1]: # maximum version specified self.depend("python (<< %s)" % vrepr(vr[1])) for pattern in options.regexpr or []: args += " -X '%s'" % pattern.replace("'", r"\'") self.rtscript((private_dir, args)) if options.guess_deps: for fn in stats['requires.txt']: # TODO: should options.recommends and options.suggests be # removed from requires.txt? for i in parse_pydep(fn): self.depend(i) # add dependencies from --depends for item in options.depends or []: self.depend(guess_dependency(item)) # add dependencies from --recommends for item in options.recommends or []: self.recommend(guess_dependency(item)) # add dependencies from --suggests for item in options.suggests or []: self.suggest(guess_dependency(item)) log.debug(self)