"""distutils.command.bdist_sunpkg Implements the Distutils 'bdist_sunpkg' command (create solaris pkg source and binary distributions).""" __revision__ = "$Id$" import os, time, getpass from distutils.core import Command from distutils.util import get_platform from distutils.errors import * from distutils import dir_util from distutils import file_util from distutils import log class bdist_sunpkg(Command): PKG_MAXLEN = 32 # max. length of PKG shortname PKG_EXTENSION = '.pkg' PKG_MAXINST = 1 PKG_CLASSES = "none" PKG_CATEGORY = "python library package" try: PKG_ARCH = os.uname()[4] except AttributeError: PKG_ARCH = os.name() description = "create a \"sunpkg\" binary distribution" user_options = [ ('bdist-dir=', None, "temporary directory for creating the distribution "), ('prefix=', None, "prepend prefix path to pseudo-installation " "(default: /sunpkg)"), ('plat-name=', 'p', "platform name to embed in generated filenames " "(default: %s)" % get_platform()), ('keep-temp', 'k', "keep the pseudo-installation tree around after " "creating the distribution archive"), ('dist-dir=', 'd', "directory to put final built distributions in"), ('pkg-dir=', None, "temporary directory for packaging (spool directory)"), ('pkg-pkg=', None, "sun package PKG id (default: concatenated from pkg-prefix, pkg-name, " "pkg-suffix"), ('pkg-version=', None, "sun package version (default: distutils version info)"), ('pkg-arch=', None, "sun package arch information (default: %s)" % PKG_ARCH), ('pkg-prefix=', None, "sun package name prefix, prepended to pkg-name"), ('pkg-name=', None, "sun package name (default: python package name)"), ('pkg-suffix=', None, "sun package name suffix, appended to pkg-name"), ('pkg-desc=', None, "sun package description (default: distutils description info)"), ('pkg-category=', None, "sun package category (default: %s)" % PKG_CATEGORY), ('pkg-vendor=', None, "sun package vendor information (default: distutils author info)"), ('pkg-email=', None, "sun package email information (default: distutils maintainer email)"), ('pkg-pstamp=', None, "sun package pstamp (default: )"), ('pkg-maxinst=', None, "sun package maxinst definition (default: %s)" % PKG_MAXINST), ('pkg-basedir=', None, "sun package destination base directory"), ('pkg-classes=', None, "sun package classes information (default: \"%s\")" % PKG_CLASSES), ('gzip', None, "gzip created package file"), ('distname-frompkg', None, "create distribution filename from PKG (default: off)"), ] boolean_options = ['keep-temp', 'gzip', 'distname-frompkg'] def initialize_options (self): self.bdist_dir = None self.prefix = None self.plat_name = None self.keep_temp = 0 self.dist_dir = None self.pkg_dir = None self.pkg_pkg = None self.pkg_prefix = None self.pkg_suffix = None self.pkg_name = None self.pkg_arch = None self.pkg_version = None self.pkg_desc = None self.pkg_category = None self.pkg_vendor = None self.pkg_maxinst = 1 self.pkg_email = None self.pkg_pstamp = None self.pkg_basedir = None self.pkg_classes = 'none' self.gzip = None self.distname_frompkg = 0 # initialize_options() def finalize_options(self): self.set_undefined_options('bdist', ('plat_name', 'plat_name'), ('dist_dir', 'dist_dir') ) if os.name != 'posix': raise DistutilsPlatformError, \ ("don't know how to create sunpkg " "distributions on platform %s" % os.name) else: # also check for the sun packaging programs pipe = os.popen('which pkgmk') try: try: if not os.path.exists(pipe.readlines()[0].strip()): raise DistutilsPlatformError, \ ("cannot invoke sunpkg packaging commands " "on platform %s - maybe set PATH" % os.uname()[0]) except IndexError: # Is which available on all posix platforms? raise DistutilsPlatformError, \ ("cannot find sunpkg packaging commands " "on platform %s - maybe set PATH" % os.uname()[0]) finally: pipe.close() if self.bdist_dir is None: bdist_base = self.get_finalized_command('bdist').bdist_base self.bdist_dir = os.path.join(bdist_base, 'sunpkg') if self.pkg_dir is None: bdist_base = self.get_finalized_command('bdist').bdist_base self.pkg_dir = os.path.join(bdist_base, "sunpkg-spool") # prevent from finalizing install if not necessary if self.pkg_basedir is None: self.pkg_basedir = \ self.get_finalized_command('install').install_base if self.pkg_prefix is None: self.pkg_prefix = '' if self.pkg_suffix is None: self.pkg_suffix = '' if self.pkg_name is None: self.pkg_name = self.distribution.get_name() if self.pkg_version is None: self.pkg_version = self.distribution.get_version() if self.pkg_pkg is None: self.pkg_pkg = (self.pkg_prefix + self.pkg_name + self.pkg_version.replace('.', '') + self.pkg_suffix) self.pkg_pkg = self.pkg_pkg[:self.PKG_MAXLEN] # Simply cut off? if self.pkg_arch is None: self.pkg_arch = self.PKG_ARCH if self.pkg_desc is None: self.pkg_desc = self.distribution.get_description() if self.pkg_category is None: self.pkg_category = self.PKG_CATEGORY if self.pkg_vendor is None: self.pkg_vendor = self.distribution.get_author() if self.pkg_email is None: self.pkg_email = self.distribution.get_contact_email() if self.pkg_pstamp is None: self.pkg_pstamp = '%s%s_%s' % (os.uname()[0], time.strftime('%Y%m%d%H%M', time.localtime()), getpass.getuser()) # create pkginfo file from distribution metadata def _make_pkginfo(self): pkginfo = [] pkginfo.append('PKG="%s"' % self.pkg_pkg) pkginfo.append('NAME="%s"' % self.pkg_name) pkginfo.append('ARCH="%s"' % self.pkg_arch) pkginfo.append('VERSION="%s"' % self.pkg_version) pkginfo.append('DESC="%s"' % self.pkg_desc) pkginfo.append('CATEGORY="%s"' % self.pkg_category) pkginfo.append('VENDOR="%s"' % self.pkg_vendor) pkginfo.append('MAXINST="%s"' % self.pkg_maxinst) pkginfo.append('EMAIL="%s"' % self.pkg_email) pkginfo.append('PSTAMP="%s"' % self.pkg_pstamp) pkginfo.append('BASEDIR="%s"' % self.pkg_basedir) pkginfo.append('CLASSES="%s"' % self.pkg_classes) return pkginfo # create prototype file from everything in build directory def _make_proto(self): self.prototype = [ 'i pkginfo=pkginfo', ] if not self.dry_run: cwdsave = os.getcwd() os.chdir(self.bdist_dir) os.path.walk('.', self.visitdir, None) os.chdir(cwdsave) return self.prototype def visitdir(self, arg, dirname, names): names.sort() for name in names: path = os.path.join(dirname[2:], name) mode = os.stat(path)[0] & 0777 # get mode from stat output if os.path.isfile(path): protoline='f none %s 0%o root other' % (path, mode) elif os.path.isdir(path): protoline='d none %s 0%o root other' % (path, mode) else: raise RuntimeError('%s is not file nor directory, not supported' % path) self.prototype.append(protoline) def run(self): log.info("bdist_sunpkg: installing to %s" % self.bdist_dir) # this will call install.finalize_options a second time # the install will run the build command if necessary install = self.reinitialize_command('install', reinit_subcommands=1) install.prefix = self.bdist_dir if self.prefix: if os.path.isabs(self.prefix): self.prefix = self.prefix[1:] install.prefix = os.path.join(install.prefix, self.prefix) install.ensure_finalized() install.run() pkginfo = self._make_pkginfo() log.debug('pkginfo =', '\n'.join(pkginfo)) log.debug('bdist_dir =', self.bdist_dir) log.debug('pkg_dir =', self.pkg_dir) log.debug('verbose =', self.verbose) pkginfo_file = os.path.join(self.bdist_dir, 'pkginfo') prototype_file = os.path.join(self.bdist_dir, 'prototype') if os.path.exists(pkginfo_file): os.remove(pkginfo_file) if os.path.exists(prototype_file): os.remove(prototype_file) proto = self._make_proto() log.debug('proto:', '\n'.join(proto)) if os.path.exists(self.pkg_dir): dir_util.remove_tree(self.pkg_dir, dry_run=self.dry_run) dir_util.mkpath(self.pkg_dir, dry_run=self.dry_run) file_util.write_file(pkginfo_file, pkginfo, self.verbose, self.dry_run) file_util.write_file(prototype_file, proto, self.verbose, self.dry_run) # Make an archive relative to the root of the # pseudo-installation tree. if self.distname_frompkg: archive_basename = "%s" % (self.pkg_pkg, ) else: archive_basename = "%s.%s" % (self.distribution.get_fullname(), self.plat_name) pkgfile = os.path.abspath(os.path.join(self.dist_dir, archive_basename) + self.PKG_EXTENSION) cmd = ['pkgmk', '-o', '-f', prototype_file, '-r', self.bdist_dir, '-d', self.pkg_dir] self.spawn(cmd) if os.path.exists(pkgfile): os.remove(pkgfile) dir_util.mkpath(self.dist_dir, dry_run=self.dry_run) cmd = ['pkgtrans','-so', os.path.abspath(self.pkg_dir), pkgfile, self.pkg_pkg] self.spawn(cmd) if self.gzip: if os.path.exists(pkgfile + '.gz'): os.remove(pkgfile + '.gz') cmd = ['gzip', pkgfile] self.spawn(cmd) if not self.keep_temp: dir_util.remove_tree(self.bdist_dir, self.verbose, self.dry_run) dir_util.remove_tree(self.pkg_dir, self.verbose, self.dry_run)