Gentoo Archives: gentoo-portage-dev

From: "Michał Górny" <mgorny@g.o>
To: gentoo-portage-dev@l.g.o
Cc: "Michał Górny" <mgorny@g.o>
Subject: [gentoo-portage-dev] [PATCH 5/6] Install Python modules using setup.py
Date: Thu, 21 Aug 2014 20:20:31
Message-Id: 1408652384-1954-6-git-send-email-mgorny@gentoo.org
In Reply to: [gentoo-portage-dev] [PATCHES] setup.py install for Portage by "Michał Górny"
1 ---
2 .gitignore | 1 +
3 Makefile | 215 --------------------
4 doc/Makefile | 11 -
5 pym/portage/const.py | 4 +-
6 setup.py | 557 +++++++++++++++++++++++++++++++++++++++++++++++++++
7 5 files changed, 560 insertions(+), 228 deletions(-)
8 delete mode 100644 Makefile
9 delete mode 100644 doc/Makefile
10 create mode 100755 setup.py
11
12 diff --git a/.gitignore b/.gitignore
13 index 074bb86..c2dd534 100644
14 --- a/.gitignore
15 +++ b/.gitignore
16 @@ -1,4 +1,5 @@
17 *.py[co]
18 __pycache__/
19 *.class
20 +/build
21 /tags
22 diff --git a/Makefile b/Makefile
23 deleted file mode 100644
24 index 9eb6e66..0000000
25 --- a/Makefile
26 +++ /dev/null
27 @@ -1,215 +0,0 @@
28 -SHELL = /bin/sh
29 -PN ?= portage
30 -PF ?= portage
31 -HOMEPAGE ?= http://www.gentoo.org/proj/en/portage/index.xml
32 -PWD ?= $(shell pwd)
33 -S ?= $(PWD)
34 -WORKDIR ?= $(PWD)
35 -DESTDIR = $(PWD)/image/
36 -srcdir = $(S)
37 -prefix = /usr
38 -sysconfdir = /etc
39 -exec_prefix = $(prefix)
40 -bindir = $(exec_prefix)/bin
41 -sbindir = $(exec_prefix)/sbin
42 -libdir = $(exec_prefix)/lib
43 -datarootdir = $(prefix)/share
44 -datadir = $(datarootdir)
45 -mandir = $(datarootdir)/man
46 -docdir = $(datarootdir)/doc/$(PF)
47 -htmldir = $(docdir)/html
48 -portage_datadir = $(datarootdir)/$(PN)
49 -portage_confdir = $(portage_datadir)/config
50 -portage_setsdir = $(portage_confdir)/sets
51 -portage_base = $(libdir)/$(PN)
52 -EPYDOC_OPTS = -qqqqq --no-frames --show-imports
53 -INSMODE = 0644
54 -EXEMODE = 0755
55 -DIRMODE = 0755
56 -SYSCONFDIR_FILES = etc-update.conf dispatch-conf.conf
57 -PORTAGE_CONFDIR_FILES = make.conf.example make.globals repos.conf
58 -LOGROTATE_FILES = elog-save-summary
59 -BINDIR_FILES = ebuild egencache emerge emerge-webrsync \
60 - emirrordist portageq quickpkg repoman
61 -SBINDIR_FILES = archive-conf dispatch-conf emaint \
62 - env-update etc-update fixpackages regenworld
63 -DOCS = ChangeLog NEWS RELEASE-NOTES
64 -LINGUAS ?= $(shell cd "$(srcdir)/man" && find -mindepth 1 -type d)
65 -
66 -ifdef PYTHONPATH
67 - PYTHONPATH := $(srcdir)/pym:$(PYTHONPATH)
68 -else
69 - PYTHONPATH := $(srcdir)/pym
70 -endif
71 -
72 -all: docbook epydoc
73 -
74 -docbook:
75 - set -e; \
76 - touch "$(srcdir)/doc/fragment/date"; \
77 - $(MAKE) -C "$(srcdir)/doc" xhtml xhtml-nochunks
78 -
79 -epydoc:
80 - set -e; \
81 - env PYTHONPATH="$(PYTHONPATH)" epydoc \
82 - -o "$(WORKDIR)/epydoc" \
83 - --name $(PN) \
84 - --url "$(HOMEPAGE)" \
85 - $(EPYDOC_OPTS) \
86 - $$(cd "$(srcdir)" && find pym -name '*.py' | sed \
87 - -e s:/__init__.py$$:: \
88 - -e s:\.py$$:: \
89 - -e s:^pym/:: \
90 - -e s:/:.:g \
91 - | sort); \
92 - rm -f "$(WORKDIR)/epydoc/api-objects.txt"; \
93 -
94 -test:
95 - set -e; \
96 - "$(srcdir)/pym/portage/tests/runTests.py"; \
97 -
98 -install:
99 - set -e; \
100 - cd "$(srcdir)/cnf"; \
101 - install -d -m$(DIRMODE) "$(DESTDIR)$(sysconfdir)"; \
102 - install -m$(INSMODE) $(SYSCONFDIR_FILES) "$(DESTDIR)$(sysconfdir)"; \
103 - \
104 - install -d -m$(DIRMODE) "$(DESTDIR)$(portage_confdir)"; \
105 - cd "$(srcdir)/cnf"; \
106 - install -m$(INSMODE) $(PORTAGE_CONFDIR_FILES) \
107 - "$(DESTDIR)$(portage_confdir)"; \
108 - install -d -m$(DIRMODE) "$(DESTDIR)$(portage_setsdir)"; \
109 - cd "$(S)/cnf/sets"; \
110 - install -m$(INSMODE) *.conf "$(DESTDIR)$(portage_setsdir)"; \
111 - \
112 - install -d -m$(DIRMODE) "$(DESTDIR)$(sysconfdir)/logrotate.d"; \
113 - cd "$(srcdir)/cnf/logrotate.d"; \
114 - install -m$(INSMODE) $(LOGROTATE_FILES) \
115 - "$(DESTDIR)$(sysconfdir)/logrotate.d"; \
116 - \
117 - for x in $$(cd "$(srcdir)" && find bin -type d) ; do \
118 - cd "$(srcdir)/$$x"; \
119 - install -d -m$(DIRMODE) "$(DESTDIR)$(portage_base)/$$x"; \
120 - files=$$(find . -mindepth 1 -maxdepth 1 -type f ! -type l); \
121 - if [ -n "$$files" ] ; then \
122 - install -m$(EXEMODE) $$files \
123 - "$(DESTDIR)$(portage_base)/$$x"; \
124 - fi; \
125 - symlinks=$$(find . -mindepth 1 -maxdepth 1 -type l); \
126 - if [ -n "$$symlinks" ] ; then \
127 - cp -P $$symlinks "$(DESTDIR)$(portage_base)/$$x"; \
128 - fi; \
129 - done; \
130 - \
131 - for x in $$(cd "$(srcdir)" && find pym/* -type d \
132 - ! -path "pym/portage/tests*") ; do \
133 - cd "$(srcdir)/$$x"; \
134 - files=$$(echo *.py); \
135 - if [ -z "$$files" ] || [ "$$files" = "*.py" ]; then \
136 - # __pycache__ directories contain no py files \
137 - continue; \
138 - fi; \
139 - install -d -m$(DIRMODE) "$(DESTDIR)$(portage_base)/$$x"; \
140 - install -m$(INSMODE) $$files "$(DESTDIR)$(portage_base)/$$x"; \
141 - done; \
142 - \
143 - install -d -m$(DIRMODE) "$(DESTDIR)$(bindir)"; \
144 - relative_path=".."; \
145 - x=$(bindir) ; \
146 - y="$(portage_base)"; \
147 - if [ "$${x#$(prefix)}" != "$$x" ] && \
148 - [ "$${y#$(prefix)}" != "$$y" ]; then \
149 - x=$${x#$(prefix)}; \
150 - y=$${y#$(prefix)}; \
151 - fi; \
152 - x=$${x%/*}; \
153 - while [ -n "$$x" ] ; do \
154 - relative_path=$${relative_path}/..; \
155 - x=$${x%/*}; \
156 - done; \
157 - relative_path=$$relative_path$$y; \
158 - for x in $(BINDIR_FILES) ; do \
159 - ln -sf "$$relative_path/bin/$$x" \
160 - "$(DESTDIR)$(bindir)/$$x"; \
161 - done; \
162 - \
163 - install -d -m$(DIRMODE) "$(DESTDIR)$(sbindir)"; \
164 - relative_path=".."; \
165 - x=$(sbindir) ; \
166 - y="$(portage_base)"; \
167 - if [ "$${x#$(prefix)}" != "$$x" ] && \
168 - [ "$${y#$(prefix)}" != "$$y" ]; then \
169 - x=$${x#$(prefix)}; \
170 - y=$${y#$(prefix)}; \
171 - fi; \
172 - x=$${x%/*}; \
173 - while [ -n "$$x" ] ; do \
174 - relative_path=$${relative_path}/..; \
175 - x=$${x%/*}; \
176 - done; \
177 - relative_path=$$relative_path$$y; \
178 - for x in $(SBINDIR_FILES) ; do \
179 - ln -sf "$$relative_path/bin/$$x" \
180 - "$(DESTDIR)$(sbindir)/$$x"; \
181 - done; \
182 - \
183 - ln -sf "$$relative_path/bin/env-update" \
184 - "$(DESTDIR)$(sbindir)/update-env"; \
185 - ln -sf "$$relative_path/bin/etc-update" \
186 - "$(DESTDIR)$(sbindir)/update-etc"; \
187 - \
188 - # We install some minimal tests for use as a preinst sanity check. \
189 - # These tests must be able to run without a full source tree and \
190 - # without relying on a previous portage instance being installed. \
191 - install -d -m$(DIRMODE) \
192 - "$(DESTDIR)$(portage_base)/pym/portage/tests"; \
193 - install -m$(EXEMODE) "$(srcdir)/pym/portage/tests/runTests" \
194 - "$(DESTDIR)$(portage_base)/pym/portage/tests"; \
195 - cd "$(srcdir)/pym/portage/tests"; \
196 - install -m$(INSMODE) *.py \
197 - "$(DESTDIR)$(portage_base)/pym/portage/tests"; \
198 - install -d -m$(DIRMODE) \
199 - "$(DESTDIR)$(portage_base)/pym/portage/tests/lint"; \
200 - cd "$(srcdir)/pym/portage/tests/lint"; \
201 - install -m$(INSMODE) *.py __test__ \
202 - "$(DESTDIR)$(portage_base)/pym/portage/tests/lint"; \
203 - \
204 - install -d -m$(DIRMODE) "$(DESTDIR)$(docdir)"; \
205 - cd "$(srcdir)"; \
206 - install -m $(INSMODE) $(DOCS) "$(DESTDIR)$(docdir)"; \
207 - \
208 - for x in "" $(LINGUAS); do \
209 - for y in 1 5 ; do \
210 - if [ -d "$(srcdir)/man/$$x" ]; then \
211 - cd "$(srcdir)/man/$$x"; \
212 - files=$$(echo *.$$y); \
213 - if [ -z "$$files" ] || [ "$$files" = "*.$$y" ]; then \
214 - continue; \
215 - fi; \
216 - install -d -m$(DIRMODE) "$(DESTDIR)$(mandir)/$$x/man$$y"; \
217 - install -m$(INSMODE) *.$$y "$(DESTDIR)$(mandir)/$$x/man$$y"; \
218 - fi; \
219 - done; \
220 - done; \
221 - \
222 - if [ -f "$(srcdir)/doc/portage.html" ] ; then \
223 - install -d -m$(DIRMODE) "$(DESTDIR)$(htmldir)"; \
224 - cd "$(srcdir)/doc"; \
225 - install -m$(INSMODE) *.html "$(DESTDIR)$(htmldir)"; \
226 - fi; \
227 - \
228 - if [ -d "$(WORKDIR)/epydoc" ] ; then \
229 - install -d -m$(DIRMODE) "$(DESTDIR)$(htmldir)"; \
230 - cp -pPR "$(WORKDIR)/epydoc" \
231 - "$(DESTDIR)$(htmldir)/api"; \
232 - cd "$(DESTDIR)$(htmldir)/api"; \
233 - find . -type d | xargs chmod $(DIRMODE); \
234 - find . -type f | xargs chmod $(INSMODE); \
235 - fi; \
236 -
237 -clean:
238 - set -e; \
239 - $(MAKE) -C "$(srcdir)/doc" clean; \
240 - rm -rf "$(WORKDIR)/epydoc"; \
241 -
242 -.PHONY: all clean docbook epydoc install test
243 diff --git a/doc/Makefile b/doc/Makefile
244 deleted file mode 100644
245 index 261a0b4..0000000
246 --- a/doc/Makefile
247 +++ /dev/null
248 @@ -1,11 +0,0 @@
249 -all: xhtml xhtml-nochunks
250 -
251 -XMLTO_FLAGS = -m custom.xsl
252 -man pdf txt xhtml xhtml-nochunks:
253 - xmlto $@ $(XMLTO_FLAGS) portage.docbook
254 -
255 -clean distclean:
256 - rm -f *.1 *.html portage.txt
257 -
258 -.PHONY: all clean distclean \
259 - man pdf txt xhtml xhtml-nochunks
260 diff --git a/pym/portage/const.py b/pym/portage/const.py
261 index f518b47..acb90f9 100644
262 --- a/pym/portage/const.py
263 +++ b/pym/portage/const.py
264 @@ -60,8 +60,8 @@ GLOBAL_CONFIG_PATH = "/usr/share/portage/config"
265 # these variables are not used with target_root or config_root
266 # NOTE: Use realpath(__file__) so that python module symlinks in site-packages
267 # are followed back to the real location of the whole portage installation.
268 -PORTAGE_BASE_PATH = os.path.join(os.sep, os.sep.join(os.path.realpath(
269 - __file__.rstrip("co")).split(os.sep)[:-3]))
270 +# NOTE: Please keep PORTAGE_BASE_PATH in one line to help substitutions.
271 +PORTAGE_BASE_PATH = os.path.join(os.sep, os.sep.join(os.path.realpath(__file__.rstrip("co")).split(os.sep)[:-3]))
272 PORTAGE_BIN_PATH = PORTAGE_BASE_PATH + "/bin"
273 PORTAGE_PYM_PATH = os.path.realpath(os.path.join(__file__, '../..'))
274 LOCALE_DATA_PATH = PORTAGE_BASE_PATH + "/locale" # FIXME: not used
275 diff --git a/setup.py b/setup.py
276 new file mode 100755
277 index 0000000..bd6e506
278 --- /dev/null
279 +++ b/setup.py
280 @@ -0,0 +1,557 @@
281 +#!/usr/bin/env python
282 +# vim:fileencoding=utf-8
283 +# (c) 2010 Michał Górny <mgorny@g.o>
284 +# Released under the terms of the 2-clause BSD license.
285 +
286 +from distutils.core import setup, Command
287 +from distutils.command.build_scripts import build_scripts
288 +from distutils.command.clean import clean
289 +from distutils.command.install import install
290 +from distutils.command.install_data import install_data
291 +from distutils.command.install_lib import install_lib
292 +from distutils.command.install_scripts import install_scripts
293 +from distutils.dir_util import remove_tree
294 +from distutils.util import change_root, subst_vars
295 +
296 +import codecs, collections, glob, os, os.path, re, subprocess, sys
297 +
298 +# TODO:
299 +# - smarter rebuilds of docs w/ 'install_docbook' and 'install_epydoc'.
300 +
301 +package_name = 'portage'
302 +package_version = '2.2.12'
303 +package_homepage = 'https://wiki.gentoo.org/wiki/Project:Portage'
304 +
305 +x_scripts = {
306 + 'bin': [
307 + 'bin/ebuild', 'bin/egencache', 'bin/emerge', 'bin/emerge-webrsync',
308 + 'bin/emirrordist', 'bin/portageq', 'bin/quickpkg', 'bin/repoman'
309 + ],
310 + 'sbin': [
311 + 'bin/archive-conf', 'bin/dispatch-conf', 'bin/emaint', 'bin/env-update',
312 + 'bin/etc-update', 'bin/fixpackages', 'bin/regenworld'
313 + ],
314 +}
315 +
316 +
317 +class docbook(Command):
318 + """ Build docs using docbook. """
319 +
320 + user_options = [
321 + ('doc-formats=', None, 'Documentation formats to build (all xmlto formats for docbook are allowed, comma-separated'),
322 + ]
323 +
324 + def initialize_options(self):
325 + self.doc_formats = 'xhtml,xhtml-nochunks'
326 +
327 + def finalize_options(self):
328 + self.doc_formats = self.doc_formats.replace(',', ' ').split()
329 +
330 + def run(self):
331 + with open('doc/fragment/date', 'w'):
332 + pass
333 +
334 + for f in self.doc_formats:
335 + print('Building docs in %s format...' % f)
336 + subprocess.check_call(['xmlto', '-o', 'doc',
337 + '-m', 'doc/custom.xsl', f, 'doc/portage.docbook'])
338 +
339 +
340 +class epydoc(Command):
341 + """ Build API docs using epydoc. """
342 +
343 + user_options = [
344 + ]
345 +
346 + def initialize_options(self):
347 + self.build_lib = None
348 +
349 + def finalize_options(self):
350 + self.set_undefined_options('build_py', ('build_lib', 'build_lib'))
351 +
352 + def run(self):
353 + self.run_command('build_py')
354 +
355 + print('Building API documentation...')
356 +
357 + process_env = os.environ.copy()
358 + pythonpath = self.build_lib
359 + try:
360 + pythonpath += ':' + process_env['PYTHONPATH']
361 + except KeyError:
362 + pass
363 + process_env['PYTHONPATH'] = pythonpath
364 +
365 + subprocess.check_call(['epydoc', '-o', 'epydoc',
366 + '--name', package_name,
367 + '--url', package_homepage,
368 + '-qq', '--no-frames', '--show-imports',
369 + '--exclude', 'portage.tests',
370 + '_emerge', 'portage', 'repoman'],
371 + env = process_env)
372 + os.remove('epydoc/api-objects.txt')
373 +
374 +
375 +class install_docbook(install_data):
376 + """ install_data for docbook docs """
377 +
378 + user_options = install_data.user_options
379 +
380 + def initialize_options(self):
381 + install_data.initialize_options(self)
382 + self.htmldir = None
383 +
384 + def finalize_options(self):
385 + self.set_undefined_options('install', ('htmldir', 'htmldir'))
386 + install_data.finalize_options(self)
387 +
388 + def run(self):
389 + if not os.path.exists('doc/portage.html'):
390 + self.run_command('docbook')
391 + self.data_files = [
392 + (self.htmldir, glob.glob('doc/*.html')),
393 + ]
394 + install_data.run(self)
395 +
396 +
397 +class install_epydoc(install_data):
398 + """ install_data for epydoc docs """
399 +
400 + user_options = install_data.user_options
401 +
402 + def initialize_options(self):
403 + install_data.initialize_options(self)
404 + self.htmldir = None
405 +
406 + def finalize_options(self):
407 + self.set_undefined_options('install', ('htmldir', 'htmldir'))
408 + install_data.finalize_options(self)
409 +
410 + def run(self):
411 + if not os.path.exists('epydoc/index.html'):
412 + self.run_command('epydoc')
413 + self.data_files = [
414 + (os.path.join(self.htmldir, 'api'), glob.glob('epydoc/*')),
415 + ]
416 + install_data.run(self)
417 +
418 +
419 +class x_build_scripts_custom(build_scripts):
420 + def finalize_options(self):
421 + build_scripts.finalize_options(self)
422 + if 'dir_name' in dir(self):
423 + self.build_dir = os.path.join(self.build_dir, self.dir_name)
424 + if self.dir_name in x_scripts:
425 + self.scripts = x_scripts[self.dir_name]
426 + else:
427 + self.scripts = set(self.scripts)
428 + for other_files in x_scripts.values():
429 + self.scripts.difference_update(other_files)
430 +
431 + def run(self):
432 + # group scripts by subdirectory
433 + split_scripts = collections.defaultdict(list)
434 + for f in self.scripts:
435 + dir_name = os.path.dirname(f[len('bin/'):])
436 + split_scripts[dir_name].append(f)
437 +
438 + base_dir = self.build_dir
439 + base_scripts = self.scripts
440 + for d, files in split_scripts.items():
441 + self.build_dir = os.path.join(base_dir, d)
442 + self.scripts = files
443 + self.copy_scripts()
444 +
445 + # restore previous values
446 + self.build_dir = base_dir
447 + self.scripts = base_scripts
448 +
449 +
450 +class x_build_scripts_bin(x_build_scripts_custom):
451 + dir_name = 'bin'
452 +
453 +
454 +class x_build_scripts_sbin(x_build_scripts_custom):
455 + dir_name = 'sbin'
456 +
457 +
458 +class x_build_scripts_portagebin(x_build_scripts_custom):
459 + dir_name = 'portage'
460 +
461 +
462 +class x_build_scripts(build_scripts):
463 + def initialize_option(self):
464 + pass
465 +
466 + def finalize_options(self):
467 + pass
468 +
469 + def run(self):
470 + self.run_command('build_scripts_bin')
471 + self.run_command('build_scripts_portagebin')
472 + self.run_command('build_scripts_sbin')
473 +
474 +
475 +class x_clean(clean):
476 + """ clean extended for doc & post-test cleaning """
477 +
478 + def clean_docs(self):
479 + def get_doc_outfiles():
480 + for dirpath, dirnames, filenames in os.walk('doc'):
481 + for f in filenames:
482 + if f.endswith('.docbook') or f == 'custom.xsl':
483 + pass
484 + else:
485 + yield os.path.join(dirpath, f)
486 +
487 + # do not recurse
488 + break
489 +
490 +
491 + for f in get_doc_outfiles():
492 + print('removing %s' % repr(f))
493 + os.remove(f)
494 +
495 + if os.path.isdir('epydoc'):
496 + remove_tree('epydoc')
497 +
498 + def clean_tests(self):
499 + # do not remove incorrect dirs accidentally
500 + top_dir = os.path.normpath(os.path.join(self.build_lib, '..'))
501 + cprefix = os.path.commonprefix((self.build_base, top_dir))
502 + if cprefix != self.build_base:
503 + return
504 +
505 + bin_dir = os.path.join(top_dir, 'bin')
506 + if os.path.exists(bin_dir):
507 + remove_tree(bin_dir)
508 +
509 + conf_dir = os.path.join(top_dir, 'cnf')
510 + if os.path.islink(conf_dir):
511 + print('removing %s symlink' % repr(conf_dir))
512 + os.unlink(conf_dir)
513 +
514 + pni_file = os.path.join(top_dir, '.portage_not_installed')
515 + if os.path.exists(pni_file):
516 + print('removing %s' % repr(pni_file))
517 + os.unlink(pni_file)
518 +
519 + def run(self):
520 + if self.all:
521 + self.clean_tests()
522 + self.clean_docs()
523 +
524 + clean.run(self)
525 +
526 +
527 +class x_install(install):
528 + """ install command with extra Portage paths """
529 +
530 + user_options = install.user_options + [
531 + # note: $prefix and $exec_prefix are reserved for Python install
532 + ('system-prefix=', None, "Prefix for architecture-independent data"),
533 + ('system-exec-prefix=', None, "Prefix for architecture-specific data"),
534 +
535 + ('bindir=', None, "Install directory for main executables"),
536 + ('datarootdir=', None, "Data install root directory"),
537 + ('docdir=', None, "Documentation install directory"),
538 + ('htmldir=', None, "HTML documentation install directory"),
539 + ('mandir=', None, "Manpage root install directory"),
540 + ('portage-base=', 'b', "Portage install base"),
541 + ('portage-bindir=', None, "Install directory for Portage internal-use executables"),
542 + ('portage-datadir=', None, 'Install directory for data files'),
543 + ('sbindir=', None, "Install directory for superuser-intended executables"),
544 + ('sysconfdir=', None, 'System configuration path'),
545 + ]
546 +
547 + # note: the order is important for proper substitution
548 + paths = [
549 + ('system_prefix', '/usr'),
550 + ('system_exec_prefix', '$system_prefix'),
551 +
552 + ('bindir', '$system_exec_prefix/bin'),
553 + ('sbindir', '$system_exec_prefix/sbin'),
554 + ('sysconfdir', '/etc'),
555 +
556 + ('datarootdir', '$system_prefix/share'),
557 + ('docdir', '$datarootdir/doc/%s-%s' % (package_name, package_version)),
558 + ('htmldir', '$docdir/html'),
559 + ('mandir', '$datarootdir/man'),
560 +
561 + ('portage_base', '$system_exec_prefix/lib/portage'),
562 + ('portage_bindir', '$portage_base/bin'),
563 + ('portage_datadir', '$datarootdir/portage'),
564 +
565 + # not customized at the moment
566 + ('logrotatedir', '$sysconfdir/logrotate'),
567 + ('portage_confdir', '$portage_datadir/config'),
568 + ('portage_setsdir', '$portage_confdir/sets'),
569 + ]
570 +
571 + def initialize_options(self):
572 + install.initialize_options(self)
573 +
574 + for key, default in self.paths:
575 + setattr(self, key, default)
576 + self.subst_paths = {}
577 +
578 + def finalize_options(self):
579 + install.finalize_options(self)
580 +
581 + # substitute variables
582 + new_paths = {}
583 + for key, default in self.paths:
584 + new_paths[key] = subst_vars(getattr(self, key), new_paths)
585 + setattr(self, key, new_paths[key])
586 + self.subst_paths = new_paths
587 +
588 +
589 +class x_install_data(install_data):
590 + """ install_data with customized path support """
591 +
592 + user_options = install_data.user_options
593 +
594 + def initialize_options(self):
595 + install_data.initialize_options(self)
596 + self.paths = None
597 +
598 + def finalize_options(self):
599 + install_data.finalize_options(self)
600 + self.set_undefined_options('install',
601 + ('subst_paths', 'paths'))
602 +
603 + # substitute variables in data_files
604 + for f in self.data_files:
605 + f[0] = subst_vars(f[0], self.paths)
606 +
607 +
608 +class x_install_lib(install_lib):
609 + """ install_lib command with Portage path substitution """
610 +
611 + user_options = install_lib.user_options
612 +
613 + def initialize_options(self):
614 + install_lib.initialize_options(self)
615 + self.portage_base = None
616 + self.portage_bindir = None
617 + self.portage_confdir = None
618 +
619 + def finalize_options(self):
620 + install_lib.finalize_options(self)
621 + self.set_undefined_options('install',
622 + ('portage_base', 'portage_base'),
623 + ('portage_bindir', 'portage_bindir'),
624 + ('portage_confdir', 'portage_confdir'))
625 +
626 + def install(self):
627 + ret = install_lib.install(self)
628 +
629 + base_re = re.compile(r'(^PORTAGE_BASE_PATH.*=) .*$', re.MULTILINE)
630 + portage_bin_re = re.compile(r'(^PORTAGE_BIN_PATH.*=) .*$', re.MULTILINE)
631 + global_config_re = re.compile(r'(^GLOBAL_CONFIG_PATH.*=) .*$', re.MULTILINE)
632 +
633 + constfile = os.path.join(self.install_dir, 'portage', 'const.py')
634 + print('Rewriting %s' % constfile)
635 + with codecs.open(constfile, 'r', 'utf-8') as f:
636 + data = f.read()
637 + data = base_re.sub('\\1 %s' % repr(self.portage_base), data)
638 + data = portage_bin_re.sub('\\1 %s' % repr(self.portage_bindir), data)
639 + data = global_config_re.sub('\\1 %s' % repr(self.portage_confdir), data)
640 + with codecs.open(constfile, 'w', 'utf-8') as f:
641 + f.write(data)
642 +
643 + return ret
644 +
645 +
646 +class x_install_scripts_custom(install_scripts):
647 + def initialize_options(self):
648 + install_scripts.initialize_options(self)
649 + self.root = None
650 +
651 + def finalize_options(self):
652 + self.set_undefined_options('install',
653 + ('root', 'root'),
654 + (self.var_name, 'install_dir'))
655 + install_scripts.finalize_options(self)
656 + self.build_dir = os.path.join(self.build_dir, self.dir_name)
657 +
658 + # prepend root
659 + if self.root is not None:
660 + self.install_dir = change_root(self.root, self.install_dir)
661 +
662 +
663 +class x_install_scripts_bin(x_install_scripts_custom):
664 + dir_name = 'bin'
665 + var_name = 'bindir'
666 +
667 +
668 +class x_install_scripts_sbin(x_install_scripts_custom):
669 + dir_name = 'sbin'
670 + var_name = 'sbindir'
671 +
672 +
673 +class x_install_scripts_portagebin(x_install_scripts_custom):
674 + dir_name = 'portage'
675 + var_name = 'portage_bindir'
676 +
677 +
678 +class x_install_scripts(install_scripts):
679 + def initialize_option(self):
680 + pass
681 +
682 + def finalize_options(self):
683 + pass
684 +
685 + def run(self):
686 + self.run_command('install_scripts_bin')
687 + self.run_command('install_scripts_portagebin')
688 + self.run_command('install_scripts_sbin')
689 +
690 +
691 +class build_tests(x_build_scripts_custom):
692 + """ Prepare build dir for running tests. """
693 +
694 + def initialize_options(self):
695 + x_build_scripts_custom.initialize_options(self)
696 + self.build_base = None
697 + self.build_lib = None
698 +
699 + def finalize_options(self):
700 + x_build_scripts_custom.finalize_options(self)
701 + self.set_undefined_options('build',
702 + ('build_base', 'build_base'),
703 + ('build_lib', 'build_lib'))
704 +
705 + # since we will be writing to $build_lib/.., it is important
706 + # that we do not leave $build_base
707 + self.top_dir = os.path.normpath(os.path.join(self.build_lib, '..'))
708 + cprefix = os.path.commonprefix((self.build_base, self.top_dir))
709 + if cprefix != self.build_base:
710 + raise SystemError('build_lib must be a subdirectory of build_base')
711 +
712 + self.build_dir = os.path.join(self.top_dir, 'bin')
713 +
714 + def run(self):
715 + self.run_command('build_py')
716 +
717 + # install all scripts $build_lib/../bin
718 + # (we can't do a symlink since we want shebangs corrected)
719 + x_build_scripts_custom.run(self)
720 +
721 + # symlink 'cnf' directory
722 + conf_dir = os.path.join(self.top_dir, 'cnf')
723 + if os.path.exists(conf_dir):
724 + if not os.path.islink(conf_dir):
725 + raise SystemError('%s exists and is not a symlink (collision)'
726 + % repr(conf_dir))
727 + os.unlink(conf_dir)
728 + conf_src = os.path.relpath('cnf', self.top_dir)
729 + print('Symlinking %s -> %s' % (conf_dir, conf_src))
730 + os.symlink(conf_src, conf_dir)
731 +
732 + # create $build_lib/../.portage_not_installed
733 + # to enable proper paths in tests
734 + with open(os.path.join(self.top_dir, '.portage_not_installed'), 'w') as f:
735 + pass
736 +
737 +
738 +class test(Command):
739 + """ run tests """
740 +
741 + user_options = []
742 +
743 + def initialize_options(self):
744 + self.build_lib = None
745 +
746 + def finalize_options(self):
747 + self.set_undefined_options('build',
748 + ('build_lib', 'build_lib'))
749 +
750 + def run(self):
751 + self.run_command('build_tests')
752 + subprocess.check_call([
753 + sys.executable, '-bWd',
754 + os.path.join(self.build_lib, 'portage/tests/runTests.py')
755 + ])
756 +
757 +
758 +def find_packages():
759 + for dirpath, dirnames, filenames in os.walk('pym'):
760 + if '__init__.py' in filenames:
761 + yield os.path.relpath(dirpath, 'pym')
762 +
763 +
764 +def find_scripts():
765 + for dirpath, dirnames, filenames in os.walk('bin'):
766 + for f in filenames:
767 + yield os.path.join(dirpath, f)
768 +
769 +
770 +def get_manpages():
771 + linguas = os.environ.get('LINGUAS')
772 + if linguas is not None:
773 + linguas = linguas.split()
774 +
775 + for dirpath, dirnames, filenames in os.walk('man'):
776 + groups = collections.defaultdict(list)
777 + for f in filenames:
778 + fn, suffix = f.rsplit('.', 1)
779 + groups[suffix].append(os.path.join(dirpath, f))
780 +
781 + topdir = dirpath[len('man/'):]
782 + if not topdir or linguas is None or topdir in linguas:
783 + for g, mans in groups.items():
784 + yield [os.path.join('$mandir', topdir, 'man%s' % g), mans]
785 +
786 +setup(
787 + name = package_name,
788 + version = package_version,
789 + author = 'Gentoo Portage Development Team',
790 + author_email = 'dev-portage@g.o',
791 + url = package_homepage,
792 +
793 + package_dir = {'': 'pym'},
794 + packages = list(find_packages()),
795 + # something to cheat build & install commands
796 + scripts = list(find_scripts()),
797 +
798 + data_files = list(get_manpages()) + [
799 + ['$sysconfdir', ['cnf/etc-update.conf', 'cnf/dispatch-conf.conf']],
800 + ['$logrotatedir', ['cnf/logrotate.d/elog-save-summary']],
801 + ['$portage_confdir', [
802 + 'cnf/make.conf.example', 'cnf/make.globals', 'cnf/repos.conf']],
803 + ['$portage_setsdir', ['cnf/sets/portage.conf']],
804 + ['$docdir', ['ChangeLog', 'NEWS', 'RELEASE-NOTES']],
805 + ],
806 +
807 + cmdclass = {
808 + 'build_scripts': x_build_scripts,
809 + 'build_scripts_bin': x_build_scripts_bin,
810 + 'build_scripts_portagebin': x_build_scripts_portagebin,
811 + 'build_scripts_sbin': x_build_scripts_sbin,
812 + 'build_tests': build_tests,
813 + 'clean': x_clean,
814 + 'docbook': docbook,
815 + 'epydoc': epydoc,
816 + 'install': x_install,
817 + 'install_data': x_install_data,
818 + 'install_docbook': install_docbook,
819 + 'install_epydoc': install_epydoc,
820 + 'install_lib': x_install_lib,
821 + 'install_scripts': x_install_scripts,
822 + 'install_scripts_bin': x_install_scripts_bin,
823 + 'install_scripts_portagebin': x_install_scripts_portagebin,
824 + 'install_scripts_sbin': x_install_scripts_sbin,
825 + 'test': test,
826 + },
827 +
828 + classifiers = [
829 + 'Development Status :: 5 - Production/Stable',
830 + 'Environment :: Console',
831 + 'Intended Audience :: System Administrators',
832 + 'License :: OSI Approved :: GNU General Public License v2 (GPLv2)',
833 + 'Operating System :: POSIX',
834 + 'Programming Language :: Python',
835 + 'Topic :: System :: Installation/Setup'
836 + ]
837 +)
838 --
839 2.0.4

Replies