| """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 |