diff options
author | Marc-André Lemburg <mal@egenix.com> | 2002-04-17 20:30:10 (GMT) |
---|---|---|
committer | Marc-André Lemburg <mal@egenix.com> | 2002-04-17 20:30:10 (GMT) |
commit | 0538f1f2c7171ceb0940fd3865172ad164d2005e (patch) | |
tree | 31d7a834f2f7a0f001956b4a0655727d6c09e643 /Lib/distutils | |
parent | b02ea65f92f7e0c04689f469d436ba35dc2f631f (diff) | |
download | cpython-0538f1f2c7171ceb0940fd3865172ad164d2005e.zip cpython-0538f1f2c7171ceb0940fd3865172ad164d2005e.tar.gz cpython-0538f1f2c7171ceb0940fd3865172ad164d2005e.tar.bz2 |
Patch #531901 by Mark W. Alexander: adds a new distutils packager
base class (in bdist_packager) and two subclasses which make use
of this base class: bdist_pkgtool (for Solaris) and bdist_sdux (for
HP-UX).
Diffstat (limited to 'Lib/distutils')
-rw-r--r-- | Lib/distutils/command/__init__.py | 5 | ||||
-rw-r--r-- | Lib/distutils/command/bdist.py | 11 | ||||
-rw-r--r-- | Lib/distutils/command/bdist_packager.py | 250 | ||||
-rw-r--r-- | Lib/distutils/command/bdist_pkgtool.py | 412 | ||||
-rw-r--r-- | Lib/distutils/command/bdist_sdux.py | 302 |
5 files changed, 976 insertions, 4 deletions
diff --git a/Lib/distutils/command/__init__.py b/Lib/distutils/command/__init__.py index ef8e9ad..8143627 100644 --- a/Lib/distutils/command/__init__.py +++ b/Lib/distutils/command/__init__.py @@ -21,4 +21,9 @@ __all__ = ['build', 'bdist_dumb', 'bdist_rpm', 'bdist_wininst', + 'bdist_sdux', + 'bdist_pkgtool', + # Note: + # bdist_packager is not included because it only provides + # an abstract base class ] diff --git a/Lib/distutils/command/bdist.py b/Lib/distutils/command/bdist.py index 99f7d95..f61611e 100644 --- a/Lib/distutils/command/bdist.py +++ b/Lib/distutils/command/bdist.py @@ -52,7 +52,7 @@ class bdist (Command): ] # The following commands do not take a format option from bdist - no_format_option = ('bdist_rpm',) + no_format_option = ('bdist_rpm', 'bdist_sdux', 'bdist_pkgtool') # This won't do in reality: will need to distinguish RPM-ish Linux, # Debian-ish Linux, Solaris, FreeBSD, ..., Windows, Mac OS. @@ -62,18 +62,21 @@ class bdist (Command): # Establish the preferred order (for the --help-formats option). format_commands = ['rpm', 'gztar', 'bztar', 'ztar', 'tar', - 'wininst', 'zip'] + 'wininst', 'zip', 'pkgtool', 'sdux'] # And the real information. format_command = { 'rpm': ('bdist_rpm', "RPM distribution"), - 'gztar': ('bdist_dumb', "gzip'ed tar file"), + 'zip': ('bdist_dumb', "ZIP file"), 'gztar': ('bdist_dumb', "gzip'ed tar file"), 'bztar': ('bdist_dumb', "bzip2'ed tar file"), 'ztar': ('bdist_dumb', "compressed tar file"), 'tar': ('bdist_dumb', "tar file"), 'wininst': ('bdist_wininst', "Windows executable installer"), 'zip': ('bdist_dumb', "ZIP file"), - } + 'pkgtool': ('bdist_pkgtool', + "Solaris pkgtool distribution"), + 'sdux': ('bdist_sdux', "HP-UX swinstall depot"), + } def initialize_options (self): diff --git a/Lib/distutils/command/bdist_packager.py b/Lib/distutils/command/bdist_packager.py new file mode 100644 index 0000000..a812307 --- /dev/null +++ b/Lib/distutils/command/bdist_packager.py @@ -0,0 +1,250 @@ +"""distutils.command.bdist_ packager + +Modified from bdist_dumb by Mark W. Alexander <slash@dotnetslash.net> + +Implements the Distutils 'bdist_packager' abstract command +to be subclassed by binary package creation commands.""" + + +__revision__ = "$Id: bdist_packager.py,v 0.1 2001/04/4 mwa" + +import os +from distutils.core import Command +from distutils.util import get_platform +from distutils.dir_util import create_tree, remove_tree +from distutils.file_util import write_file +from distutils.errors import * +import string, sys + +class bdist_packager (Command): + + description = "abstract base for package manager specific bdist commands" + +# XXX update user_options + user_options = [ + ('bdist-base=', None, + "base directory for creating built distributions"), + ('pkg-dir=', None, + "base directory for creating binary packages (defaults to \"binary\" under "), + ('dist-dir=', 'd', + "directory to put final RPM files in " + "(and .spec files if --spec-only)"), + ('category=', None, + "Software category (packager dependent format)"), + ('revision=', None, + "package revision number"), + # the following have moved into the distribution class + #('packager=', None, + #"Package maintainer"), + #('packager-mail=', None, + #"Package maintainer's email address"), + #('author=', None, + #"Package author"), + #('author-mail=', None, + #"Package author's email address"), + #('license=', None, + #"License code"), + #('licence=', None, + #"alias for license"), + ('icon=', None, + "Package icon"), + ('subpackages=', None, + "Comma seperated list of seperately packaged trees"), + ('preinstall=', None, + "preinstall script (Bourne shell code)"), + ('postinstall=', None, + "postinstall script (Bourne shell code)"), + ('preremove=', None, + "preremove script (Bourne shell code)"), + ('postremove=', None, + "postremove script (Bourne shell code)"), + ('requires=', None, + "capabilities required by this package"), + ('keep-temp', 'k', + "don't clean up RPM build directory"), + ('control-only', None, + "Generate package control files and stop"), + ('no-autorelocate', None, + "Inhibit automatic relocation to installed site-packages"), + ] + + boolean_options = ['keep-temp', 'control-only', 'no_autorelocate'] + + def ensure_string_not_none (self,option,default=None): + val = getattr(self,option) + if val is not None: + return + Command.ensure_string(self,option,default) + val = getattr(self,option) + if val is None: + raise DistutilsOptionError, "'%s' must be provided" % option + + def ensure_script (self,arg): + if not arg: + return + try: + self.ensure_string(arg, None) + except: + try: + self.ensure_filename(arg, None) + except: + raise RuntimeError, \ + "cannot decipher script option (%s)" \ + % arg + + def write_script (self,path,attr,default=None): + """ write the script specified in attr to path. if attr is None, + write use default instead """ + val = getattr(self,attr) + if not val: + if not default: + return + else: + setattr(self,attr,default) + val = default + if val!="": + self.announce('Creating %s script', attr) + self.execute(write_file, + (path, self.get_script(attr)), + "writing '%s'" % path) + + def get_binary_name(self): + py_ver = sys.version[0:string.find(sys.version,' ')] + return self.name + '-' + self.version + '-' + \ + self.revision + '-' + py_ver + + def get_script (self,attr): + # accept a script as a string ("line\012line\012..."), + # a filename, or a list + # XXX We could probably get away with copy_file, but I'm + # guessing this will be more flexible later on.... + val = getattr(self,attr) + ret=None + if val: + try: + os.stat(val) + # script is a file + ret=[] + f=open(val) + ret=string.split(f.read(),"\012"); + f.close() + #return ret + except: + if type(val)==type(""): + # script is a string + ret = string.split(val,"\012") + elif type(val)==type([]): + # script is a list + ret = val + else: + raise RuntimeError, \ + "cannot figure out what to do with 'request' option (%s)" \ + % val + return ret + + + def initialize_options (self): + d = self.distribution + self.keep_temp = 0 + self.control_only = 0 + self.no_autorelocate = 0 + self.pkg_dir = None + self.plat_name = None + self.icon = None + self.requires = None + self.subpackages = None + self.category = None + self.revision = None + + # PEP 241 Metadata + self.name = None + self.version = None + #self.url = None + #self.author = None + #self.author_email = None + #self.maintainer = None + #self.maintainer_email = None + #self.description = None + #self.long_description = None + #self.licence = None + #self.platforms = None + #self.keywords = None + self.root_package = None + + # package installation scripts + self.preinstall = None + self.postinstall = None + self.preremove = None + self.postremove = None + # initialize_options() + + + def finalize_options (self): + + if self.pkg_dir is None: + bdist_base = self.get_finalized_command('bdist').bdist_base + self.pkg_dir = os.path.join(bdist_base, 'binary') + + if not self.plat_name: + d = self.distribution + self.plat = d.get_platforms() + if self.distribution.has_ext_modules(): + self.plat_name = [sys.platform,] + else: + self.plat_name = ["noarch",] + + d = self.distribution + self.ensure_string_not_none('name', d.get_name()) + self.ensure_string_not_none('version', d.get_version()) + self.ensure_string('category') + self.ensure_string('revision',"1") + #self.ensure_string('url',d.get_url()) + if type(self.distribution.packages) == type([]): + self.root_package=self.distribution.packages[0] + else: + self.root_package=self.name + self.ensure_string('root_package',self.root_package) + #self.ensure_string_list('keywords') + #self.ensure_string_not_none('author', d.get_author()) + #self.ensure_string_not_none('author_email', d.get_author_email()) + self.ensure_filename('icon') + #self.ensure_string_not_none('maintainer', d.get_maintainer()) + #self.ensure_string_not_none('maintainer_email', + #d.get_maintainer_email()) + #self.ensure_string_not_none('description', d.get_description()) + #self.ensure_string_not_none('long_description', d.get_long_description()) + #if self.long_description=='UNKNOWN': + #self.long_description=self.description + #self.ensure_string_not_none('license', d.get_license()) + self.ensure_string_list('requires') + self.ensure_filename('preinstall') + self.ensure_filename('postinstall') + self.ensure_filename('preremove') + self.ensure_filename('postremove') + + # finalize_options() + + + def run (self): + + raise RuntimeError, \ + "abstract method -- subclass %s must override" % self.__class__ + self.run_command('build') + + install = self.reinitialize_command('install', reinit_subcommands=1) + install.root = self.pkg_dir + + self.announce("installing to %s" % self.pkg_dir) + self.run_command('install') + + # And make an archive relative to the root of the + # pseudo-installation tree. + archive_basename = "%s.%s" % (self.distribution.get_fullname(), + self.plat_name) + + if not self.keep_temp: + remove_tree(self.pkg_dir, self.verbose, self.dry_run) + + # run() + +# class bdist_packager diff --git a/Lib/distutils/command/bdist_pkgtool.py b/Lib/distutils/command/bdist_pkgtool.py new file mode 100644 index 0000000..fc035eb --- /dev/null +++ b/Lib/distutils/command/bdist_pkgtool.py @@ -0,0 +1,412 @@ +"""distutils.command.bdist_pkgtool + + +Author: Mark W. Alexander <slash@dotnet.net> + +Implements the Distutils 'bdist_pkgtool' command (create Solaris pkgtool +distributions).""" + +import os, string, sys, pwd, grp +import glob +from types import * +from distutils.core import Command, DEBUG +from distutils.util import get_platform +from distutils.file_util import write_file +from distutils.errors import * +from distutils.command import bdist_packager +from distutils import sysconfig +import compileall +from commands import getoutput + +__revision__ = "$Id: bdist_pkgtool.py,v 0.3 mwa " + +# default request script - Is also wrapped around user's request script +# unless --no-autorelocate is requested. Finds the python site-packages +# directory and prompts for verification +DEFAULT_REQUEST="""#!/bin/sh +###################################################################### +# Distutils internal package relocation support # +###################################################################### + +PRODUCT="__DISTUTILS_NAME__" + +trap `exit 3` 15 +/usr/bin/which python 2>&1 >/dev/null +if [ $? -ne 0 ]; then + echo "The python interpretor needs to be on your path!" + echo + echo "If you have more than one, make sure the first one is where" + echo "you want this module installed:" + exit 1 +fi + +PY_DIR=`python -c "import sys;print '%s/lib/python%s' % (sys.exec_prefix,sys.version[0:3])" 2>/dev/null` +PY_PKG_DIR=`python -c "import sys;print '%s/lib/python%s/site-packages' % (sys.exec_prefix,sys.version[0:3])" 2>/dev/null` + +echo "" +if [ -z "${PY_DIR}" ]; then + echo "I can't seem to find the python distribution." + echo "I'm assuming the default path for site-packages" +else + BASEDIR="${PY_PKG_DIR}" + cat <<EOF + Python found! The default path: + + ${BASEDIR} + + will install ${PRODUCT} such that all python users + can import it. + + If you just want individual access, you can install into + any directory and add that directory to your \$PYTHONPATH +EOF +fi +echo "" + +BASEDIR=`ckpath -d ${BASEDIR} -ay \ + -p "Where should ${PRODUCT} be installed? [${BASEDIR}]"` || exit $? + +###################################################################### +# user supplied request script follows # +###################################################################### +""" +### request script + +# default postinstall compiles and changes ownership on the module directory +# XXX The ownership change _should_ be handled by adjusting the prototype file +DEFAULT_POSTINSTALL="""#!/bin/sh +/usr/bin/test -d ${BASEDIR}/__DISTUTILS_NAME__ +if [ $? -eq 0 ]; then + python -c "import compileall;compileall.compile_dir(\\"${BASEDIR}/__DISTUTILS_NAME__\\")" + chown -R root:other ${BASEDIR}/__DISTUTILS_NAME__ +fi +""" + +# default preremove deletes *.pyc and *.pyo from the module tree +# This should leave the tree empty, so pkgtool will remove it. +# If the user's scripts place anything else in there (e.g. config files), +# pkgtool will leave the directory intact +DEFAULT_PREREMOVE="""#!/bin/sh + +/usr/bin/which python 2>&1 >/dev/null +if [ $? -ne 0 ]; then + echo "The python interpretor needs to be on your path!" + echo + echo "If you have more than one, make sure the first one is where" + echo "you want this module removed from" + exit 1 +fi + +/usr/bin/test -d ${BASEDIR}/__DISTUTILS_NAME__ +if [ $? -eq 0 ]; then + find ${BASEDIR}/__DISTUTILS_NAME__ -name "*.pyc" -exec rm {} \; + find ${BASEDIR}/__DISTUTILS_NAME__ -name "*.pyo" -exec rm {} \; +fi +""" + +# default postremove removes the module directory _IF_ no files are +# there (Turns out this isn't needed if the preremove does it's job +# Left for posterity +DEFAULT_POSTREMOVE="""#!/bin/sh + +/usr/bin/test -d ${BASEDIR}/__DISTUTILS_NAME__ +if [ $? -eq 0 ]; then + if [ `find ${BASEDIR}/__DISTUTILS_NAME__ ! -type d | wc -l` -eq 0 ]; then + rm -rf ${BASEDIR}/__DISTUTILS_NAME__ + fi +fi +""" + +class bdist_pkgtool (bdist_packager.bdist_packager): + + description = "create an pkgtool (Solaris) package" + + user_options = bdist_packager.bdist_packager.user_options + [ + ('revision=', None, + "package revision number (PSTAMP)"), + ('pkg-abrev=', None, + "Abbreviation (9 characters or less) of the package name"), + ('compver=', None, + "file containing compatible versions of this package (man compver)"), + ('depend=', None, + "file containing dependencies for this package (man depend)"), + #('category=', None, + #"Software category"), + ('request=', None, + "request script (Bourne shell code)"), + ] + + def initialize_options (self): + # XXX Check for pkgtools on path... + bdist_packager.bdist_packager.initialize_options(self) + self.compver = None + self.depend = None + self.vendor = None + self.classes = None + self.request = None + self.pkg_abrev = None + self.revision = None + # I'm not sure I should need to do this, but the setup.cfg + # settings weren't showing up.... + options = self.distribution.get_option_dict('bdist_packager') + for key in options.keys(): + setattr(self,key,options[key][1]) + + # initialize_options() + + + def finalize_options (self): + global DEFAULT_REQUEST, DEFAULT_POSTINSTALL + global DEFAULT_PREREMOVE, DEFAULT_POSTREMOVE + if self.pkg_dir is None: + dist_dir = self.get_finalized_command('bdist').dist_dir + self.pkg_dir = os.path.join(dist_dir, "pkgtool") + + self.ensure_string('classes', None) + self.ensure_string('revision', "1") + self.ensure_script('request') + self.ensure_script('preinstall') + self.ensure_script('postinstall') + self.ensure_script('preremove') + self.ensure_script('postremove') + self.ensure_string('vendor', None) + if self.__dict__.has_key('author'): + if self.__dict__.has_key('author_email'): + self.ensure_string('vendor', + "%s <%s>" % (self.author, + self.author_email)) + else: + self.ensure_string('vendor', + "%s" % (self.author)) + self.ensure_string('category', "System,application") + self.ensure_script('compver') + self.ensure_script('depend') + bdist_packager.bdist_packager.finalize_options(self) + if self.pkg_abrev is None: + self.pkg_abrev=self.name + if len(self.pkg_abrev)>9: + raise DistutilsOptionError, \ + "pkg-abrev (%s) must be less than 9 characters" % self.pkg_abrev + # Update default scripts with our metadata name + DEFAULT_REQUEST = string.replace(DEFAULT_REQUEST, + "__DISTUTILS_NAME__", self.root_package) + DEFAULT_POSTINSTALL = string.replace(DEFAULT_POSTINSTALL, + "__DISTUTILS_NAME__", self.root_package) + DEFAULT_PREREMOVE = string.replace(DEFAULT_PREREMOVE, + "__DISTUTILS_NAME__", self.root_package) + DEFAULT_POSTREMOVE = string.replace(DEFAULT_POSTREMOVE, + "__DISTUTILS_NAME__", self.root_package) + + # finalize_options() + + + def make_package(self,root=None): + # make directories + self.mkpath(self.pkg_dir) + if root: + pkg_dir = self.pkg_dir+"/"+root + self.mkpath(pkg_dir) + else: + pkg_dir = self.pkg_dir + + install = self.reinitialize_command('install', reinit_subcommands=1) + # build package + self.announce('Building package') + self.run_command('build') + self.announce('Creating pkginfo file') + path = os.path.join(pkg_dir, "pkginfo") + self.execute(write_file, + (path, + self._make_info_file()), + "writing '%s'" % path) + # request script handling + if self.request==None: + self.request = self._make_request_script() + if self.request!="": + path = os.path.join(pkg_dir, "request") + self.execute(write_file, + (path, + self.request), + "writing '%s'" % path) + + # Create installation scripts, since compver & depend are + # user created files, they work just fine as scripts + self.write_script(os.path.join(pkg_dir, "postinstall"), + 'postinstall',DEFAULT_POSTINSTALL) + self.write_script(os.path.join(pkg_dir, "preinstall"), + 'preinstall',None) + self.write_script(os.path.join(pkg_dir, "preremove"), + 'preremove',DEFAULT_PREREMOVE) + self.write_script(os.path.join(pkg_dir, "postremove"), + 'postremove',None) + self.write_script(os.path.join(pkg_dir, "compver"), + 'compver',None) + self.write_script(os.path.join(pkg_dir, "depend"), + 'depend',None) + + self.announce('Creating prototype file') + path = os.path.join(pkg_dir, "prototype") + self.execute(write_file, + (path, + self._make_prototype()), + "writing '%s'" % path) + + + if self.control_only: # stop if requested + return + + + self.announce('Creating package') + pkg_cmd = ['pkgmk', '-o', '-f'] + pkg_cmd.append(path) + pkg_cmd.append('-b') + pkg_cmd.append(os.environ['PWD']) + self.spawn(pkg_cmd) + pkg_cmd = ['pkgtrans', '-s', '/var/spool/pkg'] + path = os.path.join(os.environ['PWD'],pkg_dir, + self.get_binary_name() + ".pkg") + self.announce('Transferring package to ' + pkg_dir) + pkg_cmd.append(path) + pkg_cmd.append(self.pkg_abrev) + self.spawn(pkg_cmd) + os.system("rm -rf /var/spool/pkg/%s" % self.pkg_abrev) + + + def run (self): + if self.subpackages: + self.subpackages=string.split(self.subpackages,",") + for pkg in self.subpackages: + self.make_package(subpackage) + else: + self.make_package() + # run() + + + def _make_prototype(self): + proto_file = ["i pkginfo"] + if self.request: + proto_file.extend(['i request']) + if self.postinstall: + proto_file.extend(['i postinstall']) + if self.postremove: + proto_file.extend(['i postremove']) + if self.preinstall: + proto_file.extend(['i preinstall']) + if self.preremove: + proto_file.extend(['i preremove']) + if self.compver: + proto_file.extend(['i compver']) + if self.requires: + proto_file.extend(['i depend']) + proto_file.extend(['!default 644 root bin']) + build = self.get_finalized_command('build') + + try: + self.distribution.packages[0] + file_list=string.split( + getoutput("pkgproto %s/%s=%s" % (build.build_lib, + self.distribution.packages[0], + self.distribution.packages[0])),"\012") + except: + file_list=string.split( + getoutput("pkgproto %s=" % (build.build_lib)),"\012") + ownership="%s %s" % (pwd.getpwuid(os.getuid())[0], + grp.getgrgid(os.getgid())[0]) + for i in range(len(file_list)): + file_list[i] = string.replace(file_list[i],ownership,"root bin") + proto_file.extend(file_list) + return proto_file + + def _make_request_script(self): + global DEFAULT_REQUEST + # A little different from other scripts, if we are to automatically + # relocate to the target site-packages, we have to wrap any provided + # script with the autorelocation script. If no script is provided, + # The request script will simply be the autorelocate script + if self.no_autorelocate==0: + request=string.split(DEFAULT_REQUEST,"\012") + else: + self.announce('Creating relocation request script') + if self.request: + users_request=self.get_script('request') + if users_request!=None and users_request!=[]: + if self.no_autorelocate==0 and users_request[0][0:2]=="#!": + users_request.remove(users_request[0]) + for i in users_request: + request.append(i) + + if self.no_autorelocate==0: + request.append("#############################################") + request.append("# finalize relocation support #") + request.append("#############################################") + request.append('echo "BASEDIR=\\"${BASEDIR}\\"" >>$1') + return request + + def _make_info_file(self): + """Generate the text of a pkgtool info file and return it as a + list of strings (one per line). + """ + # definitions and headers + # PKG must be alphanumeric, < 9 characters + info_file = [ + 'PKG="%s"' % self.pkg_abrev, + 'NAME="%s"' % self.name, + 'VERSION="%s"' % self.version, + 'PSTAMP="%s"' % self.revision, + ] + info_file.extend(['VENDOR="%s (%s)"' % (self.distribution.maintainer, \ + self.distribution.license) ]) + info_file.extend(['EMAIL="%s"' % self.distribution.maintainer_email ]) + + p = self.distribution.get_platforms() + if p is None or p==['UNKNOWN']: + archs=getoutput('uname -p') + else: + archs=string.join(self.distribution.get_platforms(),',') + #else: + #print "Assuming a sparc architecure" + #archs='sparc' + info_file.extend(['ARCH="%s"' % archs ]) + + if self.distribution.get_url(): + info_file.extend(['HOTLINE="%s"' % self.distribution.get_url() ]) + if self.classes: + info_file.extend(['CLASSES="%s"' % self.classes ]) + if self.category: + info_file.extend(['CATEGORY="%s"' % self.category ]) + site=None + for i in sys.path: + if i[-13:]=="site-packages": + site=i + break + if site: + info_file.extend(['BASEDIR="%s"' % site ]) + + return info_file + + # _make_info_file () + + def _format_changelog(self, changelog): + """Format the changelog correctly and convert it to a list of strings + """ + if not changelog: + return changelog + new_changelog = [] + for line in string.split(string.strip(changelog), '\n'): + line = string.strip(line) + if line[0] == '*': + new_changelog.extend(['', line]) + elif line[0] == '-': + new_changelog.append(line) + else: + new_changelog.append(' ' + line) + + # strip trailing newline inserted by first changelog entry + if not new_changelog[0]: + del new_changelog[0] + + return new_changelog + + # _format_changelog() + +# class bdist_rpm diff --git a/Lib/distutils/command/bdist_sdux.py b/Lib/distutils/command/bdist_sdux.py new file mode 100644 index 0000000..985a37a --- /dev/null +++ b/Lib/distutils/command/bdist_sdux.py @@ -0,0 +1,302 @@ +"""distutils.command.bdist_pkgtool + +Implements the Distutils 'bdist_sdux' command to create HP-UX +swinstall depot""" + +# Mark Alexander <slash@dotnetslash.net> + +__revision__ = "$Id: bdist_sdux.py,v 0.2 " +import os, string +import glob +from types import * +from distutils.core import Command, DEBUG +from distutils.util import get_platform +from distutils.file_util import write_file +from distutils.errors import * +from distutils.command import bdist_packager +import sys +from commands import getoutput + +DEFAULT_CHECKINSTALL="""#!/bin/sh +/usr/bin/which python 2>&1 >/dev/null +if [ $? -ne 0 ]; then + echo "ERROR: Python must be on your PATH" &>2 + echo "ERROR: (You may need to link it to /usr/bin) " &>2 + exit 1 +fi +PY_DIR=`python -c "import sys;print '%s/lib/python%s' % (sys.exec_prefix,sys.version[0:3])" #2>/dev/null` +PY_PKG_DIR=`python -c "import sys;print '%s/lib/python%s/site-packages' % (sys.exec_prefix,sys.version[0:3])" #2>/dev/null` +PY_LIB_DIR=`dirname $PY_PKG_DIR` + +if [ "`dirname ${SW_LOCATION}`" = "__DISTUTILS_PKG_DIR__" ]; then + # swinstall to default location + if [ "${PY_PKG_DIR}" != "__DISTUTILS_PKG_DIR__" ]; then + echo "ERROR: " &>2 + echo "ERROR: Python is not installed where this package expected!" &>2 + echo "ERROR: You need to manually relocate this package to your python installation." &>2 + echo "ERROR: " &>2 + echo "ERROR: Re-run swinstall specifying the product name:location, e.g.:" &>2 + echo "ERROR: " &>2 + echo "ERROR: swinstall -s [source] __DISTUTILS_NAME__:${PY_PKG_DIR}/__DISTUTILS_DIRNAME__" &>2 + echo "ERROR: " &>2 + echo "ERROR: to relocate this package to match your python installation" &>2 + echo "ERROR: " &>2 + exit 1 + fi +else + if [ "`dirname ${SW_LOCATION}`" != "${PY_PKG_DIR}" -a "`dirname ${SWLOCATION}`" != "${PY_LIB_DIR}" ]; then + echo "WARNING: " &>2 + echo "WARNING: Package is being installed outside the 'normal' python search path!" &>2 + echo "WARNING: Add ${SW_LOCATION} to PYTHONPATH to use this package" &>2 + echo "WARNING: " &>2 + fi +fi +""" + +DEFAULT_POSTINSTALL="""#!/bin/sh +/usr/bin/which python 2>&1 >/dev/null +if [ $? -ne 0 ]; then + echo "ERROR: Python must be on your PATH" &>2 + echo "ERROR: (You may need to link it to /usr/bin) " &>2 + exit 1 +fi +python -c "import compileall;compileall.compile_dir(\\"${SW_LOCATION}\\")" +""" + +DEFAULT_PREREMOVE="""#!/bin/sh +# remove compiled bytecode files +find ${SW_LOCATION} -name "*.pyc" -exec rm {} \; +find ${SW_LOCATION} -name "*.pyo" -exec rm {} \; +""" + +DEFAULT_POSTREMOVE="""#!/bin/sh +if [ `find ${SW_LOCATION} ! -type d | wc -l` -eq 0 ]; then + # remove if there's nothing but empty directories left + rm -rf ${SW_LOCATION} +fi +""" + +class bdist_sdux(bdist_packager.bdist_packager): + + description = "create an HP swinstall depot" + + user_options = bdist_packager.bdist_packager.user_options + [ + #('revision=', None, + #"package revision number (PSTAMP)"), + ('keep-permissions', None, + "Don't reset permissions and ownership to root/bin"), # XXX + ('corequisites=', None, + "corequisites"), # XXX + ('prerequisites=', None, + "prerequisites"), # XXX + #('category=', None, + #"Software category"), + ('checkinstall=', None, # XXX ala request + "checkinstall script (Bourne shell code)"), + ('configure=', None, # XXX + "configure script (Bourne shell code)"), + ('unconfigure=', None, # XXX + "unconfigure script (Bourne shell code)"), + ('verify=', None, # XXX + "verify script (Bourne shell code)"), + ('unpreinstall=', None, # XXX + "unpreinstall script (Bourne shell code)"), + ('unpostinstall=', None, # XXX + "unpostinstall script (Bourne shell code)"), + ] + + boolean_options = ['keep-permissions'] + + def initialize_options (self): + bdist_packager.bdist_packager.initialize_options(self) + self.corequisites = None + self.prerequesites = None + self.checkinstall = None + self.configure = None + self.unconfigure = None + self.verify = None + self.unpreinstall = None + self.unpostinstall = None + # More + self.copyright = None + self.readme = None + self.machine_type = None + self.os_name = None + self.os_release = None + self.directory = None + self.readme = None + self.copyright = None + self.architecture= None + self.keep_permissions= None + options = self.distribution.get_option_dict('bdist_packager') + for key in options.keys(): + setattr(self,key,options[key][1]) + + # initialize_options() + + + def finalize_options (self): + global DEFAULT_CHECKINSTALL, DEFAULT_POSTINSTALL + global DEFAULT_PREREMOVE, DEFAULT_POSTREMOVE + if self.pkg_dir==None: + dist_dir = self.get_finalized_command('bdist').dist_dir + self.pkg_dir = os.path.join(dist_dir, "sdux") + self.ensure_script('corequisites') + self.ensure_script('prerequesites') + self.ensure_script('checkinstall') + self.ensure_script('configure') + self.ensure_script('unconfigure') + self.ensure_script('verify') + self.ensure_script('unpreinstall') + self.ensure_script('unpostinstall') + self.ensure_script('copyright') + self.ensure_script('readme') + self.ensure_string('machine_type','*') + if not self.__dict__.has_key('platforms'): + # This is probably HP, but if it's not, use sys.platform + if sys.platform[0:5] == "hp-ux": + self.platforms = "HP-UX" + else: + self.platforms = string.upper(sys.platform) + else: + # we can only handle one + self.platforms=string.join(self.platforms[0]) + self.ensure_string('os_release','*') + self.ensure_string('directory','%s/lib/python%s/site-packages' % \ + (sys.exec_prefix, sys.version[0:3])) + bdist_packager.bdist_packager.finalize_options(self) + DEFAULT_CHECKINSTALL = string.replace(DEFAULT_CHECKINSTALL, + "__DISTUTILS_NAME__", self.name) + DEFAULT_CHECKINSTALL = string.replace(DEFAULT_CHECKINSTALL, + "__DISTUTILS_DIRNAME__", self.root_package) + DEFAULT_CHECKINSTALL = string.replace(DEFAULT_CHECKINSTALL, + "__DISTUTILS_PKG_DIR__", self.directory) + DEFAULT_POSTINSTALL = string.replace(DEFAULT_POSTINSTALL, + "__DISTUTILS_DIRNAME__", self.root_package) + #DEFAULT_PREREMOVE = string.replace(DEFAULT_PREREMOVE, + #"__DISTUTILS_NAME__", self.root_package) + #DEFAULT_POSTREMOVE = string.replace(DEFAULT_POSTREMOVE, + #"__DISTUTILS_NAME__", self.root_package) + # finalize_options() + + def run (self): + # make directories + self.mkpath(self.pkg_dir) + psf_path = os.path.join(self.pkg_dir, + "%s.psf" % self.get_binary_name()) + # build package + self.announce('Building package') + self.run_command('build') + self.announce('Creating psf file') + self.execute(write_file, + (psf_path, + self._make_control_file()), + "writing '%s'" % psf_path) + if self.control_only: # stop if requested + return + + self.announce('Creating package') + spawn_cmd = ['swpackage', '-s'] + spawn_cmd.append(psf_path) + spawn_cmd.append('-x') + spawn_cmd.append('target_type=tape') + spawn_cmd.append('@') + spawn_cmd.append(self.pkg_dir+"/"+self.get_binary_name()+'.depot') + self.spawn(spawn_cmd) + + # run() + + + def _make_control_file(self): + # Generate a psf file and return it as list of strings (one per line). + # definitions and headers + title = "%s %s" % (self.maintainer,self.maintainer_email) + title=title[0:80] + #top=self.distribution.packages[0] + psf_file = [ + 'vendor', # Vendor information + ' tag %s' % "DISTUTILS", + ' title %s' % title, + ' description Distutils package maintainer (%s)' % self.license, + 'end', # end of vendor + 'product', # Product information + ' tag %s' % self.name, + ' title %s' % self.description, + ' description %s' % self.description, + ' revision %s' % self.version, + ' architecture %s' % self.platforms, + ' machine_type %s' % self.machine_type, + ' os_name %s' % self.platforms, + ' os_release %s' % self.os_release, + ' directory %s' % self.directory + "/" + self.root_package, + ] + + self.write_script(os.path.join(self.pkg_dir, "checkinstall"), + 'checkinstall',DEFAULT_CHECKINSTALL) + psf_file.extend([' checkinstall %s/checkinstall' % self.pkg_dir]) + self.write_script(os.path.join(self.pkg_dir, "postinstall"), + 'postinstall',DEFAULT_POSTINSTALL) + psf_file.extend([' postinstall %s/postinstall' % self.pkg_dir]) + self.write_script(os.path.join(self.pkg_dir, "preremove"), + 'preremove',DEFAULT_PREREMOVE) + psf_file.extend([' preremove %s/preremove' % self.pkg_dir]) + self.write_script(os.path.join(self.pkg_dir, "postremove"), + 'postremove',DEFAULT_POSTREMOVE) + psf_file.extend([' postremove %s/postremove' % self.pkg_dir]) + if self.preinstall: + self.write_script(self.pkg_dir+"/preinstall", 'preinstall', None) + psf_file.extend([' preinstall %s/preinstall' % self.pkg_dir]) + if self.configure: + self.write_script(self.pkg_dir+"/configure", 'configure', None) + psf_file.extend([' configure %s/configure' % self.pkg_dir]) + if self.unconfigure: + self.write_script(self.pkg_dir+"/unconfigure", 'unconfigure', None) + psf_file.extend([' unconfigure %s/unconfigure' % self.pkg_dir]) + if self.verify: + self.write_script(self.pkg_dir+"/verify", 'verify', None) + psf_file.extend([' verify %s/verify' % self.pkg_dir]) + if self.unpreinstall: + self.write_script(self.pkg_dir+"/unpreinstall", 'unpreinstall', None) + psf_file.extend([' unpreinstall %s/unpreinstall' % self.pkg_dir]) + if self.unpostinstall: + self.write_script(self.pkg_dir+"/unpostinstall", 'unpostinstall', None) + psf_file.extend([' unpostinstall %s/unpostinstall' % self.pkg_dir]) + psf_file.extend([' is_locatable true']) + #if self.long_description: + #psf_file.extend([self.long_description]) + if self.copyright: + # XX make a copyright file XXX + write_script('copyright') + psf_file.extend([' copyright <copyright']) + if self.readme: + # XX make a readme file XXX + write_script('readme') + psf_file.extend([' readme <readme']) + + psf_file.extend([' fileset']) # start fileset + if self.distribution.ext_modules: + platlib=self.get_finalized_command('build').build_platlib + else: + platlib=self.get_finalized_command('build').build_lib + title = "%s installation files" % (self.name) + psf_file.extend([ + ' tag %s' % 'FILES', + ' title %s' % "%s installation files" % (self.name), + ' revision %s' % self.version, + ' directory %s/%s=%s/%s' % (platlib,self.root_package,self.directory,self.root_package), + ]) + if not self.keep_permissions: + psf_file.extend([' file_permissions -m 555 -o root -g bin']) + psf_file.extend([' file *']) + psf_file.extend([' end']) # end of fileset + psf_file.extend(['end']) # end of product + +# XXX add fileset information + + + return psf_file + + # _make_control_file () + + +# class bdist_sdux |