Skip to content
Snippets Groups Projects
Commit a3fd40f6 authored by Piotr Ożarowski's avatar Piotr Ożarowski
Browse files

remove deprecated dh_python2

parent f1258029
No related branches found
No related tags found
2 merge requests!3Sync from Debian bullseye,!2Update from debian/bullseye for apertis/v2022dev2
Showing with 22 additions and 2094 deletions
......@@ -4,21 +4,13 @@ PREFIX ?= /usr/local
MANPAGES ?= dh_python2.1 pycompile.1 pyclean.1
clean:
make -C tests clean
make -C pydist clean
find . -name '*.py[co]' -delete
rm -f .coverage
install-dev:
$(INSTALL) -m 755 -d $(DESTDIR)$(PREFIX)/bin \
$(DESTDIR)$(PREFIX)/share/python/runtime.d \
$(DESTDIR)$(PREFIX)/share/debhelper/autoscripts/ \
$(DESTDIR)$(PREFIX)/share/perl5/Debian/Debhelper/Sequence/
$(DESTDIR)$(PREFIX)/share/python/runtime.d
$(INSTALL) -m 755 runtime.d/* $(DESTDIR)$(PREFIX)/share/python/runtime.d/
$(INSTALL) -m 644 autoscripts/* $(DESTDIR)$(PREFIX)/share/debhelper/autoscripts/
$(INSTALL) -m 755 dh_python2 $(DESTDIR)$(PREFIX)/share/python/
$(INSTALL) -m 755 dh_python2.py $(DESTDIR)$(PREFIX)/bin/dh_python2
$(INSTALL) -m 644 python2.pm $(DESTDIR)$(PREFIX)/share/perl5/Debian/Debhelper/Sequence/
install-runtime:
$(INSTALL) -m 755 -d $(DESTDIR)$(PREFIX)/share/python/debpython $(DESTDIR)$(PREFIX)/bin
......@@ -28,9 +20,6 @@ install-runtime:
install: install-dev install-runtime
dist_fallback:
make -C pydist $@
check_versions:
@set -e;\
DEFAULT=`sed -rn 's,^DEFAULT = \(([0-9]+)\, ([0-9]+)\),\1.\2,p' debpython/version.py`;\
......@@ -49,10 +38,4 @@ pdebuild:
nose:
nosetests --with-doctest --with-coverage
tests: nose
make -C tests
test%:
make -C tests $@
.PHONY: clean tests test% check_versions
if which pycompile >/dev/null 2>&1; then
pycompile -p #PACKAGE# #ARGS#
fi
# make sure python-central files are removed before new package is installed
if [ "$1" = upgrade ] && [ -f /var/lib/pycentral/#PACKAGE#.pkgremove ]
then
pycentral pkgremove #PACKAGE#
rm -f /var/lib/pycentral/#PACKAGE#.pkgremove
fi
if which pyclean >/dev/null 2>&1; then
pyclean -p #PACKAGE# #ARGS#
else
dpkg -L #PACKAGE# | grep '\.py$' | while read file
do
rm -f "${file}"[co] >/dev/null
done
fi
python-defaults (2.7.17-2) UNRELEASED; urgency=medium
* Remove deprecated dh_python2. Please add dh-python or
dh-sequence-python2 to Build-Depends if your package still supports
Python 2.X.
-- Piotr Ożarowski <piotr@debian.org> Fri, 08 Nov 2019 14:16:26 +0100
python-defaults (2.7.17-1) unstable; urgency=medium
* Bump version to 2.7.17.
......
......@@ -20,7 +20,7 @@ Pre-Depends: python-minimal (= ${binary:Version})
Depends: ${misc:Depends}, python2.7 (>= 2.7.17~rc1-1~), libpython-stdlib (= ${binary:Version}), python2 (= ${binary:Version})
Suggests: python-doc (= ${binary:Version}), python-tk (>= 2.7.17~rc1-1~)
Conflicts: python-central (<< 0.5.5)
Breaks: update-manager-core (<< 0.200.5-2)
Breaks: update-manager-core (<< 0.200.5-2), dh-python (<< 4.20191109)
Replaces: python-dev (<< 2.6.5-2)
Provides: python-email, python-ctypes, python-wsgiref, python-importlib, python-profiler
Description: interactive high-level object-oriented language (Python2 version)
......
......@@ -20,7 +20,7 @@ Pre-Depends: python-minimal (= ${binary:Version})
Depends: ${misc:Depends}, @PVER@ (>= @PREVVER@), libpython-stdlib (= ${binary:Version}), python2 (= ${binary:Version})
Suggests: python-doc (= ${binary:Version}), python-tk (>= @PREVVER@)
Conflicts: python-central (<< 0.5.5)
Breaks: update-manager-core (<< 0.200.5-2)
Breaks: update-manager-core (<< 0.200.5-2), dh-python (<< 4.20191109)
Replaces: python-dev (<< 2.6.5-2)
Provides: python-email, python-ctypes, python-wsgiref, python-importlib, python-profiler
Description: interactive high-level object-oriented language (Python2 version)
......
pydist/dist_fallback /usr/share/python/
dh_python2.1
......@@ -75,16 +75,6 @@ endif
&& rm -f debian/control.tmp && exit 0; \
mv debian/control.tmp debian/control
MANPAGES ?= dh_python2.1 pycompile.1 pyclean.1
%.1: %.rst
rst2man $< > $@
# Manually run this rule if there is a need to update the dh_python2 man pages
make-man: $(MANPAGES)
cd pydist && \
rst2html README.PyDist > README.PyDist.html
clean: control-file
dh_testdir
dh_testroot
......@@ -116,7 +106,7 @@ stamp-control:
fi; \
done
install: build stamp-dh_python stamp-install
install: build stamp-install
stamp-install: stamp-build control-file stamp-control
dh_testdir
dh_testroot
......@@ -125,18 +115,6 @@ stamp-install: stamp-build control-file stamp-control
touch stamp-install
stamp-dh_python:
dh_testdir
dh_testroot
dh_installdirs
-make check_versions
DESTDIR=debian/python2 PREFIX=/usr make install-dev
DESTDIR=debian/python2-minimal PREFIX=/usr make install-runtime
# disabled by default, run manually if you want to update it
# (requires apt-file and network connection)
#make -C pydist dist_fallback
touch $@
# Build architecture-independent files here.
binary-indep: build install
dh_testdir -i
......
# -*- 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.
import logging
from os import makedirs, chmod
from os.path import exists, join, dirname
log = logging.getLogger(__name__)
class DebHelper(object):
"""Reinvents the wheel / some dh functionality (Perl is ugly ;-P)"""
def __init__(self, options):
self.options = options
self.packages = {}
self.python_version = None
source_section = True
binary_package = None
pkgs = options.package
skip_pkgs = options.no_package
try:
fp = open('debian/control', 'r')
except IOError:
raise Exception('cannot find debian/control file')
xspv = xpv = False
for line in fp:
if not line.strip():
source_section = False
binary_package = None
continue
if binary_package:
if binary_package.startswith('python3'):
continue
if pkgs and binary_package not in pkgs:
continue
if skip_pkgs and binary_package in skip_pkgs:
continue
if line.startswith('Architecture:'):
arch = line[13:].strip()
# TODO: if arch doesn't match current architecture:
#del self.packages[binary_package]
self.packages[binary_package]['arch'] = arch
continue
elif line.startswith('Package:'):
binary_package = line[8:].strip()
if binary_package.startswith('python3'):
log.debug('skipping Python 3.X package: %s', binary_package)
continue
if pkgs and binary_package not in pkgs:
continue
if skip_pkgs and binary_package in skip_pkgs:
continue
self.packages[binary_package] = {'substvars': {},
'autoscripts': {},
'rtupdates': [],
'arch': 'any'}
elif line.startswith('Source:'):
self.source_name = line[7:].strip()
elif source_section:
if line.lower().startswith('xs-python-version:'):
xspv = True
if not self.python_version:
self.python_version = line[18:].strip()
if line.lower().startswith('x-python-version:'):
xpv = True
self.python_version = line[17:].strip()
if xspv and xpv:
log.error('Please remove XS-Python-Version from debian/control')
log.debug('source=%s, binary packages=%s', self.source_name, \
self.packages.keys())
def addsubstvar(self, package, name, value):
"""debhelper's addsubstvar"""
self.packages[package]['substvars'].setdefault(name, []).append(value)
def autoscript(self, package, when, template, args):
"""debhelper's autoscript"""
self.packages[package]['autoscripts'].setdefault(when, {})\
.setdefault(template, []).append(args)
def add_rtupdate(self, package, value):
self.packages[package]['rtupdates'].append(value)
def save_autoscripts(self):
for package, settings in self.packages.iteritems():
autoscripts = settings.get('autoscripts')
if not autoscripts:
continue
for when, templates in autoscripts.iteritems():
fn = "debian/%s.%s.debhelper" % (package, when)
if exists(fn):
data = open(fn, 'r').read()
else:
data = ''
new_data = ''
for tpl_name, args in templates.iteritems():
for i in args:
# try local one first (useful while testing dh_python2)
fpath = join(dirname(__file__), '..',
"autoscripts/%s" % tpl_name)
if not exists(fpath):
fpath = "/usr/share/debhelper/autoscripts/%s" % tpl_name
tpl = open(fpath, 'r').read()
if self.options.compile_all and args:
# TODO: should args be checked to contain dir name?
tpl = tpl.replace('#PACKAGE#', '')
else:
tpl = tpl.replace('#PACKAGE#', package)
tpl = tpl.replace('#ARGS#', i)
if tpl not in data and tpl not in new_data:
new_data += "\n%s" % tpl
if new_data:
data += "\n# Automatically added by dh_python2:" +\
"%s\n# End automatically added section\n" % new_data
fp = open(fn, 'w')
fp.write(data)
fp.close()
def save_substvars(self):
for package, settings in self.packages.iteritems():
substvars = settings.get('substvars')
if not substvars:
continue
fn = "debian/%s.substvars" % package
if exists(fn):
data = open(fn, 'r').read()
else:
data = ''
for name, values in substvars.iteritems():
p = data.find("%s=" % name)
if p > -1: # parse the line and remove it from data
e = data[p:].find('\n')
line = data[p + len("%s=" % name):\
p + e if e > -1 else None]
items = [i.strip() for i in line.split(',') if i]
if e > -1 and data[p + e:].strip():
data = "%s\n%s" % (data[:p], data[p + e:])
else:
data = data[:p]
else:
items = []
for j in values:
if j not in items:
items.append(j)
if items:
if data:
data += '\n'
data += "%s=%s\n" % (name, ', '.join(items))
data = data.replace('\n\n', '\n')
if data:
fp = open(fn, 'w')
fp.write(data)
fp.close()
def save_rtupdate(self):
for package, settings in self.packages.iteritems():
pkg_arg = '' if self.options.compile_all else "-p %s" % package
values = settings.get('rtupdates')
if not values:
continue
d = "debian/%s/usr/share/python/runtime.d" % package
if not exists(d):
makedirs(d)
fn = "%s/%s.rtupdate" % (d, package)
if exists(fn):
data = open(fn, 'r').read()
else:
data = "#! /bin/sh\nset -e"
for dname, args in values:
cmd = 'if [ "$1" = rtupdate ]; then' +\
"\n\tpyclean %s %s" % (pkg_arg, dname) +\
"\n\tpycompile %s %s %s\nfi" % (pkg_arg, args, dname)
if cmd not in data:
data += "\n%s" % cmd
if data:
fp = open(fn, 'w')
fp.write(data)
fp.close()
chmod(fn, 0755)
def save(self):
self.save_substvars()
self.save_autoscripts()
self.save_rtupdate()
# -*- 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.
import logging
from debpython.pydist import parse_pydep, guess_dependency
from debpython.version import DEFAULT, SUPPORTED, debsorted, vrepr, vrange_str
# minimum version required for pycompile/pyclean
MINPYCDEP = 'python:any (>= 2.6.6-7~)'
log = logging.getLogger(__name__)
class Dependencies(object):
"""Store relations (dependencies, etc.) between packages."""
def __init__(self, package):
self.package = package
self.depends = []
self.recommends = []
self.suggests = []
self.enhances = []
self.breaks = []
self.rtscripts = []
def export_to(self, dh):
"""Fill in debhelper's substvars."""
for i in sorted(self.depends):
dh.addsubstvar(self.package, 'python:Depends', i)
for i in sorted(self.recommends):
dh.addsubstvar(self.package, 'python:Recommends', i)
for i in sorted(self.suggests):
dh.addsubstvar(self.package, 'python:Suggests', i)
for i in sorted(self.enhances):
dh.addsubstvar(self.package, 'python:Enhances', i)
for i in sorted(self.breaks):
dh.addsubstvar(self.package, 'python:Breaks', i)
for i in self.rtscripts:
dh.add_rtupdate(self.package, i)
def __str__(self):
return "D=%s; R=%s; S=%s; E=%s, B=%s; RT=%s" % (self.depends, \
self.recommends, self.suggests, self.enhances, \
self.breaks, self.rtscripts)
def depend(self, value):
if value and value not in self.depends:
self.depends.append(value)
def recommend(self, value):
if value and value not in self.recommends:
self.recommends.append(value)
def suggest(self, value):
if value and value not in self.suggests:
self.suggests.append(value)
def enhance(self, value):
if value and value not in self.enhances:
self.enhances.append(value)
def break_(self, value):
if value and value not in self.breaks:
self.breaks.append(value)
def rtscript(self, value):
if value not in self.rtscripts:
self.rtscripts.append(value)
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)
# -*- coding: UTF-8 -*-
# Copyright © 2010-2012 Piotr Ożarowski <piotr@debian.org>
# Copyright © 2010-2019 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
......
# -*- coding: UTF-8 -*-
# Copyright © 2011-2012 Piotr Ożarowski <piotr@debian.org>
# Copyright © 2011-2019 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
......@@ -25,8 +25,7 @@ from os import environ, listdir, remove, rmdir
from os.path import dirname, exists, join, getsize, split
from subprocess import Popen, PIPE
from debpython.pydist import PUBLIC_DIR_RE
from debpython.tools import memoize, sitedir
from debpython.tools import memoize, sitedir, PUBLIC_DIR_RE
log = logging.getLogger(__name__)
......@@ -122,41 +121,3 @@ def add_namespace_files(files, package=None, action=None):
log.debug(e)
else:
yield fpath
def remove_from_package(package, namespaces, versions):
"""Remove empty __init__.py files for requested namespaces."""
if not isinstance(namespaces, set):
namespaces = set(namespaces)
keep = set()
for ns in namespaces:
for version in versions:
fpath = join(sitedir(version, package), *ns.split('.'))
fpath = join(fpath, '__init__.py')
if not exists(fpath):
continue
if getsize(fpath) != 0:
log.warning('file not empty, cannot share %s namespace', ns)
keep.add(ns)
break
# return a set of namespaces that should be handled by pycompile/pyclean
result = namespaces - keep
# remove empty __init__.py files, if available
for ns in result:
for version in versions:
dpath = join(sitedir(version, package), *ns.split('.'))
fpath = join(dpath, '__init__.py')
if exists(fpath):
remove(fpath)
if not listdir(dpath):
rmdir(dpath)
# clean pyshared dir as well
dpath = join('debian', package, 'usr/share/pyshared', *ns.split('.'))
fpath = join(dpath, '__init__.py')
if exists(fpath):
remove(fpath)
if not listdir(dpath):
rmdir(dpath)
return result
# -*- coding: UTF-8 -*-
# Copyright © 2010-2012 Piotr Ożarowski <piotr@debian.org>
# Copyright © 2010-2019 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
......
# -*- 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
# -*- coding: UTF-8 -*-
# Copyright © 2010-2012 Piotr Ożarowski <piotr@debian.org>
# Copyright © 2010-2019 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
......@@ -19,35 +19,10 @@
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
from __future__ import with_statement
import codecs
import logging
import os
import re
from cPickle import dumps
from glob import glob
from os.path import exists, isdir, join, split
from shutil import rmtree
from subprocess import PIPE, Popen
from debpython.version import RANGE_PATTERN, getver, get_requested_versions
log = logging.getLogger(__name__)
EGGnPTH_RE = re.compile(r'(.*?)(-py\d\.\d(?:-[^.]*)?)?(\.egg-info|\.pth)$')
SHEBANG_RE = re.compile(r'^#!\s*(.*?/bin/.*?)(python(2\.\d+)?(?:-dbg)?)(?:\s(.*))?[$\r\n].*')
SHAREDLIB_RE = re.compile(r'NEEDED.*libpython(\d\.\d)')
INSTALL_RE = re.compile(r"""
(?P<pattern>.+?) # file pattern
(?:\s+ # optional Python module name:
(?P<module>[A-Za-z][A-Za-z0-9_.]*)?
)?
\s* # optional version range:
(?P<vrange>%s)?$
""" % RANGE_PATTERN, re.VERBOSE)
REMOVE_RE = re.compile(r"""
(?P<pattern>.+?) # file pattern
\s* # optional version range:
(?P<vrange>%s)?$
""" % RANGE_PATTERN, re.VERBOSE)
PUBLIC_DIR_RE = re.compile(r'.*?/usr/lib/python(\d.\d+)/(site|dist)-packages')
def sitedir(version, package=None, gdb=False):
......@@ -74,109 +49,6 @@ def sitedir(version, package=None, gdb=False):
return path
def relpath(target, link):
"""Return relative path.
>>> relpath('/usr/share/python-foo/foo.py', '/usr/bin/foo', )
'../share/python-foo/foo.py'
"""
t = target.split('/')
l = link.split('/')
while l[0] == t[0]:
del l[0], t[0]
return '/'.join(['..'] * (len(l) - 1) + t)
def relative_symlink(target, link):
"""Create relative symlink."""
return os.symlink(relpath(target, link), link)
def fix_shebang(fpath, replacement=None):
"""Normalize file's shebang.
:param replacement: new shebang command (path to interpreter and options)
"""
try:
with open(fpath) as fp:
fcontent = fp.readlines()
if not fcontent:
log.debug('fix_shebang: ignoring empty file: %s', fpath)
return None
except IOError:
log.error('cannot open %s', fpath)
return False
match = SHEBANG_RE.match(fcontent[0])
if not match:
return None
if not replacement:
path, interpreter, version, argv = match.groups()
if path != '/usr/bin': # f.e. /usr/local/* or */bin/env
replacement = "/usr/bin/%s" % interpreter
if interpreter == 'python2':
replacement = '/usr/bin/python'
if replacement and argv:
replacement += " %s" % argv
if replacement:
log.info('replacing shebang in %s (%s)', fpath, fcontent[0])
# do not catch IOError here, the file is zeroed at this stage so it's
# better to fail dh_python2
with open(fpath, 'w') as fp:
fp.write("#! %s\n" % replacement)
fp.writelines(fcontent[1:])
return True
def shebang2pyver(fpath):
"""Check file's shebang.
:rtype: tuple
:returns: pair of Python interpreter string and Python version
"""
try:
with open(fpath) as fp:
data = fp.read(32)
match = SHEBANG_RE.match(data)
if not match:
return None
res = match.groups()
if res[1:3] != (None, None):
if res[2]:
return res[1], getver(res[2])
return res[1], None
except IOError:
log.error('cannot open %s', fpath)
def so2pyver(fpath):
"""Return libpython version file is linked to or None.
:rtype: tuple
:returns: Python version
"""
cmd = "readelf -Wd '%s'" % fpath
process = Popen(cmd, stdout=PIPE, shell=True)
match = SHAREDLIB_RE.search(process.stdout.read())
if match:
return getver(match.groups()[0])
def clean_egg_name(name):
"""Remove Python version and platform name from Egg files/dirs.
>>> clean_egg_name('python_pipeline-0.1.3_py3k-py3.1.egg-info')
'python_pipeline-0.1.3_py3k.egg-info'
>>> clean_egg_name('Foo-1.2-py2.7-linux-x86_64.egg-info')
'Foo-1.2.egg-info'
"""
match = EGGnPTH_RE.match(name)
if match and match.group(2) is not None:
return ''.join(match.group(1, 3))
return name
class memoize(object):
def __init__(self, func):
self.func = func
......@@ -187,111 +59,3 @@ class memoize(object):
if key not in self.cache:
self.cache[key] = self.func(*args, **kwargs)
return self.cache[key]
def pyinstall(package, vrange):
"""Install local files listed in pkg.pyinstall files as public modules."""
status = True
srcfpath = "./debian/%s.pyinstall" % package
if not exists(srcfpath):
return status
versions = get_requested_versions(vrange)
for line in codecs.open(srcfpath, encoding='utf-8'):
if not line or line.startswith('#'):
continue
details = INSTALL_RE.match(line)
if not details:
status = False
log.warn('%s.pyinstall: unrecognized line: %s',
package, line)
continue
details = details.groupdict()
if details['module']:
details['module'] = details['module'].replace('.', '/')
myvers = versions & get_requested_versions(details['vrange'])
if not myvers:
log.debug('%s.pyinstall: no matching versions for line %s',
package, line)
continue
files = glob(details['pattern'])
if not files:
status = False
log.error('%s.pyinstall: file not found: %s',
package, details['pattern'])
continue
for fpath in files:
fpath = fpath.lstrip('/.')
if details['module']:
dstname = join(details['module'], split(fpath)[1])
elif fpath.startswith('debian/'):
dstname = fpath[7:]
else:
dstname = fpath
for version in myvers:
dstfpath = join(sitedir(version, package), dstname)
dstdir = split(dstfpath)[0]
if not exists(dstdir):
try:
os.makedirs(dstdir)
except Exception:
log.error('cannot create %s directory', dstdir)
return False
if exists(dstfpath):
try:
os.remove(dstfpath)
except Exception:
status = False
log.error('cannot replace %s file', dstfpath)
continue
try:
os.link(fpath, dstfpath)
except Exception:
status = False
log.error('cannot copy %s file to %s', fpath, dstdir)
return status
def pyremove(package, vrange):
"""Remove public modules listed in pkg.pyremove file."""
status = True
srcfpath = "./debian/%s.pyremove" % package
if not exists(srcfpath):
return status
versions = get_requested_versions(vrange)
for line in codecs.open(srcfpath, encoding='utf-8'):
if not line or line.startswith('#'):
continue
details = REMOVE_RE.match(line)
if not details:
status = False
log.warn('%s.pyremove: unrecognized line: %s',
package, line)
continue
details = details.groupdict()
myvers = versions & get_requested_versions(details['vrange'])
if not myvers:
log.debug('%s.pyremove: no matching versions for line %s',
package, line)
continue
for version in myvers:
files = glob(sitedir(version, package) + details['pattern'])
if not files:
log.debug('%s.pyremove: nothing to remove: python%d.%d, %s',
package, version, details['pattern'])
continue
for fpath in files:
if isdir(fpath):
try:
rmtree(fpath)
except Exception, e:
status = False
log.error(e)
else:
try:
os.remove(fpath)
except (IOError, OSError), e:
status = False
log.error(e)
return status
# -*- coding: UTF-8 -*-
# Copyright © 2010-2012 Piotr Ożarowski <piotr@debian.org>
# Copyright © 2010-2019 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
......@@ -23,7 +23,7 @@ import logging
import re
from ConfigParser import SafeConfigParser
from os import environ
from os.path import exists, dirname, join
from os.path import exists
from types import GeneratorType
# will be overriden via debian_defaults file few lines later
......@@ -53,7 +53,7 @@ except Exception:
log.exception('cannot read debian_defaults')
try:
SUPPORTED = tuple(tuple(int(j) for j in i.strip().split('.'))
for i in _supported.split(','))
for i in _supported.split(','))
except Exception:
log.exception('cannot read debian_defaults')
......@@ -142,102 +142,6 @@ def parse_vrange(value):
return minv, maxv
def parse_pycentral_vrange(value):
"""Parse XS-Python-Version.
>>> parse_pycentral_vrange('current') == (DEFAULT, DEFAULT)
True
>>> parse_pycentral_vrange('all')
(None, None)
>>> parse_pycentral_vrange('all, >= 2.4')
((2, 4), None)
>>> parse_pycentral_vrange('all, << 3.0')
(None, (3, 0))
>>> parse_pycentral_vrange('2.6')
((2, 6), (2, 6))
>>> parse_pycentral_vrange('2.5, 2.6')
((2, 5), None)
>>> parse_pycentral_vrange('>= 2.6.3')
((2, 6), None)
"""
get = lambda x: get_requested_versions(parse_vrange(x))
current = False
minv = maxv = None
hardcoded = set()
for item in value.split(','):
item = item.strip()
if item == 'all':
continue
elif item == 'current':
current = True
continue
match = re.match('>=\s*([\d\.]+)', item)
if match:
minv = "%.3s" % match.group(1)
continue
match = re.match('<<\s*([\d\.]+)', item)
if match:
maxv = "%.3s" % match.group(1)
continue
match = re.match('^[\d\.]+$', item)
if match:
hardcoded.add("%.3s" % match.group(0))
if len(hardcoded) == 1:
ver = hardcoded.pop()
return getver(ver), getver(ver)
if not minv and hardcoded:
# yeah, no maxv!
minv = sorted(hardcoded)[0]
if current:
versions = sorted(get("%s-%s" % (minv if minv else '',
maxv if maxv else '')))
if not versions:
raise ValueError("version range doesn't match installed Python versions: %s" % value)
# not really what "current" means...
if DEFAULT in versions:
return DEFAULT, DEFAULT
else:
return versions[0], versions[0]
return getver(minv) if minv else None, \
getver(maxv) if maxv else None
def vrange_str(vrange):
"""Return version range string from given range.
>>> vrange_str(((2, 4), None))
'2.4-'
>>> vrange_str(((2, 4), (2, 6)))
'2.4-2.6'
>>> vrange_str(((2, 4), (3, 0)))
'2.4-3.0'
>>> vrange_str((None, (2, 7)))
'-2.7'
>>> vrange_str(((2, 5), (2, 5)))
'2.5'
>>> vrange_str((None, None))
'-'
"""
if vrange[0] is vrange[1] is None:
return '-'
if vrange[0] == vrange[1]:
return '.'.join(str(i) for i in vrange[0])
elif vrange[0] is None:
return '-' + '.'.join(str(i) for i in vrange[1])
elif vrange[1] is None:
return '.'.join(str(i) for i in vrange[0]) + '-'
else:
return "%s-%s" % ('.'.join(str(i) for i in vrange[0]),
'.'.join(str(i) for i in vrange[1]))
def vrepr(value):
"""
>>> vrepr(([2, 7], [3, 2]))
......@@ -252,7 +156,7 @@ def vrepr(value):
if isinstance(value, basestring):
return value
elif not isinstance(value, (GeneratorType, set))\
and isinstance(value[0], int):
and isinstance(value[0], int):
return '.'.join(str(i) for i in value)
result = []
......
This diff is collapsed.
.\" Man page generated from reStructuredText.
.
.TH DH_PYTHON2 1 "" "" ""
.SH NAME
dh_python2 \- calculates Python dependencies, adds maintainer scripts to byte compile files, etc.
.
.nr rst2man-indent-level 0
.
.de1 rstReportMargin
\\$1 \\n[an-margin]
level \\n[rst2man-indent-level]
level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
-
\\n[rst2man-indent0]
\\n[rst2man-indent1]
\\n[rst2man-indent2]
..
.de1 INDENT
.\" .rstReportMargin pre:
. RS \\$1
. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin]
. nr rst2man-indent-level +1
.\" .rstReportMargin post:
..
.de UNINDENT
. RE
.\" indent \\n[an-margin]
.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]]
.nr rst2man-indent-level -1
.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
.in \\n[rst2man-indent\\n[rst2man-indent-level]]u
..
.SH SYNOPSIS
.INDENT 0.0
.INDENT 3.5
dh_python2 \-p PACKAGE [\-V [X.Y][\-][A.B]] DIR_OR_FILE [\-X REGEXPR]
.UNINDENT
.UNINDENT
.SH DESCRIPTION
.SS QUICK GUIDE FOR MAINTAINERS
.INDENT 0.0
.INDENT 3.5
.INDENT 0.0
.IP \(bu 2
if necessary, describe supported Python versions via X\-Python\-Version field
in debian/control,
.IP \(bu 2
build\-depend on python or python\-all or python\-all\-dev (>= 2.6.6\-3~),
.IP \(bu 2
build module/application using its standard build system,
remember to build extensions for all supported Python versions (loop over
\fBpyversions \-vr\fP),
.IP \(bu 2
install files to the \fIstandard\fP locations, add \fI\-\-install\-layout=deb\fP to
setup.py\(aqs install command if your package is using distutils,
.IP \(bu 2
add \fIpython2\fP to dh\(aqs \-\-with option, or:
.IP \(bu 2
\fIinclude /usr/share/cdbs/1/class/python\-distutils.mk\fP in debian/rules and
depend on \fIcdbs (>= 0.4.90)\fP, or:
.IP \(bu 2
call \fBdh_python2\fP in the \fIbinary\-*\fP target,
.IP \(bu 2
add \fI${python:Depends}\fP to Depends
.UNINDENT
.UNINDENT
.UNINDENT
.SS NOTES
.sp
In order to support more than one Python version in the same binary package,
dh_python2 (unlike dh_pycentral and dh_pysupport) creates symlinks to all
supported Python versions at build time. It means binNMU (or sourceful upload
in case of architecture independent packages) is required once a list of
supported Python version is changed. It\(aqs faster and more robust than its
competitors, though.
.SS dependencies
.sp
dh_python2 tries to translate Python dependencies from requires.txt file to
Debian dependencies. Use debian/pydist\-overrides or \-\-no\-guessing\-deps option
to override it if the guess is incorrect. If you want dh_python2 to generate
more strict dependencies (f.e. to avoid ABI problems) create
debian/python\-foo.pydist file. See /usr/share/doc/python\-doc/README.PyDist
(provided by python\-doc package) for more information. If the pydist file
contains PEP386 flag or set of (uscan like) rules, dh_python2 will make the
dependency versioned (version requirements are ignored by default).
.SS namespace feature
.sp
dh_python2 parses Egg\(aqs namespace_packages.txt files (in addition to
\-\-namespace command line argument(s)) and drops empty __init__.py files from
binary package. pycompile will regenerate them at install time and pyclean
will remove them at uninstall time (if they\(aqre no longer used in installed
packages). It\(aqs still a good idea to provide __init__.py file in one of
binary packages (even if all other packages use this feature).
.SS private dirs
.sp
\fI/usr/share/foo\fP, \fI/usr/share/games/foo\fP, \fI/usr/lib/foo\fP and
\fI/usr/lib/games/foo\fP private directories are scanned for Python files
by default (where \fIfoo\fP is binary package name). If your package is shipping
Python files in some other directory, add another dh_python2 call in
debian/rules with directory name as an argument \- you can use different set of
options in this call. If you need to change options (f.e. a list of supported
Python versions) for a private directory that is checked by default, invoke
dh_python2 with \-\-skip\-private option and add another call with a path to this
directory and new options.
.SS debug packages
.sp
In binary packages which name ends with \fI\-dbg\fP, all files in
\fI/usr/lib/python2.X/{site,dist}\-packages/\fP directory
that have extensions different than \fIso\fP or \fIh\fP are removed by default.
Use \-\-no\-dbg\-cleaning option to disable this feature.
.SS pyinstall files
.sp
Files listed in debian/pkg.pyinstall file will be installed as public modules
for all requested Python versions (dh_install doesn\(aqt know about python\(aqs site\-
vs. dist\-packages issue).
.sp
Syntax: \fBpath/to/file [VERSION_RANGE] [NAMESPACE]\fP
.sp
debian directory is automatically removed from the path, so you can place your
files in debian/ directory and install them from this location (if you want to
install them in "debian" namespace, set NAMESPACE to debian). If NAMESPACE is
set, all listed files will be installed in .../dist\-packages/NAMESPACE/
directory.
.INDENT 0.0
.TP
.B Examples:
.INDENT 7.0
.IP \(bu 2
\fBfoo.py\fP installs .../dist\-packages/foo.py for all supported Python versions
.IP \(bu 2
\fBfoo/bar.py 2.6\-\fP installs .../dist\-packages/foo/bar.py for versions >= 2.6
.IP \(bu 2
\fBfoo/bar.py spam\fP installs .../dist\-packages/spam/bar.py
.IP \(bu 2
\fBdebian/*.py spam.egg 2.5\fP installs .../python2.5/site\-packages/spam/egg/*.py
files
.UNINDENT
.UNINDENT
.SS pyremove files
.sp
If you want to remove some files installed by build system (from all supported
Python versions or only from a subset of these versions), add them to
debian/pkg.pyremove file.
.INDENT 0.0
.TP
.B Examples:
.INDENT 7.0
.IP \(bu 2
\fB*.pth\fP removes .pth files from .../dist\-packages/
.IP \(bu 2
\fBbar/baz.py 2.5\fP removes .../python2.5/site\-packages/bar/baz.py
.UNINDENT
.UNINDENT
.SS overriding supported / default Python versions
.sp
If you want to override system\(aqs list of supported Python versions or the
default one (f.e. to build a package that includes symlinks for older version
of Python or compile .py files only for given interpreter version), you can do
that via \fIDEBPYTHON_SUPPORTED\fP and/or \fIDEBPYTHON_DEFAULT\fP env. variables.
.sp
Example: \fB2.5,2.7\fP limits the list of supported Python versions to Python 2.5
and Python 2.7.
.SH OPTIONS
.INDENT 0.0
.TP
.B \-\-version
show program\(aqs version number and exit
.TP
.B \-h\fP,\fB \-\-help
show help message and exit
.TP
.B \-\-no\-guessing\-versions
disable guessing other supported Python versions
.TP
.B \-\-no\-guessing\-deps
disable guessing dependencies
.TP
.B \-\-no\-dbg\-cleaning
do not remove any files from debug packages
.TP
.B \-\-no\-shebang\-rewrite
do not rewrite shebangs
.TP
.B \-\-skip\-private
don\(aqt check private directories
.TP
.B \-v\fP,\fB \-\-verbose
turn verbose mode on
.TP
.B \-i\fP,\fB \-\-indep
act on architecture independent packages
.TP
.B \-a\fP,\fB \-\-arch
act on architecture dependent packages
.TP
.B \-q\fP,\fB \-\-quiet
be quiet
.TP
.BI \-p \ PACKAGE\fP,\fB \ \-\-package\fB= PACKAGE
act on the package named PACKAGE
.TP
.BI \-N \ NO_PACKAGE\fP,\fB \ \-\-no\-package\fB= NO_PACKAGE
do not act on the specified package
.TP
.BI \-V \ VRANGE
specify list of supported Python versions. See
pycompile(1) for examples
.TP
.BI \-X \ REGEXPR\fP,\fB \ \-\-exclude\fB= REGEXPR
exclude items that match given REGEXPR. You may
use this option multiple times to build up a list of things to exclude.
.TP
.B \-\-compile\-all
compile all files from given private directory in postinst/rtupdate
not just the ones provided by the package (i.e. do not pass the \-\-package
parameter to pycompile/pyclean)
.TP
.BI \-\-depends\fB= DEPENDS
translate given requirements into Debian dependencies
and add them to ${python:Depends}. Use it for missing items in requires.txt
.TP
.BI \-\-recommends\fB= RECOMMENDS
translate given requirements into Debian dependencies
and add them to ${python:Recommends}
.TP
.BI \-\-suggests\fB= SUGGESTS
translate given requirements into Debian dependencies
and add them to ${python:Suggests}
.TP
.B \-\-namespace
use this option (multiple time if necessary) if
namespace_packages.txt is not complete
.TP
.B \-\-ignore\-namespace
ignore Egg\(aqs namespace declaration and
\-\-namespace option. This option will disable removing (and recreating at
install time) empty __init__.py files. Removing namespace_packages.txt from
egg\-info directory has the same effect.
.TP
.B \-\-clean\-pycentral
generate maintainer script that will remove byte code
generated by python\-central helper
.TP
.BI \-\-shebang\fB= COMMAND
use given command as shebang in scripts
.TP
.B \-\-ignore\-shebangs
do not translate shebangs into Debian dependencies
.UNINDENT
.SH SEE ALSO
.INDENT 0.0
.IP \(bu 2
/usr/share/doc/python/python\-policy.txt.gz
.IP \(bu 2
/usr/share/doc/python\-doc/README.PyDist (python\-doc package)
.IP \(bu 2
pycompile(1), pyclean(1)
.IP \(bu 2
dh_python3(1), py3compile(1), py3clean(1)
.IP \(bu 2
Wiki page about converting package to dh_python2:
\fI\%http://wiki.debian.org/Python/TransitionToDHPython2\fP
.UNINDENT
.SH AUTHOR
Piotr Ożarowski, 2012-2013
.\" Generated by docutils manpage writer.
.
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment