--- .gitignore | 1 + MANIFEST.in | 19 ++ Makefile | 215 ------------------- doc/Makefile | 11 - mkrelease.sh | 141 ------------- pym/portage/const.py | 4 +- setup.py | 578 +++++++++++++++++++++++++++++++++++++++++++++++++++ 7 files changed, 600 insertions(+), 369 deletions(-) create mode 100644 MANIFEST.in delete mode 100644 Makefile delete mode 100644 doc/Makefile delete mode 100755 mkrelease.sh create mode 100755 setup.py
diff --git a/.gitignore b/.gitignore index 074bb86..c2dd534 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ *.py[co] __pycache__/ *.class +/build /tags diff --git a/MANIFEST.in b/MANIFEST.in new file mode 100644 index 0000000..a005ab9 --- /dev/null +++ b/MANIFEST.in @@ -0,0 +1,19 @@ +# docs +include DEVELOPING +include LICENSE +include TEST-NOTES + +# docbook sources +include doc/custom.xsl +include doc/fragment/* +recursive-include doc *.docbook + +# extra conf files used in ebuild +include cnf/make.conf.example.* + +# extra files for tests +include .portage_not_installed +include cnf/metadata.dtd + +# extra scripts +include misc/* diff --git a/Makefile b/Makefile deleted file mode 100644 index 9eb6e66..0000000 --- a/Makefile +++ /dev/null @@ -1,215 +0,0 @@ -SHELL = /bin/sh -PN ?= portage -PF ?= portage -HOMEPAGE ?= http://www.gentoo.org/proj/en/portage/index.xml -PWD ?= $(shell pwd) -S ?= $(PWD) -WORKDIR ?= $(PWD) -DESTDIR = $(PWD)/image/ -srcdir = $(S) -prefix = /usr -sysconfdir = /etc -exec_prefix = $(prefix) -bindir = $(exec_prefix)/bin -sbindir = $(exec_prefix)/sbin -libdir = $(exec_prefix)/lib -datarootdir = $(prefix)/share -datadir = $(datarootdir) -mandir = $(datarootdir)/man -docdir = $(datarootdir)/doc/$(PF) -htmldir = $(docdir)/html -portage_datadir = $(datarootdir)/$(PN) -portage_confdir = $(portage_datadir)/config -portage_setsdir = $(portage_confdir)/sets -portage_base = $(libdir)/$(PN) -EPYDOC_OPTS = -qqqqq --no-frames --show-imports -INSMODE = 0644 -EXEMODE = 0755 -DIRMODE = 0755 -SYSCONFDIR_FILES = etc-update.conf dispatch-conf.conf -PORTAGE_CONFDIR_FILES = make.conf.example make.globals repos.conf -LOGROTATE_FILES = elog-save-summary -BINDIR_FILES = ebuild egencache emerge emerge-webrsync \ - emirrordist portageq quickpkg repoman -SBINDIR_FILES = archive-conf dispatch-conf emaint \ - env-update etc-update fixpackages regenworld -DOCS = ChangeLog NEWS RELEASE-NOTES -LINGUAS ?= $(shell cd "$(srcdir)/man" && find -mindepth 1 -type d) - -ifdef PYTHONPATH - PYTHONPATH := $(srcdir)/pym:$(PYTHONPATH) -else - PYTHONPATH := $(srcdir)/pym -endif - -all: docbook epydoc - -docbook: - set -e; \ - touch "$(srcdir)/doc/fragment/date"; \ - $(MAKE) -C "$(srcdir)/doc" xhtml xhtml-nochunks - -epydoc: - set -e; \ - env PYTHONPATH="$(PYTHONPATH)" epydoc \ - -o "$(WORKDIR)/epydoc" \ - --name $(PN) \ - --url "$(HOMEPAGE)" \ - $(EPYDOC_OPTS) \ - $$(cd "$(srcdir)" && find pym -name '*.py' | sed \ - -e s:/__init__.py$$:: \ - -e s:\.py$$:: \ - -e s:^pym/:: \ - -e s:/:.:g \ - | sort); \ - rm -f "$(WORKDIR)/epydoc/api-objects.txt"; \ - -test: - set -e; \ - "$(srcdir)/pym/portage/tests/runTests.py"; \ - -install: - set -e; \ - cd "$(srcdir)/cnf"; \ - install -d -m$(DIRMODE) "$(DESTDIR)$(sysconfdir)"; \ - install -m$(INSMODE) $(SYSCONFDIR_FILES) "$(DESTDIR)$(sysconfdir)"; \ - \ - install -d -m$(DIRMODE) "$(DESTDIR)$(portage_confdir)"; \ - cd "$(srcdir)/cnf"; \ - install -m$(INSMODE) $(PORTAGE_CONFDIR_FILES) \ - "$(DESTDIR)$(portage_confdir)"; \ - install -d -m$(DIRMODE) "$(DESTDIR)$(portage_setsdir)"; \ - cd "$(S)/cnf/sets"; \ - install -m$(INSMODE) *.conf "$(DESTDIR)$(portage_setsdir)"; \ - \ - install -d -m$(DIRMODE) "$(DESTDIR)$(sysconfdir)/logrotate.d"; \ - cd "$(srcdir)/cnf/logrotate.d"; \ - install -m$(INSMODE) $(LOGROTATE_FILES) \ - "$(DESTDIR)$(sysconfdir)/logrotate.d"; \ - \ - for x in $$(cd "$(srcdir)" && find bin -type d) ; do \ - cd "$(srcdir)/$$x"; \ - install -d -m$(DIRMODE) "$(DESTDIR)$(portage_base)/$$x"; \ - files=$$(find . -mindepth 1 -maxdepth 1 -type f ! -type l); \ - if [ -n "$$files" ] ; then \ - install -m$(EXEMODE) $$files \ - "$(DESTDIR)$(portage_base)/$$x"; \ - fi; \ - symlinks=$$(find . -mindepth 1 -maxdepth 1 -type l); \ - if [ -n "$$symlinks" ] ; then \ - cp -P $$symlinks "$(DESTDIR)$(portage_base)/$$x"; \ - fi; \ - done; \ - \ - for x in $$(cd "$(srcdir)" && find pym/* -type d \ - ! -path "pym/portage/tests*") ; do \ - cd "$(srcdir)/$$x"; \ - files=$$(echo *.py); \ - if [ -z "$$files" ] || [ "$$files" = "*.py" ]; then \ - # __pycache__ directories contain no py files \ - continue; \ - fi; \ - install -d -m$(DIRMODE) "$(DESTDIR)$(portage_base)/$$x"; \ - install -m$(INSMODE) $$files "$(DESTDIR)$(portage_base)/$$x"; \ - done; \ - \ - install -d -m$(DIRMODE) "$(DESTDIR)$(bindir)"; \ - relative_path=".."; \ - x=$(bindir) ; \ - y="$(portage_base)"; \ - if [ "$${x#$(prefix)}" != "$$x" ] && \ - [ "$${y#$(prefix)}" != "$$y" ]; then \ - x=$${x#$(prefix)}; \ - y=$${y#$(prefix)}; \ - fi; \ - x=$${x%/*}; \ - while [ -n "$$x" ] ; do \ - relative_path=$${relative_path}/..; \ - x=$${x%/*}; \ - done; \ - relative_path=$$relative_path$$y; \ - for x in $(BINDIR_FILES) ; do \ - ln -sf "$$relative_path/bin/$$x" \ - "$(DESTDIR)$(bindir)/$$x"; \ - done; \ - \ - install -d -m$(DIRMODE) "$(DESTDIR)$(sbindir)"; \ - relative_path=".."; \ - x=$(sbindir) ; \ - y="$(portage_base)"; \ - if [ "$${x#$(prefix)}" != "$$x" ] && \ - [ "$${y#$(prefix)}" != "$$y" ]; then \ - x=$${x#$(prefix)}; \ - y=$${y#$(prefix)}; \ - fi; \ - x=$${x%/*}; \ - while [ -n "$$x" ] ; do \ - relative_path=$${relative_path}/..; \ - x=$${x%/*}; \ - done; \ - relative_path=$$relative_path$$y; \ - for x in $(SBINDIR_FILES) ; do \ - ln -sf "$$relative_path/bin/$$x" \ - "$(DESTDIR)$(sbindir)/$$x"; \ - done; \ - \ - ln -sf "$$relative_path/bin/env-update" \ - "$(DESTDIR)$(sbindir)/update-env"; \ - ln -sf "$$relative_path/bin/etc-update" \ - "$(DESTDIR)$(sbindir)/update-etc"; \ - \ - # We install some minimal tests for use as a preinst sanity check. \ - # These tests must be able to run without a full source tree and \ - # without relying on a previous portage instance being installed. \ - install -d -m$(DIRMODE) \ - "$(DESTDIR)$(portage_base)/pym/portage/tests"; \ - install -m$(EXEMODE) "$(srcdir)/pym/portage/tests/runTests" \ - "$(DESTDIR)$(portage_base)/pym/portage/tests"; \ - cd "$(srcdir)/pym/portage/tests"; \ - install -m$(INSMODE) *.py \ - "$(DESTDIR)$(portage_base)/pym/portage/tests"; \ - install -d -m$(DIRMODE) \ - "$(DESTDIR)$(portage_base)/pym/portage/tests/lint"; \ - cd "$(srcdir)/pym/portage/tests/lint"; \ - install -m$(INSMODE) *.py __test__ \ - "$(DESTDIR)$(portage_base)/pym/portage/tests/lint"; \ - \ - install -d -m$(DIRMODE) "$(DESTDIR)$(docdir)"; \ - cd "$(srcdir)"; \ - install -m $(INSMODE) $(DOCS) "$(DESTDIR)$(docdir)"; \ - \ - for x in "" $(LINGUAS); do \ - for y in 1 5 ; do \ - if [ -d "$(srcdir)/man/$$x" ]; then \ - cd "$(srcdir)/man/$$x"; \ - files=$$(echo *.$$y); \ - if [ -z "$$files" ] || [ "$$files" = "*.$$y" ]; then \ - continue; \ - fi; \ - install -d -m$(DIRMODE) "$(DESTDIR)$(mandir)/$$x/man$$y"; \ - install -m$(INSMODE) *.$$y "$(DESTDIR)$(mandir)/$$x/man$$y"; \ - fi; \ - done; \ - done; \ - \ - if [ -f "$(srcdir)/doc/portage.html" ] ; then \ - install -d -m$(DIRMODE) "$(DESTDIR)$(htmldir)"; \ - cd "$(srcdir)/doc"; \ - install -m$(INSMODE) *.html "$(DESTDIR)$(htmldir)"; \ - fi; \ - \ - if [ -d "$(WORKDIR)/epydoc" ] ; then \ - install -d -m$(DIRMODE) "$(DESTDIR)$(htmldir)"; \ - cp -pPR "$(WORKDIR)/epydoc" \ - "$(DESTDIR)$(htmldir)/api"; \ - cd "$(DESTDIR)$(htmldir)/api"; \ - find . -type d | xargs chmod $(DIRMODE); \ - find . -type f | xargs chmod $(INSMODE); \ - fi; \ - -clean: - set -e; \ - $(MAKE) -C "$(srcdir)/doc" clean; \ - rm -rf "$(WORKDIR)/epydoc"; \ - -.PHONY: all clean docbook epydoc install test diff --git a/doc/Makefile b/doc/Makefile deleted file mode 100644 index 261a0b4..0000000 --- a/doc/Makefile +++ /dev/null @@ -1,11 +0,0 @@ -all: xhtml xhtml-nochunks - -XMLTO_FLAGS = -m custom.xsl -man pdf txt xhtml xhtml-nochunks: - xmlto $@ $(XMLTO_FLAGS) portage.docbook - -clean distclean: - rm -f *.1 *.html portage.txt - -.PHONY: all clean distclean \ - man pdf txt xhtml xhtml-nochunks diff --git a/mkrelease.sh b/mkrelease.sh deleted file mode 100755 index f9f7564..0000000 --- a/mkrelease.sh +++ /dev/null @@ -1,141 +0,0 @@ -#!/bin/bash -# Copyright 2008-2014 Gentoo Foundation -# Distributed under the terms of the GNU General Public License v2 - -RELEASE_BUILDDIR=${RELEASE_BUILDDIR:-/var/tmp/portage-release} -SOURCE_DIR=${RELEASE_BUILDDIR}/checkout -BRANCH=${BRANCH:-master} -USE_TAG=false -CHANGELOG_REVISION= -UPLOAD_LOCATION= -RUNTESTS=false -USER= - -usage() { - echo "Usage: ${0##*/} [--changelog-rev <tree-ish>] [-t|--tag] [-u|--upload <location>] [--user <username>] [--runtests] <version>" - exit ${1:-0} -} - -die() { - printf 'error: %s\n' "$*" - usage 1 -} - -ARGS=$(getopt -o htu: --long help,changelog-rev:,runtests,tag,upload:,user: \ - -n "${0##*/}" -- "$@") -[ $? != 0 ] && die "initialization error" - -eval set -- "${ARGS}" - -while true; do - case $1 in - --changelog-rev) - CHANGELOG_REVISION=$2 - shift 2 - ;; - -t|--tag) - USE_TAG=true - shift - ;; - -u|--upload) - UPLOAD_LOCATION=$2 - shift 2 - ;; - --user) - USER=$2"@" - shift 2 - ;; - -h|--help) - usage - ;; - --runtests) - RUNTESTS=true - shift - ;; - --) - shift - break - ;; - *) - die "unknown option: $1" - ;; - esac -done - -[ $# != 1 ] && die "Need version argument" -[[ -n ${1/[0-9]*} ]] && die "Invalid version argument" - -VERSION=$1 -RELEASE=portage-${VERSION} -RELEASE_DIR=${RELEASE_BUILDDIR}/${RELEASE} -RELEASE_TARBALL="${RELEASE_BUILDDIR}/${RELEASE}.tar.bz2" -TREE_ISH=${BRANCH} -if [[ ${USE_TAG} == "true" ]] ; then - TREE_ISH="v${VERSION}" -fi - -echo ">>> Cleaning working directories ${RELEASE_DIR} ${SOURCE_DIR}" -rm -rf "${RELEASE_DIR}" "${SOURCE_DIR}" || die "directory cleanup failed" -mkdir -p "${RELEASE_DIR}" || die "directory creation failed" -mkdir -p "${SOURCE_DIR}" || die "mkdir failed" - -echo ">>> Starting GIT archive" -git archive --format=tar ${TREE_ISH} | \ - tar -xf - -C "${SOURCE_DIR}" || die "git archive failed" - -echo ">>> Building release tree" -cp -a "${SOURCE_DIR}/"{bin,cnf,doc,man,misc,pym} "${RELEASE_DIR}/" || die "directory copy failed" -cp "${SOURCE_DIR}/"{.portage_not_installed,DEVELOPING,LICENSE,Makefile,NEWS,README,RELEASE-NOTES,TEST-NOTES} \ - "${RELEASE_DIR}/" || die "file copy failed" - -if [[ ${RUNTESTS} == "true" ]] ; then - pushd "${SOURCE_DIR}" >/dev/null - ./runtests.sh --python-versions=supported || die "tests failed" - popd >/dev/null -fi - -rm -rf "${SOURCE_DIR}" || die "directory cleanup failed" - -echo ">>> Setting portage.VERSION" -sed -e "s/^VERSION = .*/VERSION = \"${VERSION}\"/" \ - -i "${RELEASE_DIR}/pym/portage/__init__.py" || \ - die "Failed to patch portage.VERSION" - -echo ">>> Creating Changelog" -git_log_opts="" -if [[ -n ${CHANGELOG_REVISION} ]] ; then - git_log_opts+=" ${CHANGELOG_REVISION}^..${TREE_ISH}" -else - git_log_opts+=" ${TREE_ISH}" -fi -skip_next=false -git log ${git_log_opts} | fmt -w 80 -p " " | while read -r ; do - if [[ ${skip_next} == "true" ]] ; then - skip_next=false - elif [[ ${REPLY} == " svn path="* ]] ; then - skip_next=true - else - echo "${REPLY}" - fi -done > "${RELEASE_DIR}/ChangeLog" || die "ChangeLog creation failed" - -cd "${RELEASE_BUILDDIR}" - -echo ">>> Creating release tarball ${RELEASE_TARBALL}" -tar --owner portage --group portage -cjf "${RELEASE_TARBALL}" "${RELEASE}" || \ - die "tarball creation failed" - -DISTDIR=$(portageq distdir) -if [[ -n ${DISTDIR} && -d ${DISTDIR} && -w ${DISTDIR} ]] ; then - echo ">>> Copying release tarball into ${DISTDIR}" - cp "${RELEASE_TARBALL}" "${DISTDIR}"/ || echo "!!! tarball copy failed" -fi - -if [[ -n ${UPLOAD_LOCATION} ]] ; then - echo ">>> Uploading ${RELEASE_TARBALL} to ${USER}dev.gentoo.org:${UPLOAD_LOCATION}" - scp "${RELEASE_TARBALL}" "${USER}dev.gentoo.org:${UPLOAD_LOCATION}" || die "upload failed" -else - du -h "${RELEASE_TARBALL}" -fi - -exit 0 diff --git a/pym/portage/const.py b/pym/portage/const.py index f518b47..acb90f9 100644 --- a/pym/portage/const.py +++ b/pym/portage/const.py @@ -60,8 +60,8 @@ GLOBAL_CONFIG_PATH = "/usr/share/portage/config" # these variables are not used with target_root or config_root # NOTE: Use realpath(__file__) so that python module symlinks in site-packages # are followed back to the real location of the whole portage installation. -PORTAGE_BASE_PATH = os.path.join(os.sep, os.sep.join(os.path.realpath( - __file__.rstrip("co")).split(os.sep)[:-3])) +# NOTE: Please keep PORTAGE_BASE_PATH in one line to help substitutions. +PORTAGE_BASE_PATH = os.path.join(os.sep, os.sep.join(os.path.realpath(__file__.rstrip("co")).split(os.sep)[:-3])) PORTAGE_BIN_PATH = PORTAGE_BASE_PATH + "/bin" PORTAGE_PYM_PATH = os.path.realpath(os.path.join(__file__, '../..')) LOCALE_DATA_PATH = PORTAGE_BASE_PATH + "/locale" # FIXME: not used diff --git a/setup.py b/setup.py new file mode 100755 index 0000000..7ffe7f0 --- /dev/null +++ b/setup.py @@ -0,0 +1,578 @@ +#!/usr/bin/env python +# vim:fileencoding=utf-8 +# (c) 2010 Michał Górny <mgo...@gentoo.org> +# Released under the terms of the 2-clause BSD license. + +from distutils.core import setup, Command +from distutils.command.build_scripts import build_scripts +from distutils.command.clean import clean +from distutils.command.install import install +from distutils.command.install_data import install_data +from distutils.command.install_lib import install_lib +from distutils.command.install_scripts import install_scripts +from distutils.command.sdist import sdist +from distutils.dir_util import remove_tree +from distutils.util import change_root, subst_vars + +import codecs, collections, glob, os, os.path, re, subprocess, sys + +# TODO: +# - smarter rebuilds of docs w/ 'install_docbook' and 'install_epydoc'. + +x_scripts = { + 'bin': [ + 'bin/ebuild', 'bin/egencache', 'bin/emerge', 'bin/emerge-webrsync', + 'bin/emirrordist', 'bin/portageq', 'bin/quickpkg', 'bin/repoman' + ], + 'sbin': [ + 'bin/archive-conf', 'bin/dispatch-conf', 'bin/emaint', 'bin/env-update', + 'bin/etc-update', 'bin/fixpackages', 'bin/regenworld' + ], +} + + +class docbook(Command): + """ Build docs using docbook. """ + + user_options = [ + ('doc-formats=', None, 'Documentation formats to build (all xmlto formats for docbook are allowed, comma-separated'), + ] + + def initialize_options(self): + self.doc_formats = 'xhtml,xhtml-nochunks' + + def finalize_options(self): + self.doc_formats = self.doc_formats.replace(',', ' ').split() + + def run(self): + with open('doc/fragment/date', 'w'): + pass + + for f in self.doc_formats: + print('Building docs in %s format...' % f) + subprocess.check_call(['xmlto', '-o', 'doc', + '-m', 'doc/custom.xsl', f, 'doc/portage.docbook']) + + +class epydoc(Command): + """ Build API docs using epydoc. """ + + user_options = [ + ] + + def initialize_options(self): + self.build_lib = None + + def finalize_options(self): + self.set_undefined_options('build_py', ('build_lib', 'build_lib')) + + def run(self): + self.run_command('build_py') + + print('Building API documentation...') + + process_env = os.environ.copy() + pythonpath = self.build_lib + try: + pythonpath += ':' + process_env['PYTHONPATH'] + except KeyError: + pass + process_env['PYTHONPATH'] = pythonpath + + subprocess.check_call(['epydoc', '-o', 'epydoc', + '--name', self.distribution.get_name(), + '--url', self.distribution.get_url(), + '-qq', '--no-frames', '--show-imports', + '--exclude', 'portage.tests', + '_emerge', 'portage', 'repoman'], + env = process_env) + os.remove('epydoc/api-objects.txt') + + +class install_docbook(install_data): + """ install_data for docbook docs """ + + user_options = install_data.user_options + + def initialize_options(self): + install_data.initialize_options(self) + self.htmldir = None + + def finalize_options(self): + self.set_undefined_options('install', ('htmldir', 'htmldir')) + install_data.finalize_options(self) + + def run(self): + if not os.path.exists('doc/portage.html'): + self.run_command('docbook') + self.data_files = [ + (self.htmldir, glob.glob('doc/*.html')), + ] + install_data.run(self) + + +class install_epydoc(install_data): + """ install_data for epydoc docs """ + + user_options = install_data.user_options + + def initialize_options(self): + install_data.initialize_options(self) + self.htmldir = None + + def finalize_options(self): + self.set_undefined_options('install', ('htmldir', 'htmldir')) + install_data.finalize_options(self) + + def run(self): + if not os.path.exists('epydoc/index.html'): + self.run_command('epydoc') + self.data_files = [ + (os.path.join(self.htmldir, 'api'), glob.glob('epydoc/*')), + ] + install_data.run(self) + + +class x_build_scripts_custom(build_scripts): + def finalize_options(self): + build_scripts.finalize_options(self) + if 'dir_name' in dir(self): + self.build_dir = os.path.join(self.build_dir, self.dir_name) + if self.dir_name in x_scripts: + self.scripts = x_scripts[self.dir_name] + else: + self.scripts = set(self.scripts) + for other_files in x_scripts.values(): + self.scripts.difference_update(other_files) + + def run(self): + # group scripts by subdirectory + split_scripts = collections.defaultdict(list) + for f in self.scripts: + dir_name = os.path.dirname(f[len('bin/'):]) + split_scripts[dir_name].append(f) + + base_dir = self.build_dir + base_scripts = self.scripts + for d, files in split_scripts.items(): + self.build_dir = os.path.join(base_dir, d) + self.scripts = files + self.copy_scripts() + + # restore previous values + self.build_dir = base_dir + self.scripts = base_scripts + + +class x_build_scripts_bin(x_build_scripts_custom): + dir_name = 'bin' + + +class x_build_scripts_sbin(x_build_scripts_custom): + dir_name = 'sbin' + + +class x_build_scripts_portagebin(x_build_scripts_custom): + dir_name = 'portage' + + +class x_build_scripts(build_scripts): + def initialize_option(self): + build_scripts.initialize_options(self) + + def finalize_options(self): + build_scripts.finalize_options(self) + + def run(self): + self.run_command('build_scripts_bin') + self.run_command('build_scripts_portagebin') + self.run_command('build_scripts_sbin') + + +class x_clean(clean): + """ clean extended for doc & post-test cleaning """ + + def clean_docs(self): + def get_doc_outfiles(): + for dirpath, dirnames, filenames in os.walk('doc'): + for f in filenames: + if f.endswith('.docbook') or f == 'custom.xsl': + pass + else: + yield os.path.join(dirpath, f) + + # do not recurse + break + + + for f in get_doc_outfiles(): + print('removing %s' % repr(f)) + os.remove(f) + + if os.path.isdir('epydoc'): + remove_tree('epydoc') + + def clean_tests(self): + # do not remove incorrect dirs accidentally + top_dir = os.path.normpath(os.path.join(self.build_lib, '..')) + cprefix = os.path.commonprefix((self.build_base, top_dir)) + if cprefix != self.build_base: + return + + bin_dir = os.path.join(top_dir, 'bin') + if os.path.exists(bin_dir): + remove_tree(bin_dir) + + conf_dir = os.path.join(top_dir, 'cnf') + if os.path.islink(conf_dir): + print('removing %s symlink' % repr(conf_dir)) + os.unlink(conf_dir) + + pni_file = os.path.join(top_dir, '.portage_not_installed') + if os.path.exists(pni_file): + print('removing %s' % repr(pni_file)) + os.unlink(pni_file) + + def run(self): + if self.all: + self.clean_tests() + self.clean_docs() + + clean.run(self) + + +class x_install(install): + """ install command with extra Portage paths """ + + user_options = install.user_options + [ + # note: $prefix and $exec_prefix are reserved for Python install + ('system-prefix=', None, "Prefix for architecture-independent data"), + ('system-exec-prefix=', None, "Prefix for architecture-specific data"), + + ('bindir=', None, "Install directory for main executables"), + ('datarootdir=', None, "Data install root directory"), + ('docdir=', None, "Documentation install directory"), + ('htmldir=', None, "HTML documentation install directory"), + ('mandir=', None, "Manpage root install directory"), + ('portage-base=', 'b', "Portage install base"), + ('portage-bindir=', None, "Install directory for Portage internal-use executables"), + ('portage-datadir=', None, 'Install directory for data files'), + ('sbindir=', None, "Install directory for superuser-intended executables"), + ('sysconfdir=', None, 'System configuration path'), + ] + + # note: the order is important for proper substitution + paths = [ + ('system_prefix', '/usr'), + ('system_exec_prefix', '$system_prefix'), + + ('bindir', '$system_exec_prefix/bin'), + ('sbindir', '$system_exec_prefix/sbin'), + ('sysconfdir', '/etc'), + + ('datarootdir', '$system_prefix/share'), + ('docdir', '$datarootdir/doc/$package-$version'), + ('htmldir', '$docdir/html'), + ('mandir', '$datarootdir/man'), + + ('portage_base', '$system_exec_prefix/lib/portage'), + ('portage_bindir', '$portage_base/bin'), + ('portage_datadir', '$datarootdir/portage'), + + # not customized at the moment + ('logrotatedir', '$sysconfdir/logrotate'), + ('portage_confdir', '$portage_datadir/config'), + ('portage_setsdir', '$portage_confdir/sets'), + ] + + def initialize_options(self): + install.initialize_options(self) + + for key, default in self.paths: + setattr(self, key, default) + self.subst_paths = {} + + def finalize_options(self): + install.finalize_options(self) + + # substitute variables + new_paths = { + 'package': self.distribution.get_name(), + 'version': self.distribution.get_version(), + } + for key, default in self.paths: + new_paths[key] = subst_vars(getattr(self, key), new_paths) + setattr(self, key, new_paths[key]) + self.subst_paths = new_paths + + +class x_install_data(install_data): + """ install_data with customized path support """ + + user_options = install_data.user_options + + def initialize_options(self): + install_data.initialize_options(self) + self.paths = None + + def finalize_options(self): + install_data.finalize_options(self) + self.set_undefined_options('install', + ('subst_paths', 'paths')) + + # substitute variables in data_files + for f in self.data_files: + f[0] = subst_vars(f[0], self.paths) + + +class x_install_lib(install_lib): + """ install_lib command with Portage path substitution """ + + user_options = install_lib.user_options + + def initialize_options(self): + install_lib.initialize_options(self) + self.portage_base = None + self.portage_bindir = None + self.portage_confdir = None + + def finalize_options(self): + install_lib.finalize_options(self) + self.set_undefined_options('install', + ('portage_base', 'portage_base'), + ('portage_bindir', 'portage_bindir'), + ('portage_confdir', 'portage_confdir')) + + def install(self): + ret = install_lib.install(self) + + def rewrite_file(path, val_dict): + path = os.path.join(self.install_dir, path) + print('Rewriting %s' % path) + with codecs.open(path, 'r', 'utf-8') as f: + data = f.read() + + for varname, val in val_dict.items(): + regexp = r'^(%s\s*=).*$' % varname + repl = r'\1 %s' % repr(val) + + data = re.sub(regexp, repl, data, 0, re.MULTILINE) + + with codecs.open(path, 'w', 'utf-8') as f: + f.write(data) + + rewrite_file('portage/__init__.py', { + 'VERSION': self.distribution.get_version(), + }) + rewrite_file('portage/const.py', { + 'PORTAGE_BASE_PATH': self.portage_base, + 'PORTAGE_BIN_PATH': self.portage_bindir, + 'PORTAGE_CONFIG_PATH': self.portage_confdir, + }) + + return ret + + +class x_install_scripts_custom(install_scripts): + def initialize_options(self): + install_scripts.initialize_options(self) + self.root = None + + def finalize_options(self): + self.set_undefined_options('install', + ('root', 'root'), + (self.var_name, 'install_dir')) + install_scripts.finalize_options(self) + self.build_dir = os.path.join(self.build_dir, self.dir_name) + + # prepend root + if self.root is not None: + self.install_dir = change_root(self.root, self.install_dir) + + +class x_install_scripts_bin(x_install_scripts_custom): + dir_name = 'bin' + var_name = 'bindir' + + +class x_install_scripts_sbin(x_install_scripts_custom): + dir_name = 'sbin' + var_name = 'sbindir' + + +class x_install_scripts_portagebin(x_install_scripts_custom): + dir_name = 'portage' + var_name = 'portage_bindir' + + +class x_install_scripts(install_scripts): + def initialize_option(self): + pass + + def finalize_options(self): + pass + + def run(self): + self.run_command('install_scripts_bin') + self.run_command('install_scripts_portagebin') + self.run_command('install_scripts_sbin') + + +class x_sdist(sdist): + """ sdist defaulting to .tar.bz2 format """ + + def finalize_options(self): + if self.formats is None: + self.formats = ['bztar'] + + sdist.finalize_options(self) + + +class build_tests(x_build_scripts_custom): + """ Prepare build dir for running tests. """ + + def initialize_options(self): + x_build_scripts_custom.initialize_options(self) + self.build_base = None + self.build_lib = None + + def finalize_options(self): + x_build_scripts_custom.finalize_options(self) + self.set_undefined_options('build', + ('build_base', 'build_base'), + ('build_lib', 'build_lib')) + + # since we will be writing to $build_lib/.., it is important + # that we do not leave $build_base + self.top_dir = os.path.normpath(os.path.join(self.build_lib, '..')) + cprefix = os.path.commonprefix((self.build_base, self.top_dir)) + if cprefix != self.build_base: + raise SystemError('build_lib must be a subdirectory of build_base') + + self.build_dir = os.path.join(self.top_dir, 'bin') + + def run(self): + self.run_command('build_py') + + # install all scripts $build_lib/../bin + # (we can't do a symlink since we want shebangs corrected) + x_build_scripts_custom.run(self) + + # symlink 'cnf' directory + conf_dir = os.path.join(self.top_dir, 'cnf') + if os.path.exists(conf_dir): + if not os.path.islink(conf_dir): + raise SystemError('%s exists and is not a symlink (collision)' + % repr(conf_dir)) + os.unlink(conf_dir) + conf_src = os.path.relpath('cnf', self.top_dir) + print('Symlinking %s -> %s' % (conf_dir, conf_src)) + os.symlink(conf_src, conf_dir) + + # create $build_lib/../.portage_not_installed + # to enable proper paths in tests + with open(os.path.join(self.top_dir, '.portage_not_installed'), 'w') as f: + pass + + +class test(Command): + """ run tests """ + + user_options = [] + + def initialize_options(self): + self.build_lib = None + + def finalize_options(self): + self.set_undefined_options('build', + ('build_lib', 'build_lib')) + + def run(self): + self.run_command('build_tests') + subprocess.check_call([ + sys.executable, '-bWd', + os.path.join(self.build_lib, 'portage/tests/runTests.py') + ]) + + +def find_packages(): + for dirpath, dirnames, filenames in os.walk('pym'): + if '__init__.py' in filenames: + yield os.path.relpath(dirpath, 'pym') + + +def find_scripts(): + for dirpath, dirnames, filenames in os.walk('bin'): + for f in filenames: + yield os.path.join(dirpath, f) + + +def get_manpages(): + linguas = os.environ.get('LINGUAS') + if linguas is not None: + linguas = linguas.split() + + for dirpath, dirnames, filenames in os.walk('man'): + groups = collections.defaultdict(list) + for f in filenames: + fn, suffix = f.rsplit('.', 1) + groups[suffix].append(os.path.join(dirpath, f)) + + topdir = dirpath[len('man/'):] + if not topdir or linguas is None or topdir in linguas: + for g, mans in groups.items(): + yield [os.path.join('$mandir', topdir, 'man%s' % g), mans] + +setup( + name = 'portage', + version = '2.2.12', + url = 'https://wiki.gentoo.org/wiki/Project:Portage', + author = 'Gentoo Portage Development Team', + author_email = 'dev-port...@gentoo.org', + + package_dir = {'': 'pym'}, + packages = list(find_packages()), + # something to cheat build & install commands + scripts = list(find_scripts()), + + data_files = list(get_manpages()) + [ + ['$sysconfdir', ['cnf/etc-update.conf', 'cnf/dispatch-conf.conf']], + ['$logrotatedir', ['cnf/logrotate.d/elog-save-summary']], + ['$portage_confdir', [ + 'cnf/make.conf.example', 'cnf/make.globals', 'cnf/repos.conf']], + ['$portage_setsdir', ['cnf/sets/portage.conf']], + ['$docdir', ['NEWS', 'RELEASE-NOTES']], + ], + + cmdclass = { + 'build_scripts': x_build_scripts, + 'build_scripts_bin': x_build_scripts_bin, + 'build_scripts_portagebin': x_build_scripts_portagebin, + 'build_scripts_sbin': x_build_scripts_sbin, + 'build_tests': build_tests, + 'clean': x_clean, + 'docbook': docbook, + 'epydoc': epydoc, + 'install': x_install, + 'install_data': x_install_data, + 'install_docbook': install_docbook, + 'install_epydoc': install_epydoc, + 'install_lib': x_install_lib, + 'install_scripts': x_install_scripts, + 'install_scripts_bin': x_install_scripts_bin, + 'install_scripts_portagebin': x_install_scripts_portagebin, + 'install_scripts_sbin': x_install_scripts_sbin, + 'sdist': x_sdist, + 'test': test, + }, + + classifiers = [ + 'Development Status :: 5 - Production/Stable', + 'Environment :: Console', + 'Intended Audience :: System Administrators', + 'License :: OSI Approved :: GNU General Public License v2 (GPLv2)', + 'Operating System :: POSIX', + 'Programming Language :: Python', + 'Topic :: System :: Installation/Setup' + ] +) -- 2.0.4