[Reproducible-builds] [dh-python] 22/183: move dh_python{2, 3}'s scan method into dhpython.fs.Scan class
Jérémy Bobbio
lunar at moszumanska.debian.org
Fri Sep 19 15:30:15 UTC 2014
This is an automated email from the git hooks/post-receive script.
lunar pushed a commit to branch pu/reproducible_builds
in repository dh-python.
commit 78c479a3558c5cc6d2e5f567d0c64f5d42bb9d14
Author: Piotr Ożarowski <piotr at debian.org>
Date: Mon Jul 1 22:45:12 2013 +0200
move dh_python{2,3}'s scan method into dhpython.fs.Scan class
... and make it easier to overload it (and read! :)
---
dh_python2 | 243 ++++-------------------------------------
dh_python3 | 216 +++---------------------------------
dhpython/__init__.py | 6 +-
dhpython/fs.py | 301 +++++++++++++++++++++++++++++++++++++++++++++++++--
4 files changed, 331 insertions(+), 435 deletions(-)
diff --git a/dh_python2 b/dh_python2
index 83af4cd..664b199 100755
--- a/dh_python2
+++ b/dh_python2
@@ -27,22 +27,17 @@ import re
import sys
from filecmp import dircmp, cmpfiles, cmp as fcmp
from optparse import OptionParser, SUPPRESS_HELP
-from os.path import isabs, isdir, islink, exists, join, normpath, realpath,\
- split
-from shutil import rmtree, copy as fcopy
-from stat import ST_MODE, S_IXUSR, S_IXGRP, S_IXOTH
+from os.path import isabs, isdir, islink, exists, join, normpath, realpath
+from shutil import copy as fcopy
sys.path.insert(1, '/usr/share/dh-python/')
from dhpython.debhelper import DebHelper
from dhpython.depends import Dependencies
from dhpython.interpreter import Interpreter
-from dhpython.fs import fix_locations
+from dhpython.fs import fix_locations, Scan
from dhpython.version import supported, default, VersionRange, \
get_requested_versions
from dhpython.pydist import validate as validate_pydist
-from dhpython.tools import relative_symlink,\
- fix_shebang,\
- so2pyver, clean_egg_name,\
- parse_ns, remove_ns,\
+from dhpython.tools import relative_symlink, so2pyver, parse_ns, remove_ns,\
pyinstall, pyremove
from dhpython.option import Option
@@ -55,6 +50,22 @@ DEFAULT = default('cpython2')
SUPPORTED = supported('cpython2')
+class Scanner(Scan):
+ def handle_ext(self, fpath):
+ so_version = so2pyver(fpath)
+ if so_version:
+ path, fn = fpath.rsplit('/', 1)
+ if self.current_pub_version:
+ if self.current_pub_version != so_version:
+ log.error('extension linked to libpython%s '
+ 'and shipped in python%s\'s dist-'
+ 'packages: %s',
+ so_version, self.current_pub_version, fn)
+ log.warn('public extension linked with '
+ 'libpython%s: %s', so_version, fn)
+ return so_version
+
+
### SHARING FILES ##############################################
def share(package, stats, options):
"""Move files to /usr/share/pyshared/ if possible."""
@@ -248,215 +259,6 @@ def share_2x(dir1, dir2, dc=None):
share_2x(join(dir1, dn), join(dir2, dn), dc)
-### PACKAGE DETAILS ############################################
-def scan(package, dname=None, options=None):
- """Gather statistics about Python files in given package."""
- r = {'requires.txt': set(),
- 'nsp.txt': set(),
- 'shebangs': set(),
- 'public_vers': set(),
- 'private_dirs': {},
- 'compile': False,
- 'ext': set()}
-
- dbg_package = package.endswith('-dbg')
- interpreter = Interpreter('python', debug=dbg_package)
-
- if not dname:
- proot = "debian/%s" % package
- if dname is False:
- private_to_check = []
- else:
- private_to_check = [i % package for i in
- ('usr/lib/%s', 'usr/lib/games/%s',
- 'usr/share/%s', 'usr/share/games/%s')]
- else:
- # scan private directory *only*
- dname = dname.strip('/')
- proot = join('debian', package, dname)
- private_to_check = [dname]
-
- for root, dirs, file_names in os.walk(proot):
- if interpreter.should_ignore(root):
- del dirs[:]
- continue
-
- bin_dir = private_dir = None
- version = interpreter.parse_public_version(root)
- public_dir = bool(version)
- if public_dir:
- if root.endswith('-packages'):
- r['public_vers'].add(version)
- else:
- # TODO: find a way to specify Python version private
- # extension was build for
- version = False
- for i in private_to_check:
- if root.startswith(join('debian', package, i)):
- private_dir = '/' + i
- break
- else: # i.e. not public_dir and not private_dir
- if len(root.split('/', 6)) < 6 and \
- root.endswith(('/sbin', '/bin', '/usr/games')):
- # /(s)bin or /usr/(s)bin or /usr/games
- bin_dir = root
-
- for name in dirs:
- if name == '__pycache__':
- rmtree(join(root, name))
- dirs.remove(name)
- continue
- # handle EGG related data (.egg-info dirs)
- if name.endswith('.egg-info'):
- if dbg_package and options.clean_dbg_pkg:
- rmtree(join(root, name))
- dirs.remove(name)
- continue
- clean_name = clean_egg_name(name)
- if clean_name != name:
- if exists(join(root, clean_name)):
- log.info('removing %s (%s is already available)', name, clean_name)
- rmtree(join(root, name))
- dirs[dirs.index(name)] = clean_name
- else:
- log.info('renaming %s to %s', name, clean_name)
- os.rename(join(root, name), join(root, clean_name))
- dirs[dirs.index(name)] = clean_name
- if root.endswith('.egg-info'):
- if 'requires.txt' in file_names:
- r['requires.txt'].add(join(root, 'requires.txt'))
- if 'namespace_packages.txt' in file_names:
- r['nsp.txt'].add(join(root, 'namespace_packages.txt'))
- if 'SOURCES.txt' in file_names:
- file_names.remove('SOURCES.txt')
- os.remove(join(root, 'SOURCES.txt'))
- continue
-
- # check files
- for fn in sorted(file_names):
- # sorted() to make sure .so files are handled before .so.foo
- fpath = join(root, fn)
- if not exists(fpath):
- # could be removed while handling .so symlinks
- if islink(fpath) and '.so.' in split(fpath)[-1]:
- # dangling symlink to (now removed/renamed) .so file
- # which wasn't removed yet (see test3's quux.so.0)
- log.info('removing symlink: %s', fpath)
- os.remove(fpath)
- continue
- fext = fn.rsplit('.', 1)[-1]
- if fext in ('pyc', 'pyo'):
- os.remove(fpath)
- continue
- if public_dir:
- if fext == 'so' and islink(fpath):
- dstfpath = fpath
- links = set()
- while islink(dstfpath):
- links.add(dstfpath)
- dstfpath = join(root, os.readlink(dstfpath))
- if exists(dstfpath) and '.so.' in split(dstfpath)[-1]:
- # rename .so.$FOO symlinks, remove other ones
- for lpath in links:
- log.info('removing symlink: %s', lpath)
- os.remove(lpath)
- log.info('renaming %s to %s', dstfpath, fn)
- os.rename(dstfpath, fpath)
- if dbg_package and options.clean_dbg_pkg and \
- fext not in ('so', 'h'):
- os.remove(join(root, fn))
- continue
- # assume all extensions were build for cPython
- if fext == 'so':
- new_fn = interpreter.check_extname(fn, version)
- if new_fn:
- new_fpath = join(root, new_fn)
- if exists(new_fpath):
- log.warn('destination file exist, '
- 'cannot rename %s to %s', fn, new_fn)
- else:
- log.warn('renaming %s to %s', fn, new_fn)
- os.rename(fpath, new_fpath)
-
- elif private_dir:
- if exists(fpath) and fext != 'so':
- mode = os.stat(fpath)[ST_MODE]
- if mode & S_IXUSR or mode & S_IXGRP or mode & S_IXOTH:
- if (options.no_shebang_rewrite or
- fix_shebang(fpath, options.shebang)) and \
- not options.ignore_shebangs:
- try:
- res = Interpreter.from_file(fpath)
- except Exception as e:
- log.debug('cannot parse shebang %s: %s', fpath, e)
- else:
- r['private_dirs'].setdefault(private_dir, {})\
- .setdefault('shebangs', set()).add(res)
-
- if public_dir or private_dir:
- if fext == 'so':
- so_version = so2pyver(join(root, fn))
- if so_version:
- if public_dir:
- if version != so_version:
- log.error('extension linked to libpython%s '
- 'and shipped in python%s\'s dist-'
- 'packages: %s',
- so_version, version, fn)
- exit(7)
- log.warn('public extension linked with '
- 'libpython%s: %s', so_version, fn)
- elif not version:
- version = so_version
-
- (r if public_dir else
- r['private_dirs'].setdefault(private_dir, {}))\
- .setdefault('ext', set()).add(version)
- continue
- elif fext == 'py':
- (r if public_dir else
- r['private_dirs'].setdefault(private_dir, {})
- )['compile'] = True
- continue
-
- # .egg-info files
- if fn.endswith('.egg-info'):
- clean_name = clean_egg_name(fn)
- if clean_name != fn:
- if exists(join(root, clean_name)):
- log.info('removing %s (%s is already available)',
- fn, clean_name)
- os.remove(join(root, fn))
- else:
- log.info('renaming %s to %s', fn, clean_name)
- os.rename(join(root, fn), join(root, clean_name))
- continue
- # search for scripts in bin dirs
- if bin_dir:
- if (options.no_shebang_rewrite or
- fix_shebang(fpath, options.shebang)) and \
- not options.ignore_shebangs:
- try:
- res = Interpreter.from_file(fpath)
- except Exception as e:
- log.debug('cannot parse shebang %s: %s', fpath, e)
- else:
- r['shebangs'].add(res)
-
- if dbg_package and options.clean_dbg_pkg:
- # remove empty directories in -dbg packages
- proot = proot + '/usr/lib'
- for root, dirs, file_names in os.walk(proot, topdown=False):
- if '-packages/' in root and not file_names:
- try:
- os.rmdir(root)
- except Exception:
- pass
-
- log.debug("package %s details = %s", package, r)
- return r
-
-
################################################################
def main():
usage = '%prog -p PACKAGE [-V [X.Y][-][A.B]] DIR [-X REGEXPR]\n'
@@ -605,14 +407,13 @@ def main():
log.error("%s.pyremove: %s", package, err)
exit(5)
fix_locations(package, interpreter, SUPPORTED)
- stats = scan(package, private_dir, options)
+ stats = Scanner(interpreter, package, private_dir, options).result
if not private_dir:
share(package, stats, options)
pyshared_dir = "debian/%s/usr/share/pyshared/" % package
if not stats['public_vers'] and exists(pyshared_dir):
create_public_links(pyshared_dir, options.vrange)
- stats['public_vers'] = get_requested_versions('cpython2', options.vrange)
- stats['compile'] = True
+ stats = Scanner(interpreter, package, private_dir, options).result
dependencies = Dependencies(package, 'cpython2')
dependencies.parse(stats, options)
diff --git a/dh_python3 b/dh_python3
index 0c829c6..3a06b2c 100755
--- a/dh_python3
+++ b/dh_python3
@@ -26,17 +26,15 @@ import os
import re
import sys
from optparse import OptionParser, SUPPRESS_HELP
-from os.path import islink, exists, join, split
-from shutil import rmtree, copy as fcopy
-from stat import ST_MODE, S_IXUSR, S_IXGRP, S_IXOTH
+from os.path import exists, join
+from shutil import copy as fcopy
sys.path.insert(1, '/usr/share/dh-python/')
from dhpython.debhelper import DebHelper
from dhpython.depends import Dependencies
from dhpython.interpreter import Interpreter, EXTFILE_RE
from dhpython.version import supported, default, Version, VersionRange
from dhpython.pydist import validate as validate_pydist
-from dhpython.fs import fix_locations
-from dhpython.tools import fix_shebang, clean_egg_name
+from dhpython.fs import fix_locations, Scan
from dhpython.option import Option
# initialize script
@@ -48,201 +46,21 @@ DEFAULT = default('cpython3')
SUPPORTED = supported('cpython3')
-### PACKAGE DETAILS ############################################
-def scan(package, dname=None, options=None):
- """Gather statistics about Python files in given package."""
- r = {'requires.txt': set(),
- 'shebangs': set(),
- 'private_dirs': {},
- 'compile': False,
- 'ext': set()}
+class Scanner(Scan):
+ def handle_ext(self, fpath):
+ path, fname = fpath.rsplit('/', 1)
+ tagver = EXTFILE_RE.search(fname)
+ if tagver is None:
+ # yeah, python3.1 is not covered, but we don't want to
+ # mess with non-Python libraries, don't we?
+ return
+ tagver = tagver.groupdict()['ver']
+ if tagver is None:
+ return
+ tagver = Version("%s.%s" % (tagver[0], tagver[1]))
+ return tagver
- dbg_package = package.endswith('-dbg')
- interpreter = Interpreter('python', impl='cpython3', debug=dbg_package)
- if not dname:
- proot = "debian/%s" % package
- if dname is False:
- private_to_check = []
- else:
- private_to_check = [i % package for i in
- ('usr/lib/%s', 'usr/lib/games/%s',
- 'usr/share/%s', 'usr/share/games/%s')]
- else:
- # scan private directory *only*
- dname = dname.strip('/')
- proot = join('debian', package, dname)
- private_to_check = [dname]
-
- for root, dirs, file_names in os.walk(proot):
- if interpreter.should_ignore(root):
- del dirs[:]
- continue
-
- bin_dir = private_dir = None
- version = interpreter.parse_public_version(root)
- public_dir = bool(version)
- if not public_dir:
- for i in private_to_check:
- if root.startswith(join('debian', package, i)):
- private_dir = '/' + i
- break
- else: # i.e. not public_dir and not private_dir
- if len(root.split('/', 6)) < 6 and \
- root.endswith(('/sbin', '/bin', '/usr/games')):
- # /(s)bin or /usr/(s)bin or /usr/games
- bin_dir = root
-
- for name in dirs:
- if name == '__pycache__':
- rmtree(join(root, name))
- dirs.remove(name)
- continue
- # handle EGG related data (.egg-info dirs)
- if name.endswith('.egg-info'):
- if dbg_package and options.clean_dbg_pkg:
- rmtree(join(root, name))
- dirs.remove(name)
- continue
- clean_name = clean_egg_name(name)
- if clean_name != name:
- if exists(join(root, clean_name)):
- log.info('removing %s (%s is already available)', name, clean_name)
- rmtree(join(root, name))
- dirs[dirs.index(name)] = clean_name
- else:
- log.info('renaming %s to %s', name, clean_name)
- os.rename(join(root, name), join(root, clean_name))
- dirs[dirs.index(name)] = clean_name
- if root.endswith('.egg-info'):
- if 'requires.txt' in file_names:
- r['requires.txt'].add(join(root, 'requires.txt'))
- if 'SOURCES.txt' in file_names:
- file_names.remove('SOURCES.txt')
- os.remove(join(root, 'SOURCES.txt'))
- continue
-
- # check files
- for fn in sorted(file_names):
- # sorted() to make sure .so files are handled before .so.foo
- fpath = join(root, fn)
- if not exists(fpath):
- # could be removed while handling .so symlinks
- if islink(fpath) and '.so.' in split(fpath)[-1]:
- # dangling symlink to (now removed/renamed) .so file
- # which wasn't removed yet (see test3's quux.so.0)
- log.info('removing symlink: %s', fpath)
- os.remove(fpath)
- continue
- fext = fn.rsplit('.', 1)[-1]
- if fext in ('pyc', 'pyo'):
- os.remove(fpath)
- continue
- if public_dir:
- if fext == 'so' and islink(fpath):
- dstfpath = fpath
- links = set()
- while islink(dstfpath):
- links.add(dstfpath)
- dstfpath = join(root, os.readlink(dstfpath))
- if exists(dstfpath) and '.so.' in split(dstfpath)[-1]:
- # rename .so.$FOO symlinks, remove other ones
- for lpath in links:
- log.info('removing symlink: %s', lpath)
- os.remove(lpath)
- log.info('renaming %s to %s', dstfpath, fn)
- os.rename(dstfpath, fpath)
- if dbg_package and options.clean_dbg_pkg and \
- fext not in ('so', 'h'):
- os.remove(join(root, fn))
- continue
- # assume all extensions were build for cPython
- if fext == 'so':
- new_fn = interpreter.check_extname(fn, version)
- if new_fn:
- new_fpath = join(root, new_fn)
- if exists(new_fpath):
- log.warn('destination file exist, '
- 'cannot rename %s to %s', fn, new_fn)
- else:
- log.warn('renaming %s to %s', fn, new_fn)
- os.rename(fpath, new_fpath)
-
- elif private_dir:
- if exists(fpath) and fext != 'so':
- mode = os.stat(fpath)[ST_MODE]
- if mode & S_IXUSR or mode & S_IXGRP or mode & S_IXOTH:
- if (options.no_shebang_rewrite or
- fix_shebang(fpath, options.shebang)) and \
- not options.ignore_shebangs:
- try:
- res = Interpreter.from_file(fpath)
- except Exception as e:
- log.debug('cannot parse shebang %s: %s', fpath, e)
- else:
- r['private_dirs'].setdefault(private_dir, {})\
- .setdefault('shebangs', set()).add(res)
-
- if public_dir or private_dir:
- if fext == 'so':
- tagver = EXTFILE_RE.search(fn)
- if tagver is None:
- # yeah, python3.1 is not covered, but we don't want to
- # mess with non-Python libraries, don't we?
- continue
- tagver = tagver.groupdict()['ver']
- if tagver is None:
- continue
- tagver = Version("%s.%s" % (tagver[0], tagver[1]))
- (r if public_dir else
- r['private_dirs'].setdefault(private_dir, {}))\
- .setdefault('ext', set()).add(tagver)
- continue
- elif fext == 'py':
- (r if public_dir else
- r['private_dirs'].setdefault(private_dir, {})
- )['compile'] = True
- continue
-
- # .egg-info files
- if fn.endswith('.egg-info'):
- clean_name = clean_egg_name(fn)
- if clean_name != fn:
- if exists(join(root, clean_name)):
- log.info('removing %s (%s is already available)',
- fn, clean_name)
- os.remove(join(root, fn))
- else:
- log.info('renaming %s to %s', fn, clean_name)
- os.rename(join(root, fn), join(root, clean_name))
- continue
- # search for scripts in bin dirs
- if bin_dir:
- if (options.no_shebang_rewrite or
- fix_shebang(fpath, options.shebang)) and \
- not options.ignore_shebangs:
- try:
- res = Interpreter.from_file(fpath)
- except Exception as e:
- log.debug('cannot parse shebang %s: %s', fpath, e)
- else:
- r['shebangs'].add(res)
-
- if dbg_package and options.clean_dbg_pkg:
- # remove empty directories in -dbg packages
- proot = proot + '/usr/lib'
- for root, dirs, file_names in os.walk(proot, topdown=False):
- if '-packages/' in root and not file_names:
- try:
- os.rmdir(root)
- except Exception:
- pass
-
- log.debug("package %s details = %s", package, r)
- return r
-
-
-################################################################
def main():
usage = '%prog -p PACKAGE [-V [X.Y][-][A.B]] DIR [-X REGEXPR]\n'
parser = OptionParser(usage, version='%prog DEVELV', option_class=Option)
@@ -349,7 +167,7 @@ def main():
if not private_dir:
fix_locations(package, interpreter, SUPPORTED)
- stats = scan(package, private_dir, options)
+ stats = Scanner(interpreter, package, private_dir, options).result
dependencies = Dependencies(package, 'cpython3')
dependencies.parse(stats, options)
diff --git a/dhpython/__init__.py b/dhpython/__init__.py
index cd6bcf5..39fa8b7 100644
--- a/dhpython/__init__.py
+++ b/dhpython/__init__.py
@@ -30,9 +30,9 @@ MINPYCDEP = {'cpython2': 'python (>= 2.6.6-3)',
'pypy': 'pypy'}
PUBLIC_DIR_RE = {
- 'cpython2': re.compile(r'.*?/usr/lib/python(2\.\d)/(site|dist)-packages'),
- 'cpython3': re.compile(r'.*?/usr/lib/python(3(?:\.\d+)?)/dist-packages'),
- 'pypy': re.compile(r'.*?/usr/lib/pypy/dist-packages')}
+ 'cpython2': re.compile(r'.*?/usr/lib/python(2\.\d)(?:/|$)'),
+ 'cpython3': re.compile(r'.*?/usr/lib/python(3(?:\.\d+)?)(?:/|$)'),
+ 'pypy': re.compile(r'.*?/usr/lib/pypy(?:/|$)')}
INTERPRETER_DIR_TPLS = {
'cpython2': r'.*/python2\.\d/',
diff --git a/dhpython/fs.py b/dhpython/fs.py
index b7ddf86..05b9bb2 100644
--- a/dhpython/fs.py
+++ b/dhpython/fs.py
@@ -19,9 +19,14 @@
# THE SOFTWARE.
import logging
+import os
+import re
from filecmp import cmp as cmpfile
-from os import listdir, remove, renames, rmdir
-from os.path import exists, isdir, join
+from os.path import exists, isdir, islink, join, split
+from shutil import rmtree
+from stat import ST_MODE, S_IXUSR, S_IXGRP, S_IXOTH
+from dhpython.tools import fix_shebang, clean_egg_name
+from dhpython.interpreter import Interpreter
log = logging.getLogger('dhpython')
@@ -38,8 +43,8 @@ def fix_locations(package, interpreter, versions):
log.debug('moving files from %s to %s', srcdir, dstdir)
share_files(srcdir, dstdir, interpreter)
parent_dir = '/'.join(srcdir.split('/')[:-1])
- if exists(parent_dir) and not listdir(parent_dir):
- rmdir(parent_dir)
+ if exists(parent_dir) and not os.listdir(parent_dir):
+ os.rmdir(parent_dir)
# do the same with debug locations
dstdir = interpreter.sitedir(package, gdb=True)
@@ -48,13 +53,13 @@ def fix_locations(package, interpreter, versions):
log.debug('moving files from %s to %s', srcdir, dstdir)
share_files(srcdir, dstdir, interpreter)
parent_dir = '/'.join(srcdir.split('/')[:-1])
- if exists(parent_dir) and not listdir(parent_dir):
- rmdir(parent_dir)
+ if exists(parent_dir) and not os.listdir(parent_dir):
+ os.rmdir(parent_dir)
def share_files(srcdir, dstdir, interpreter):
"""Try to move as many files from srcdir to dstdir as possible."""
- for i in listdir(srcdir):
+ for i in os.listdir(srcdir):
fpath1 = join(srcdir, i)
if i.rsplit('.', 1)[-1] == 'so':
# try to rename extension here as well (in :meth:`scan` info about
@@ -71,18 +76,290 @@ def share_files(srcdir, dstdir, interpreter):
'cannot rename %s to %s', fpath1_orig, fpath1)
else:
log.warn('renaming %s to %s', fpath1_orig, fpath1)
- renames(fpath1_orig, fpath1)
+ os.renames(fpath1_orig, fpath1)
fpath2 = join(dstdir, i)
if not exists(fpath2):
- renames(fpath1, fpath2)
+ os.renames(fpath1, fpath2)
continue
if isdir(fpath1):
share_files(fpath1, fpath2, interpreter)
elif cmpfile(fpath1, fpath2, shallow=False):
- remove(fpath1)
+ os.remove(fpath1)
# XXX: check symlinks
- if exists(srcdir) and not listdir(srcdir):
- rmdir(srcdir)
+ if exists(srcdir) and not os.listdir(srcdir):
+ os.rmdir(srcdir)
+class Scan:
+ UNWANTED_DIRS = re.compile('.*/__pycache__/.*')
+ UNWANTED_FILES = re.compile('.*\.py[co]')
+
+ def __init__(self, interpreter, package, dpath=None, options=None):
+ self.interpreter = interpreter
+ self.impl = interpreter.impl
+
+ self.package = package
+
+ if not dpath:
+ self.proot = "debian/%s" % self.package
+ else:
+ dpath = dpath.strip('/')
+ self.proot = join('debian', self.package, dpath)
+ self.dpath = dpath
+ del dpath
+
+ self.options = options
+ self.result = {'requires.txt': set(),
+ 'nsp.txt': set(),
+ 'shebangs': set(),
+ 'public_vers': set(),
+ 'private_dirs': {},
+ 'compile': False,
+ 'ext_vers': set()}
+
+ for root, dirs, file_names in os.walk(self.proot):
+ if interpreter.should_ignore(root):
+ del dirs[:]
+ continue
+
+ self.current_private_dir = None
+ self.current_pub_version = version = interpreter.parse_public_version(root)
+ if self.current_pub_version: # i.e. a public site-packages directory
+ if root.endswith('-packages'):
+ self.result['public_vers'].add(version)
+ else:
+ self.current_private_dir = self.check_private_dir(root)
+ if not self.current_private_dir:
+ # i.e. not a public dir and not a private dir
+ is_bin_dir = self.is_bin_dir(root)
+ if is_bin_dir:
+ self.handle_bin_dir(root, file_names)
+ else: # not a public, private or bin directory
+ # continue with a subdirectory
+ continue
+
+ for name in dirs:
+ dpath = join(root, name)
+ if self.is_unwanted_dir(dpath):
+ rmtree(dpath)
+ dirs.remove(name)
+ continue
+
+ if self.is_egg_dir(root):
+ self.handle_egg_dir(root, file_names)
+ continue
+
+ # check files
+ for fn in sorted(file_names):
+ # sorted() to make sure .so files are handled before .so.foo
+ fpath = join(root, fn)
+
+ if self.is_unwanted_file(fpath):
+ log.debug('removing unwanted: %s', fpath)
+ os.remove(fpath)
+ continue
+
+ if self.is_egg_file(fpath):
+ self.handle_egg_file(fpath)
+ continue
+
+ if not exists(fpath):
+ # possibly removed while handling .so symlinks
+ if islink(fpath) and '.so.' in split(fpath)[-1]:
+ # dangling symlink to (now removed/renamed) .so file
+ # which wasn't removed yet (see test203's quux.so.0)
+ log.info('removing dangling symlink: %s', fpath)
+ os.remove(fpath)
+ continue
+
+ fext = fn.rsplit('.', 1)[-1]
+ if fext == 'so':
+ fpath = self.rename_ext(fpath)
+ ver = self.handle_ext(fpath)
+ if ver:
+ self.current_result.setdefault('ext_vers', set()).add(ver)
+ else:
+ self.current_result.setdefault('ext_no_version', set()).add(fpath)
+
+ if self.current_private_dir:
+ if exists(fpath) and fext != 'so':
+ mode = os.stat(fpath)[ST_MODE]
+ if mode & S_IXUSR or mode & S_IXGRP or mode & S_IXOTH:
+ if (options.no_shebang_rewrite or
+ fix_shebang(fpath, self.options.shebang)) and \
+ not self.options.ignore_shebangs:
+ try:
+ res = Interpreter.from_file(fpath)
+ except Exception as e:
+ log.debug('cannot parse shebang %s: %s', fpath, e)
+ else:
+ self.current_result.setdefault('shebangs', set()).add(res)
+
+ if fext == 'py' and self.handle_public_module(fpath) is not False:
+ self.current_result['compile'] = True
+
+ log.debug("package %s details = %s", package, self.result)
+
+ @property
+ def current_result(self):
+ if self.current_private_dir:
+ return self.result['private_dirs'].setdefault(self.current_private_dir, {})
+ return self.result
+
+ def is_unwanted_dir(self, dpath):
+ return self.__class__.UNWANTED_DIRS.match(dpath)
+
+ def is_unwanted_file(self, fpath):
+ if self.__class__.UNWANTED_FILES.match(fpath):
+ return True
+ if self.current_pub_version and self.is_dbg_package\
+ and self.options.clean_dbg_pkg\
+ and fpath.rsplit('.', 1)[1] not in ('so', 'h'):
+ return True
+
+ @property
+ def private_dirs_to_check(self):
+ if self.dpath:
+ # scan private directory *only*
+ return [self.dpath]
+
+ if self.dpath is False:
+ result = []
+ else:
+ result = [i % self.package for i in (
+ 'usr/lib/%s',
+ 'usr/lib/games/%s',
+ 'usr/share/%s',
+ 'usr/share/games/%s')]
+ return result
+
+ @property
+ def is_dbg_package(self):
+ #return self.interpreter.debug
+ return self.package.endswith('-dbg')
+
+ def check_private_dir(self, dpath):
+ """Return private dir's root if it's a private dir."""
+ for i in self.private_dirs_to_check:
+ if dpath.startswith(join('debian', self.package, i)):
+ return '/' + i
+
+ def rename_ext(self, fpath):
+ """Add multiarch triplet, etc. Return new name.
+
+ This method is invoked for all .so files in public or private directories.
+ """
+ path, fname = fpath.rsplit('/', 1)
+ if islink(fpath):
+ dstfpath = fpath
+ links = set()
+ while islink(dstfpath):
+ links.add(dstfpath)
+ dstfpath = join(path, os.readlink(dstfpath))
+ if exists(dstfpath) and '.so.' in split(dstfpath)[-1]:
+ # rename .so.$FOO symlinks, remove other ones
+ for lpath in links:
+ log.info('removing symlink: %s', lpath)
+ os.remove(lpath)
+ log.info('renaming %s to %s', dstfpath, fname)
+ os.rename(dstfpath, fpath)
+
+ new_fn = self.interpreter.check_extname(fname, self.current_pub_version)
+ if new_fn:
+ # TODO: what about symlinks pointing to this file
+ new_fpath = join(path, new_fn)
+ if exists(new_fpath):
+ log.warn('destination file exist, '
+ 'cannot rename %s to %s', fname, new_fn)
+ else:
+ log.warn('renaming %s to %s', fname, new_fn)
+ os.rename(fpath, new_fpath)
+ return new_fpath
+ return fpath
+
+ def handle_ext(self, fpath):
+ """Handle .so file, return its version if detected."""
+
+ def handle_public_module(self, fpath):
+ pass
+
+ def is_bin_dir(self, dpath):
+ """Check if dir is one from PATH ones."""
+ # dname = debian/packagename/usr/games
+ spath = dpath.strip('/').split('/', 4)
+ if len(spath) > 4:
+ return False # assume bin directories don't have subdirectories
+ if dpath.endswith(('/sbin', '/bin', '/usr/games')):
+ # /(s)bin or /usr/(s)bin or /usr/games
+ return True
+
+ def handle_bin_dir(self, dpath, file_names):
+ if self.options.no_shebang_rewrite or self.options.ignore_shebangs:
+ return
+ for fn in file_names:
+ fpath = join(dpath, fn)
+ if fix_shebang(fpath, self.options.shebang):
+ try:
+ res = Interpreter.from_file(fpath)
+ except Exception as e:
+ log.debug('cannot parse shebang %s: %s', fpath, e)
+ else:
+ self.result['shebangs'].add(res)
+
+ def is_egg_dir(self, dname):
+ """Check if given directory contains egg-info."""
+ return dname.endswith('.egg-info')
+
+ def handle_egg_dir(self, dpath, file_names):
+ path, dname = dpath.rsplit('/', 1)
+ if self.is_dbg_package and self.options.clean_dbg_pkg:
+ rmtree(dpath)
+ return
+
+ clean_name = clean_egg_name(dname)
+ if clean_name != dname:
+ if exists(join(path, clean_name)):
+ log.info('removing %s (%s is already available)', dname, clean_name)
+ rmtree(dpath)
+ return
+ else:
+ log.info('renaming %s to %s', dname, clean_name)
+ os.rename(dpath, join(path, clean_name))
+ dname = clean_name
+ dpath = join(path, dname)
+ if file_names:
+ if 'requires.txt' in file_names:
+ self.result['requires.txt'].add(join(dpath, 'requires.txt'))
+ if 'namespace_packages.txt' in file_names:
+ self.result['nsp.txt'].add(join(dpath, 'namespace_packages.txt'))
+ if 'SOURCES.txt' in file_names:
+ os.remove(join(dpath, 'SOURCES.txt'))
+ file_names.remove('SOURCES.txt')
+
+ def is_egg_file(self, fpath):
+ """Check if given file contains egg-info."""
+ return fpath.endswith('.egg-info')
+
+ def handle_egg_file(self, fpath):
+ root, name = fpath.rsplit('/', 1)
+ clean_name = clean_egg_name(name)
+ if clean_name != name:
+ if exists(join(root, clean_name)):
+ log.info('removing %s (%s is already available)',
+ name, clean_name)
+ os.remove(fpath)
+ else:
+ log.info('renaming %s to %s', name, clean_name)
+ os.rename(fpath, join(root, clean_name))
+
+ def cleanup(self):
+ if self.is_dbg_package and self.options.clean_dbg_pkg:
+ # remove empty directories in -dbg packages
+ proot = self.proot + '/usr/lib'
+ for root, dirs, file_names in os.walk(proot, topdown=False):
+ if '-packages/' in root and not file_names:
+ try:
+ os.rmdir(root)
+ except Exception:
+ pass
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/reproducible/dh-python.git
More information about the Reproducible-builds
mailing list