Server IP : 85.214.239.14 / Your IP : 3.144.4.50 Web Server : Apache/2.4.62 (Debian) System : Linux h2886529.stratoserver.net 4.9.0 #1 SMP Tue Jan 9 19:45:01 MSK 2024 x86_64 User : www-data ( 33) PHP Version : 7.4.18 Disable Function : pcntl_alarm,pcntl_fork,pcntl_waitpid,pcntl_wait,pcntl_wifexited,pcntl_wifstopped,pcntl_wifsignaled,pcntl_wifcontinued,pcntl_wexitstatus,pcntl_wtermsig,pcntl_wstopsig,pcntl_signal,pcntl_signal_get_handler,pcntl_signal_dispatch,pcntl_get_last_error,pcntl_strerror,pcntl_sigprocmask,pcntl_sigwaitinfo,pcntl_sigtimedwait,pcntl_exec,pcntl_getpriority,pcntl_setpriority,pcntl_async_signals,pcntl_unshare, MySQL : OFF | cURL : OFF | WGET : ON | Perl : ON | Python : ON | Sudo : ON | Pkexec : OFF Directory : /proc/2/task/2/cwd/usr/share/python/debpython/ |
Upload File : |
# -*- coding: UTF-8 -*- # Copyright © 2010-2012 Piotr Ożarowski <piotr@debian.org> # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. from __future__ import with_statement import logging import os import re from os.path import exists, isdir, join from string import maketrans from subprocess import PIPE, Popen from debpython.version import vrepr, getver, get_requested_versions from debpython.tools import memoize log = logging.getLogger(__name__) PUBLIC_DIR_RE = re.compile(r'.*?/usr/lib/python(\d.\d+)/(site|dist)-packages') PYDIST_RE = re.compile(r""" (?P<name>[A-Za-z][A-Za-z0-9_.\-]*) # Python distribution name \s* (?P<vrange>(?:-?\d\.\d+(?:-(?:\d\.\d+)?)?)?) # version range \s* (?P<dependency>(?:[a-z][^;]*)?) # Debian dependency (?: # optional upstream version -> Debian version translator ;\s* (?P<standard>PEP386)? # PEP-386 mode \s* (?P<rules>(?:s|tr|y).*)? # translator rules )? """, re.VERBOSE) REQUIRES_RE = re.compile(r''' (?P<name>[A-Za-z][A-Za-z0-9_.]*) # Python distribution name \s* (?P<enabled_extras>(?:\[[^\]]*\])?) # ignored for now \s* (?: # optional minimum/maximum version (?P<operator><=?|>=?|==|!=) \s* (?P<version>(\w|[-.])+) )? ''', re.VERBOSE) def validate(fpath): """Check if pydist file looks good.""" with open(fpath) as fp: for line in fp: line = line.strip('\r\n') if line.startswith('#') or not line: continue if not PYDIST_RE.match(line): log.error('invalid pydist data in file %s: %s', \ fpath.rsplit('/', 1)[-1], line) return False return True @memoize def load(dname='/usr/share/python/dist/', fname='debian/pydist-overrides', fbname='/usr/share/python/dist_fallback'): """Load iformation about installed Python distributions.""" if exists(fname): to_check = [fname] # first one! else: to_check = [] if isdir(dname): to_check.extend(join(dname, i) for i in os.listdir(dname)) if exists(fbname): # fall back generated at python-defaults build time to_check.append(fbname) # last one! result = {} for fpath in to_check: with open(fpath) as fp: for line in fp: line = line.strip('\r\n') if line.startswith('#') or not line: continue dist = PYDIST_RE.search(line) if not dist: raise Exception('invalid pydist line: %s (in %s)' % (line, fpath)) dist = dist.groupdict() name = safe_name(dist['name']) dist['versions'] = get_requested_versions(dist['vrange']) dist['dependency'] = dist['dependency'].strip() if dist['rules']: dist['rules'] = dist['rules'].split(';') else: dist['rules'] = [] result.setdefault(name, []).append(dist) return result 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 parse_pydep(fname): public_dir = PUBLIC_DIR_RE.match(fname) if public_dir: ver = public_dir.group(1) else: ver = None result = [] modified = optional_section = False processed = [] with open(fname, 'r') as fp: lines = [i.strip() for i in fp.readlines()] for line in lines: if not line or line.startswith('#'): processed.append(line) continue if line.startswith('['): optional_section = True if optional_section: processed.append(line) continue dependency = guess_dependency(line, ver) if dependency: result.append(dependency) if 'setuptools' in line.lower(): # TODO: or dependency in recommends\ # or dependency in suggests modified = True else: processed.append(line) else: processed.append(line) if modified: with open(fname, 'w') as fp: fp.writelines(i + '\n' for i in processed) return result def safe_name(name): """Emulate distribute's safe_name.""" return re.compile('[^A-Za-z0-9.]+').sub('_', name).lower() def sensible_pname(egg_name): """Guess Debian package name from Egg name.""" egg_name = safe_name(egg_name).replace('_', '-') if egg_name.startswith('python-'): egg_name = egg_name[7:] return "python-%s" % egg_name.lower() def ci_regexp(name): """Return case insensitive dpkg -S regexp.""" return ''.join("[%s%s]" % (i.upper(), i) if i.isalpha() else i for i in name.lower()) PRE_VER_RE = re.compile(r'[-.]?(alpha|beta|rc|dev|a|b|c)') GROUP_RE = re.compile(r'\$(\d+)') def _pl2py(pattern): """Convert Perl RE patterns used in uscan to Python's >>> print _pl2py('foo$3') foo\g<3> """ return GROUP_RE.sub(r'\\g<\1>', pattern) def _translate(version, rules, standard): """Translate Python version into Debian one. >>> _translate('1.C2betac', ['s/c//gi'], None) '1.2beta' >>> _translate('5-fooa1.2beta3-fooD', ... ['s/^/1:/', 's/-foo//g', 's:([A-Z]):+$1:'], 'PEP386') '1:5~a1.2~beta3+D' >>> _translate('x.y.x.z', ['tr/xy/ab/', 'y,z,Z,'], None) 'a.b.a.Z' """ for rule in rules: # uscan supports s, tr and y operations if rule.startswith(('tr', 'y')): # Note: no support for escaped separator in the pattern pos = 1 if rule.startswith('y') else 2 tmp = rule[pos + 1:].split(rule[pos]) version = version.translate(maketrans(tmp[0], tmp[1])) elif rule.startswith('s'): # uscan supports: g, u and x flags tmp = rule[2:].split(rule[1]) pattern = re.compile(tmp[0]) count = 1 if tmp[2:]: flags = tmp[2] if 'g' in flags: count = 0 if 'i' in flags: pattern = re.compile(tmp[0], re.I) version = pattern.sub(_pl2py(tmp[1]), version, count) else: log.warn('unknown rule ignored: %s', rule) if standard == 'PEP386': version = PRE_VER_RE.sub('~\g<1>', version) return version