From: "Michał Górny" <mgorny@gentoo.org>
To: gentoo-portage-dev@lists.gentoo.org
Cc: "Michał Górny" <mgorny@gentoo.org>
Subject: [gentoo-portage-dev] [PATCH v3] Install Portage using setup.py
Date: Fri, 5 Sep 2014 08:58:42 +0200 [thread overview]
Message-ID: <1409900322-1962-1-git-send-email-mgorny@gentoo.org> (raw)
In-Reply-To: <1408825856-12510-1-git-send-email-mgorny@gentoo.org>
Changes in v2:
- 'sdist' support
Changes in v3:
- version substituted properly in docs & mans
- cleaner handling of install_data
---
.gitignore | 1 +
MANIFEST.in | 18 ++
Makefile | 215 -----------------
doc/Makefile | 11 -
doc/fragment/date | 0
doc/fragment/version | 1 -
mkrelease.sh | 141 -----------
pym/portage/const.py | 4 +-
setup.py | 657 +++++++++++++++++++++++++++++++++++++++++++++++++++
9 files changed, 678 insertions(+), 370 deletions(-)
create mode 100644 MANIFEST.in
delete mode 100644 Makefile
delete mode 100644 doc/Makefile
delete mode 100644 doc/fragment/date
delete mode 100644 doc/fragment/version
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..d65c874
--- /dev/null
+++ b/MANIFEST.in
@@ -0,0 +1,18 @@
+# docs
+include DEVELOPING
+include LICENSE
+include TEST-NOTES
+
+# docbook sources
+include doc/custom.xsl
+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/doc/fragment/date b/doc/fragment/date
deleted file mode 100644
index e69de29..0000000
diff --git a/doc/fragment/version b/doc/fragment/version
deleted file mode 100644
index f85674c..0000000
--- a/doc/fragment/version
+++ /dev/null
@@ -1 +0,0 @@
-<releaseinfo>VERSION</releaseinfo>
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..e5c3631
--- /dev/null
+++ b/setup.py
@@ -0,0 +1,657 @@
+#!/usr/bin/env python
+# Copyright 1998-2014 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+from distutils.core import setup, Command
+from distutils.command.build import build
+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.dep_util import newer
+from distutils.dir_util import mkpath, remove_tree
+from distutils.util import change_root, subst_vars
+
+import codecs, collections, errno, 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 x_build(build):
+ """ Build command with extra build_man call. """
+
+ def run(self):
+ build.run(self)
+ self.run_command('build_man')
+
+
+class build_man(Command):
+ """ Perform substitutions in manpages. """
+
+ user_options = [
+ ]
+
+ def initialize_options(self):
+ self.build_base = None
+
+ def finalize_options(self):
+ self.set_undefined_options('build',
+ ('build_base', 'build_base'))
+
+ def run(self):
+ for d, files in self.distribution.data_files:
+ if not d.startswith('$mandir/'):
+ continue
+
+ for source in files:
+ target = os.path.join(self.build_base, source)
+ mkpath(os.path.dirname(target))
+
+ if not newer(source, target) and not newer(__file__, target):
+ continue
+
+ print('copying and updating %s -> %s' % (
+ source, target))
+
+ with codecs.open(source, 'r', 'utf8') as f:
+ data = f.readlines()
+ data[0] = data[0].replace('VERSION',
+ self.distribution.get_version())
+ with codecs.open(target, 'w', 'utf8') as f:
+ f.writelines(data)
+
+
+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):
+ if not os.path.isdir('doc/fragment'):
+ mkpath('doc/fragment')
+
+ with open('doc/fragment/date', 'w'):
+ pass
+ with open('doc/fragment/version', 'w') as f:
+ f.write('<releaseinfo>%s</releaseinfo>' % self.distribution.get_version())
+
+ 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('doc/fragment'):
+ remove_tree('doc/fragment')
+
+ 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 clean_man(self):
+ man_dir = os.path.join(self.build_base, 'man')
+ if os.path.exists(man_dir):
+ remove_tree(man_dir)
+
+ def run(self):
+ if self.all:
+ self.clean_tests()
+ self.clean_docs()
+ self.clean_man()
+
+ 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.build_base = None
+ self.paths = None
+
+ def finalize_options(self):
+ install_data.finalize_options(self)
+ self.set_undefined_options('build',
+ ('build_base', 'build_base'))
+ self.set_undefined_options('install',
+ ('subst_paths', 'paths'))
+
+ def run(self):
+ self.run_command('build_man')
+
+ def process_data_files(df):
+ for d, files in df:
+ # substitute man sources
+ if d.startswith('$mandir/'):
+ files = [os.path.join(self.build_base, v) for v in files]
+
+ # substitute variables in path
+ d = subst_vars(d, self.paths)
+ yield (d, files)
+
+ old_data_files = self.data_files
+ self.data_files = process_data_files(self.data_files)
+
+ install_data.run(self)
+ self.data_files = old_data_files
+
+
+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'(?m)^(%s\s*=).*$' % varname
+ repl = r'\1 %s' % repr(val)
+
+ data = re.sub(regexp, repl, data)
+
+ 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-portage@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': x_build,
+ 'build_man': build_man,
+ '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.1.0
next prev parent reply other threads:[~2014-09-05 6:58 UTC|newest]
Thread overview: 23+ messages / expand[flat|nested] mbox.gz Atom feed top
2014-08-21 20:19 [gentoo-portage-dev] [PATCHES] setup.py install for Portage Michał Górny
2014-08-21 20:19 ` [gentoo-portage-dev] [PATCH 1/6] self-update: Copy only relevant packages from PORTAGE_PYM_PATH Michał Górny
2014-08-22 21:47 ` Brian Dolbec
2014-08-21 20:19 ` [gentoo-portage-dev] [PATCH 2/6] portage.const: Make PORTAGE_PYM_PATH point to the real package tree Michał Górny
2014-08-21 20:19 ` [gentoo-portage-dev] [PATCH 3/6] tests: Append .py to files that need to be installed Michał Górny
2014-08-21 20:19 ` [gentoo-portage-dev] [PATCH 4/6] tests: Fix running on installed copy of Portage Michał Górny
2014-08-22 22:19 ` Brian Dolbec
2014-08-22 22:52 ` Michał Górny
2014-08-21 20:19 ` [gentoo-portage-dev] [PATCH 5/6] Install Python modules using setup.py Michał Górny
2014-08-22 22:30 ` Brian Dolbec
2014-08-22 22:55 ` Michał Górny
2014-08-23 20:30 ` [gentoo-portage-dev] [PATCH v2] Install Portage " Michał Górny
2014-08-23 21:56 ` Brian Dolbec
2014-08-29 17:08 ` Brian Dolbec
2014-08-29 23:30 ` Brian Dolbec
2014-09-05 6:58 ` Michał Górny [this message]
2014-08-21 20:19 ` [gentoo-portage-dev] [PATCH 6/6] travis: Use setup.py for running tests Michał Górny
2014-08-21 20:22 ` [gentoo-portage-dev] [PATCHES] setup.py install for Portage Michał Górny
2014-08-21 20:25 ` Michał Górny
2014-08-22 22:32 ` Brian Dolbec
2014-08-24 19:42 ` Brian Dolbec
2014-08-24 21:19 ` Michał Górny
2014-09-12 7:17 ` Michał Górny
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1409900322-1962-1-git-send-email-mgorny@gentoo.org \
--to=mgorny@gentoo.org \
--cc=gentoo-portage-dev@lists.gentoo.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox