PageRenderTime 60ms CodeModel.GetById 17ms RepoModel.GetById 1ms app.codeStats 0ms

/src/zc/buildout/buildout.py

https://github.com/koodaamo/buildout
Python | 1777 lines | 1672 code | 63 blank | 42 comment | 103 complexity | ae5705289d8a648caf304c5e4eede2a3 MD5 | raw file
Possible License(s): GPL-2.0
  1. ##############################################################################
  2. #
  3. # Copyright (c) 2005-2009 Zope Foundation and Contributors.
  4. # All Rights Reserved.
  5. #
  6. # This software is subject to the provisions of the Zope Public License,
  7. # Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
  8. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
  9. # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  10. # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
  11. # FOR A PARTICULAR PURPOSE.
  12. #
  13. ##############################################################################
  14. """Buildout main script
  15. """
  16. from zc.buildout.rmtree import rmtree
  17. import zc.buildout.easy_install
  18. try:
  19. from hashlib import md5
  20. except ImportError:
  21. from md5 import md5
  22. try:
  23. from UserDict import DictMixin
  24. except ImportError:
  25. from collections import MutableMapping as DictMixin
  26. import zc.buildout.configparser
  27. import copy
  28. import distutils.errors
  29. import glob
  30. import itertools
  31. import logging
  32. import os
  33. import pkg_resources
  34. import re
  35. import shutil
  36. import subprocess
  37. import sys
  38. import tempfile
  39. import zc.buildout
  40. import zc.buildout.download
  41. def _print_options(sep=' ', end='\n', file=None):
  42. return sep, end, file
  43. def print_(*args, **kw):
  44. sep, end, file = _print_options(**kw)
  45. if file is None:
  46. file = sys.stdout
  47. file.write(sep.join(map(str, args))+end)
  48. realpath = zc.buildout.easy_install.realpath
  49. pkg_resources_loc = pkg_resources.working_set.find(
  50. pkg_resources.Requirement.parse('distribute')).location
  51. _isurl = re.compile('([a-zA-Z0-9+.-]+)://').match
  52. class MissingOption(zc.buildout.UserError, KeyError):
  53. """A required option was missing.
  54. """
  55. class MissingSection(zc.buildout.UserError, KeyError):
  56. """A required section is missing.
  57. """
  58. def __str__(self):
  59. return "The referenced section, %r, was not defined." % self.args[0]
  60. def _annotate_section(section, note):
  61. for key in section:
  62. section[key] = (section[key], note)
  63. return section
  64. def _annotate(data, note):
  65. for key in data:
  66. data[key] = _annotate_section(data[key], note)
  67. return data
  68. def _print_annotate(data):
  69. sections = list(data.keys())
  70. sections.sort()
  71. print_()
  72. print_("Annotated sections")
  73. print_("="*len("Annotated sections"))
  74. for section in sections:
  75. print_()
  76. print_('[%s]' % section)
  77. keys = list(data[section].keys())
  78. keys.sort()
  79. for key in keys:
  80. value, notes = data[section][key]
  81. keyvalue = "%s= %s" % (key, value)
  82. print_(keyvalue)
  83. line = ' '
  84. for note in notes.split():
  85. if note == '[+]':
  86. line = '+= '
  87. elif note == '[-]':
  88. line = '-= '
  89. else:
  90. print_(line, note)
  91. line = ' '
  92. print_()
  93. def _unannotate_section(section):
  94. for key in section:
  95. value, note = section[key]
  96. section[key] = value
  97. return section
  98. def _unannotate(data):
  99. for key in data:
  100. data[key] = _unannotate_section(data[key])
  101. return data
  102. _buildout_default_options = _annotate_section({
  103. 'allow-hosts': '*',
  104. 'allow-picked-versions': 'true',
  105. 'bin-directory': 'bin',
  106. 'develop-eggs-directory': 'develop-eggs',
  107. 'eggs-directory': 'eggs',
  108. 'executable': sys.executable,
  109. 'find-links': '',
  110. 'install-from-cache': 'false',
  111. 'installed': '.installed.cfg',
  112. 'log-format': '',
  113. 'log-level': 'INFO',
  114. 'newest': 'true',
  115. 'offline': 'false',
  116. 'parts-directory': 'parts',
  117. 'prefer-final': 'true',
  118. 'python': 'buildout',
  119. 'socket-timeout': '',
  120. 'use-dependency-links': 'true',
  121. }, 'DEFAULT_VALUE')
  122. class Buildout(DictMixin):
  123. def __init__(self, config_file, cloptions,
  124. user_defaults=True, windows_restart=False,
  125. command=None, args=()):
  126. __doing__ = 'Initializing.'
  127. self.__windows_restart = windows_restart
  128. # default options
  129. data = dict(buildout=_buildout_default_options.copy())
  130. self._buildout_dir = os.getcwd()
  131. if not _isurl(config_file):
  132. config_file = os.path.abspath(config_file)
  133. base = os.path.dirname(config_file)
  134. if not os.path.exists(config_file):
  135. if command == 'init':
  136. self._init_config(config_file, args)
  137. elif command == 'setup':
  138. # Sigh. This model of a buildout instance
  139. # with methods is breaking down. :(
  140. config_file = None
  141. data['buildout']['directory'] = ('.', 'COMPUTED_VALUE')
  142. else:
  143. raise zc.buildout.UserError(
  144. "Couldn't open %s" % config_file)
  145. elif command == 'init':
  146. raise zc.buildout.UserError(
  147. "%r already exists." % config_file)
  148. if config_file:
  149. data['buildout']['directory'] = (os.path.dirname(config_file),
  150. 'COMPUTED_VALUE')
  151. else:
  152. base = None
  153. cloptions = dict(
  154. (section, dict((option, (value, 'COMMAND_LINE_VALUE'))
  155. for (_, option, value) in v))
  156. for (section, v) in itertools.groupby(sorted(cloptions),
  157. lambda v: v[0])
  158. )
  159. override = cloptions.get('buildout', {}).copy()
  160. # load user defaults, which override defaults
  161. if user_defaults:
  162. user_config = os.path.join(os.path.expanduser('~'),
  163. '.buildout', 'default.cfg')
  164. if os.path.exists(user_config):
  165. _update(data, _open(os.path.dirname(user_config), user_config,
  166. [], data['buildout'].copy(), override,
  167. set()))
  168. # load configuration files
  169. if config_file:
  170. _update(data, _open(os.path.dirname(config_file), config_file, [],
  171. data['buildout'].copy(), override, set()))
  172. # apply command-line options
  173. _update(data, cloptions)
  174. self._annotated = copy.deepcopy(data)
  175. self._raw = _unannotate(data)
  176. self._data = {}
  177. self._parts = []
  178. # provide some defaults before options are parsed
  179. # because while parsing options those attributes might be
  180. # used already (Gottfried Ganssauge)
  181. buildout_section = data['buildout']
  182. # Try to make sure we have absolute paths for standard
  183. # directories. We do this before doing substitutions, in case
  184. # a one of these gets read by another section. If any
  185. # variable references are used though, we leave it as is in
  186. # _buildout_path.
  187. if 'directory' in buildout_section:
  188. self._buildout_dir = buildout_section['directory']
  189. for name in ('bin', 'parts', 'eggs', 'develop-eggs'):
  190. d = self._buildout_path(buildout_section[name+'-directory'])
  191. buildout_section[name+'-directory'] = d
  192. # Attributes on this buildout object shouldn't be used by
  193. # recipes in their __init__. It can cause bugs, because the
  194. # recipes will be instantiated below (``options = self['buildout']``)
  195. # before this has completed initializing. These attributes are
  196. # left behind for legacy support but recipe authors should
  197. # beware of using them. A better practice is for a recipe to
  198. # use the buildout['buildout'] options.
  199. links = buildout_section['find-links']
  200. self._links = links and links.split() or ()
  201. allow_hosts = buildout_section['allow-hosts'].split('\n')
  202. self._allow_hosts = tuple([host.strip() for host in allow_hosts
  203. if host.strip() != ''])
  204. self._logger = logging.getLogger('zc.buildout')
  205. self.offline = (buildout_section['offline'] == 'true')
  206. self.newest = (buildout_section['newest'] == 'true')
  207. ##################################################################
  208. ## WARNING!!!
  209. ## ALL ATTRIBUTES MUST HAVE REASONABLE DEFAULTS AT THIS POINT
  210. ## OTHERWISE ATTRIBUTEERRORS MIGHT HAPPEN ANY TIME FROM RECIPES.
  211. ## RECIPES SHOULD GENERALLY USE buildout['buildout'] OPTIONS, NOT
  212. ## BUILDOUT ATTRIBUTES.
  213. ##################################################################
  214. # initialize some attrs and buildout directories.
  215. options = self['buildout']
  216. # now reinitialize
  217. links = options.get('find-links', '')
  218. self._links = links and links.split() or ()
  219. allow_hosts = options['allow-hosts'].split('\n')
  220. self._allow_hosts = tuple([host.strip() for host in allow_hosts
  221. if host.strip() != ''])
  222. self._buildout_dir = options['directory']
  223. # Make sure we have absolute paths for standard directories. We do this
  224. # a second time here in case someone overrode these in their configs.
  225. for name in ('bin', 'parts', 'eggs', 'develop-eggs'):
  226. d = self._buildout_path(options[name+'-directory'])
  227. options[name+'-directory'] = d
  228. if options['installed']:
  229. options['installed'] = os.path.join(options['directory'],
  230. options['installed'])
  231. self._setup_logging()
  232. self._setup_socket_timeout()
  233. offline = options['offline']
  234. if offline not in ('true', 'false'):
  235. self._error('Invalid value for offline option: %s', offline)
  236. self.offline = (offline == 'true')
  237. if self.offline:
  238. newest = options['newest'] = 'false'
  239. else:
  240. newest = options['newest']
  241. if newest not in ('true', 'false'):
  242. self._error('Invalid value for newest option: %s', newest)
  243. self.newest = (newest == 'true')
  244. versions = {'zc.recipe.egg': '>=2.0.0a3'}
  245. self.versions = versions
  246. versions_section = options.get('versions')
  247. if versions_section:
  248. versions.update(dict(self[versions_section]))
  249. zc.buildout.easy_install.default_versions(versions)
  250. prefer_final = options['prefer-final']
  251. if prefer_final not in ('true', 'false'):
  252. self._error('Invalid value for prefer-final option: %s',
  253. prefer_final)
  254. zc.buildout.easy_install.prefer_final(prefer_final=='true')
  255. use_dependency_links = options['use-dependency-links']
  256. if use_dependency_links not in ('true', 'false'):
  257. self._error('Invalid value for use-dependency-links option: %s',
  258. use_dependency_links)
  259. zc.buildout.easy_install.use_dependency_links(
  260. use_dependency_links == 'true')
  261. allow_picked_versions = options['allow-picked-versions']
  262. if allow_picked_versions not in ('true', 'false'):
  263. self._error('Invalid value for allow-picked-versions option: %s',
  264. allow_picked_versions)
  265. zc.buildout.easy_install.allow_picked_versions(
  266. allow_picked_versions == 'true')
  267. download_cache = options.get('download-cache')
  268. if download_cache:
  269. download_cache = os.path.join(options['directory'], download_cache)
  270. if not os.path.isdir(download_cache):
  271. raise zc.buildout.UserError(
  272. 'The specified download cache:\n'
  273. '%r\n'
  274. "Doesn't exist.\n"
  275. % download_cache)
  276. download_cache = os.path.join(download_cache, 'dist')
  277. if not os.path.isdir(download_cache):
  278. os.mkdir(download_cache)
  279. zc.buildout.easy_install.download_cache(download_cache)
  280. install_from_cache = options['install-from-cache']
  281. if install_from_cache not in ('true', 'false'):
  282. self._error('Invalid value for install-from-cache option: %s',
  283. install_from_cache)
  284. zc.buildout.easy_install.install_from_cache(
  285. install_from_cache=='true')
  286. # "Use" each of the defaults so they aren't reported as unused options.
  287. for name in _buildout_default_options:
  288. options[name]
  289. # Do the same for extends-cache which is not among the defaults but
  290. # wasn't recognized as having been used since it was used before
  291. # tracking was turned on.
  292. options.get('extends-cache')
  293. os.chdir(options['directory'])
  294. def _buildout_path(self, name):
  295. if '${' in name:
  296. return name
  297. return os.path.join(self._buildout_dir, name)
  298. def bootstrap(self, args):
  299. __doing__ = 'Bootstrapping.'
  300. self._setup_directories()
  301. # Now copy buildout and distribute eggs, and record destination eggs:
  302. entries = []
  303. for name in 'distribute', 'zc.buildout':
  304. r = pkg_resources.Requirement.parse(name)
  305. dist = pkg_resources.working_set.find(r)
  306. if dist.precedence == pkg_resources.DEVELOP_DIST:
  307. dest = os.path.join(self['buildout']['develop-eggs-directory'],
  308. name+'.egg-link')
  309. open(dest, 'w').write(dist.location)
  310. entries.append(dist.location)
  311. else:
  312. dest = os.path.join(self['buildout']['eggs-directory'],
  313. os.path.basename(dist.location))
  314. entries.append(dest)
  315. if not os.path.exists(dest):
  316. if os.path.isdir(dist.location):
  317. shutil.copytree(dist.location, dest)
  318. else:
  319. shutil.copy2(dist.location, dest)
  320. # Create buildout script
  321. ws = pkg_resources.WorkingSet(entries)
  322. ws.require('zc.buildout')
  323. zc.buildout.easy_install.scripts(
  324. ['zc.buildout'], ws, sys.executable,
  325. self['buildout']['bin-directory'])
  326. def _init_config(self, config_file, args):
  327. print_('Creating %r.' % config_file)
  328. f = open(config_file, 'w')
  329. sep = re.compile(r'[\\/]')
  330. if args:
  331. eggs = '\n '.join(a for a in args if not sep.search(a))
  332. sepsub = os.path.sep == '/' and '/' or re.escape(os.path.sep)
  333. paths = '\n '.join(
  334. sep.sub(sepsub, a)
  335. for a in args if sep.search(a))
  336. f.write('[buildout]\n'
  337. 'parts = py\n'
  338. '\n'
  339. '[py]\n'
  340. 'recipe = zc.recipe.egg\n'
  341. 'interpreter = py\n'
  342. 'eggs =\n'
  343. )
  344. if eggs:
  345. f.write(' %s\n' % eggs)
  346. if paths:
  347. f.write('extra-paths =\n %s\n' % paths)
  348. for p in [a for a in args if sep.search(a)]:
  349. if not os.path.exists(p):
  350. os.mkdir(p)
  351. else:
  352. f.write('[buildout]\nparts =\n')
  353. f.close()
  354. def init(self, args):
  355. self.bootstrap(())
  356. if args:
  357. self.install(())
  358. def install(self, install_args):
  359. __doing__ = 'Installing.'
  360. self._load_extensions()
  361. self._setup_directories()
  362. # Add develop-eggs directory to path so that it gets searched
  363. # for eggs:
  364. sys.path.insert(0, self['buildout']['develop-eggs-directory'])
  365. # Check for updates. This could cause the process to be rstarted
  366. self._maybe_upgrade()
  367. # load installed data
  368. (installed_part_options, installed_exists
  369. )= self._read_installed_part_options()
  370. # Remove old develop eggs
  371. self._uninstall(
  372. installed_part_options['buildout'].get(
  373. 'installed_develop_eggs', '')
  374. )
  375. # Build develop eggs
  376. installed_develop_eggs = self._develop()
  377. installed_part_options['buildout']['installed_develop_eggs'
  378. ] = installed_develop_eggs
  379. if installed_exists:
  380. self._update_installed(
  381. installed_develop_eggs=installed_develop_eggs)
  382. # get configured and installed part lists
  383. conf_parts = self['buildout']['parts']
  384. conf_parts = conf_parts and conf_parts.split() or []
  385. installed_parts = installed_part_options['buildout']['parts']
  386. installed_parts = installed_parts and installed_parts.split() or []
  387. if install_args:
  388. install_parts = install_args
  389. uninstall_missing = False
  390. else:
  391. install_parts = conf_parts
  392. uninstall_missing = True
  393. # load and initialize recipes
  394. [self[part]['recipe'] for part in install_parts]
  395. if not install_args:
  396. install_parts = self._parts
  397. if self._log_level < logging.DEBUG:
  398. sections = list(self)
  399. sections.sort()
  400. print_()
  401. print_('Configuration data:')
  402. for section in self._data:
  403. _save_options(section, self[section], sys.stdout)
  404. print_()
  405. # compute new part recipe signatures
  406. self._compute_part_signatures(install_parts)
  407. # uninstall parts that are no-longer used or who's configs
  408. # have changed
  409. for part in reversed(installed_parts):
  410. if part in install_parts:
  411. old_options = installed_part_options[part].copy()
  412. installed_files = old_options.pop('__buildout_installed__')
  413. new_options = self.get(part)
  414. if old_options == new_options:
  415. # The options are the same, but are all of the
  416. # installed files still there? If not, we should
  417. # reinstall.
  418. if not installed_files:
  419. continue
  420. for f in installed_files.split('\n'):
  421. if not os.path.exists(self._buildout_path(f)):
  422. break
  423. else:
  424. continue
  425. # output debugging info
  426. if self._logger.getEffectiveLevel() < logging.DEBUG:
  427. for k in old_options:
  428. if k not in new_options:
  429. self._logger.debug("Part %s, dropped option %s.",
  430. part, k)
  431. elif old_options[k] != new_options[k]:
  432. self._logger.debug(
  433. "Part %s, option %s changed:\n%r != %r",
  434. part, k, new_options[k], old_options[k],
  435. )
  436. for k in new_options:
  437. if k not in old_options:
  438. self._logger.debug("Part %s, new option %s.",
  439. part, k)
  440. elif not uninstall_missing:
  441. continue
  442. self._uninstall_part(part, installed_part_options)
  443. installed_parts = [p for p in installed_parts if p != part]
  444. if installed_exists:
  445. self._update_installed(parts=' '.join(installed_parts))
  446. # Check for unused buildout options:
  447. _check_for_unused_options_in_section(self, 'buildout')
  448. # install new parts
  449. for part in install_parts:
  450. signature = self[part].pop('__buildout_signature__')
  451. saved_options = self[part].copy()
  452. recipe = self[part].recipe
  453. if part in installed_parts: # update
  454. need_to_save_installed = False
  455. __doing__ = 'Updating %s.', part
  456. self._logger.info(*__doing__)
  457. old_options = installed_part_options[part]
  458. old_installed_files = old_options['__buildout_installed__']
  459. try:
  460. update = recipe.update
  461. except AttributeError:
  462. update = recipe.install
  463. self._logger.warning(
  464. "The recipe for %s doesn't define an update "
  465. "method. Using its install method.",
  466. part)
  467. try:
  468. installed_files = self[part]._call(update)
  469. except:
  470. installed_parts.remove(part)
  471. self._uninstall(old_installed_files)
  472. if installed_exists:
  473. self._update_installed(
  474. parts=' '.join(installed_parts))
  475. raise
  476. old_installed_files = old_installed_files.split('\n')
  477. if installed_files is None:
  478. installed_files = old_installed_files
  479. else:
  480. if isinstance(installed_files, str):
  481. installed_files = [installed_files]
  482. else:
  483. installed_files = list(installed_files)
  484. need_to_save_installed = [
  485. p for p in installed_files
  486. if p not in old_installed_files]
  487. if need_to_save_installed:
  488. installed_files = (old_installed_files
  489. + need_to_save_installed)
  490. else: # install
  491. need_to_save_installed = True
  492. __doing__ = 'Installing %s.', part
  493. self._logger.info(*__doing__)
  494. installed_files = self[part]._call(recipe.install)
  495. if installed_files is None:
  496. self._logger.warning(
  497. "The %s install returned None. A path or "
  498. "iterable os paths should be returned.",
  499. part)
  500. installed_files = ()
  501. elif isinstance(installed_files, str):
  502. installed_files = [installed_files]
  503. else:
  504. installed_files = list(installed_files)
  505. installed_part_options[part] = saved_options
  506. saved_options['__buildout_installed__'
  507. ] = '\n'.join(installed_files)
  508. saved_options['__buildout_signature__'] = signature
  509. installed_parts = [p for p in installed_parts if p != part]
  510. installed_parts.append(part)
  511. _check_for_unused_options_in_section(self, part)
  512. if need_to_save_installed:
  513. installed_part_options['buildout']['parts'] = (
  514. ' '.join(installed_parts))
  515. self._save_installed_options(installed_part_options)
  516. installed_exists = True
  517. else:
  518. assert installed_exists
  519. self._update_installed(parts=' '.join(installed_parts))
  520. if installed_develop_eggs:
  521. if not installed_exists:
  522. self._save_installed_options(installed_part_options)
  523. elif (not installed_parts) and installed_exists:
  524. os.remove(self['buildout']['installed'])
  525. self._unload_extensions()
  526. def _update_installed(self, **buildout_options):
  527. installed = self['buildout']['installed']
  528. f = open(installed, 'a')
  529. f.write('\n[buildout]\n')
  530. for option, value in list(buildout_options.items()):
  531. _save_option(option, value, f)
  532. f.close()
  533. def _uninstall_part(self, part, installed_part_options):
  534. # ununstall part
  535. __doing__ = 'Uninstalling %s.', part
  536. self._logger.info(*__doing__)
  537. # run uinstall recipe
  538. recipe, entry = _recipe(installed_part_options[part])
  539. try:
  540. uninstaller = _install_and_load(
  541. recipe, 'zc.buildout.uninstall', entry, self)
  542. self._logger.info('Running uninstall recipe.')
  543. uninstaller(part, installed_part_options[part])
  544. except (ImportError, pkg_resources.DistributionNotFound):
  545. pass
  546. # remove created files and directories
  547. self._uninstall(
  548. installed_part_options[part]['__buildout_installed__'])
  549. def _setup_directories(self):
  550. __doing__ = 'Setting up buildout directories'
  551. # Create buildout directories
  552. for name in ('bin', 'parts', 'eggs', 'develop-eggs'):
  553. d = self['buildout'][name+'-directory']
  554. if not os.path.exists(d):
  555. self._logger.info('Creating directory %r.', d)
  556. os.mkdir(d)
  557. def _develop(self):
  558. """Install sources by running setup.py develop on them
  559. """
  560. __doing__ = 'Processing directories listed in the develop option'
  561. develop = self['buildout'].get('develop')
  562. if not develop:
  563. return ''
  564. dest = self['buildout']['develop-eggs-directory']
  565. old_files = os.listdir(dest)
  566. env = dict(os.environ, PYTHONPATH=pkg_resources_loc)
  567. here = os.getcwd()
  568. try:
  569. try:
  570. for setup in develop.split():
  571. setup = self._buildout_path(setup)
  572. files = glob.glob(setup)
  573. if not files:
  574. self._logger.warn("Couldn't develop %r (not found)",
  575. setup)
  576. else:
  577. files.sort()
  578. for setup in files:
  579. self._logger.info("Develop: %r", setup)
  580. __doing__ = 'Processing develop directory %r.', setup
  581. zc.buildout.easy_install.develop(setup, dest)
  582. except:
  583. # if we had an error, we need to roll back changes, by
  584. # removing any files we created.
  585. self._sanity_check_develop_eggs_files(dest, old_files)
  586. self._uninstall('\n'.join(
  587. [os.path.join(dest, f)
  588. for f in os.listdir(dest)
  589. if f not in old_files
  590. ]))
  591. raise
  592. else:
  593. self._sanity_check_develop_eggs_files(dest, old_files)
  594. return '\n'.join([os.path.join(dest, f)
  595. for f in os.listdir(dest)
  596. if f not in old_files
  597. ])
  598. finally:
  599. os.chdir(here)
  600. def _sanity_check_develop_eggs_files(self, dest, old_files):
  601. for f in os.listdir(dest):
  602. if f in old_files:
  603. continue
  604. if not (os.path.isfile(os.path.join(dest, f))
  605. and f.endswith('.egg-link')):
  606. self._logger.warning(
  607. "Unexpected entry, %r, in develop-eggs directory.", f)
  608. def _compute_part_signatures(self, parts):
  609. # Compute recipe signature and add to options
  610. for part in parts:
  611. options = self.get(part)
  612. if options is None:
  613. options = self[part] = {}
  614. recipe, entry = _recipe(options)
  615. req = pkg_resources.Requirement.parse(recipe)
  616. sig = _dists_sig(pkg_resources.working_set.resolve([req]))
  617. options['__buildout_signature__'] = ' '.join(sig)
  618. def _read_installed_part_options(self):
  619. old = self['buildout']['installed']
  620. if old and os.path.isfile(old):
  621. fp = open(old)
  622. sections = zc.buildout.configparser.parse(fp, old)
  623. fp.close()
  624. result = {}
  625. for section, options in sections.items():
  626. for option, value in options.items():
  627. if '%(' in value:
  628. for k, v in _spacey_defaults:
  629. value = value.replace(k, v)
  630. options[option] = value
  631. result[section] = Options(self, section, options)
  632. return result, True
  633. else:
  634. return ({'buildout': Options(self, 'buildout', {'parts': ''})},
  635. False,
  636. )
  637. def _uninstall(self, installed):
  638. for f in installed.split('\n'):
  639. if not f:
  640. continue
  641. f = self._buildout_path(f)
  642. if os.path.isfile(f) or os.path.islink(f):
  643. try:
  644. os.remove(f)
  645. except OSError:
  646. if not (
  647. sys.platform == 'win32' and
  648. (realpath(os.path.join(os.path.dirname(sys.argv[0]),
  649. 'buildout.exe'))
  650. ==
  651. realpath(f)
  652. )
  653. # Sigh. This is the exectable used to run the buildout
  654. # and, of course, it's in use. Leave it.
  655. ):
  656. raise
  657. elif os.path.isdir(f):
  658. rmtree(f)
  659. def _install(self, part):
  660. options = self[part]
  661. recipe, entry = _recipe(options)
  662. recipe_class = pkg_resources.load_entry_point(
  663. recipe, 'zc.buildout', entry)
  664. installed = recipe_class(self, part, options).install()
  665. if installed is None:
  666. installed = []
  667. elif isinstance(installed, str):
  668. installed = [installed]
  669. base = self._buildout_path('')
  670. installed = [d.startswith(base) and d[len(base):] or d
  671. for d in installed]
  672. return ' '.join(installed)
  673. def _save_installed_options(self, installed_options):
  674. installed = self['buildout']['installed']
  675. if not installed:
  676. return
  677. f = open(installed, 'w')
  678. _save_options('buildout', installed_options['buildout'], f)
  679. for part in installed_options['buildout']['parts'].split():
  680. print_(file=f)
  681. _save_options(part, installed_options[part], f)
  682. f.close()
  683. def _error(self, message, *args):
  684. raise zc.buildout.UserError(message % args)
  685. def _setup_socket_timeout(self):
  686. timeout = self['buildout']['socket-timeout']
  687. if timeout != '':
  688. try:
  689. timeout = int(timeout)
  690. import socket
  691. self._logger.info('Setting socket time out to %d seconds.', timeout)
  692. socket.setdefaulttimeout(timeout)
  693. except ValueError:
  694. self._logger.warning("Default socket timeout is used !\n"
  695. "Value in configuration is not numeric: [%s].\n",
  696. timeout)
  697. def _setup_logging(self):
  698. root_logger = logging.getLogger()
  699. self._logger = logging.getLogger('zc.buildout')
  700. handler = logging.StreamHandler(sys.stdout)
  701. log_format = self['buildout']['log-format']
  702. if not log_format:
  703. # No format specified. Use different formatter for buildout
  704. # and other modules, showing logger name except for buildout
  705. log_format = '%(name)s: %(message)s'
  706. buildout_handler = logging.StreamHandler(sys.stdout)
  707. buildout_handler.setFormatter(logging.Formatter('%(message)s'))
  708. self._logger.propagate = False
  709. self._logger.addHandler(buildout_handler)
  710. handler.setFormatter(logging.Formatter(log_format))
  711. root_logger.addHandler(handler)
  712. level = self['buildout']['log-level']
  713. if level in ('DEBUG', 'INFO', 'WARNING', 'ERROR', 'CRITICAL'):
  714. level = getattr(logging, level)
  715. else:
  716. try:
  717. level = int(level)
  718. except ValueError:
  719. self._error("Invalid logging level %s", level)
  720. verbosity = self['buildout'].get('verbosity', 0)
  721. try:
  722. verbosity = int(verbosity)
  723. except ValueError:
  724. self._error("Invalid verbosity %s", verbosity)
  725. level -= verbosity
  726. root_logger.setLevel(level)
  727. self._log_level = level
  728. def _maybe_upgrade(self):
  729. # See if buildout or distribute need to be upgraded.
  730. # If they do, do the upgrade and restart the buildout process.
  731. __doing__ = 'Checking for upgrades.'
  732. if not self.newest:
  733. return
  734. # Prevent downgrading due to prefer-final:
  735. options = self['buildout']
  736. if not ('zc.buildout-version' in options
  737. or
  738. 'zc.buildout' in self.versions):
  739. v = pkg_resources.working_set.find(
  740. pkg_resources.Requirement.parse('zc.buildout')
  741. ).version
  742. options['zc.buildout-version'] = '>=' + v
  743. ws = zc.buildout.easy_install.install(
  744. [
  745. (spec + ' ' + self['buildout'].get(spec+'-version', '')).strip()
  746. for spec in ('zc.buildout', 'distribute')
  747. ],
  748. self['buildout']['eggs-directory'],
  749. links = self['buildout'].get('find-links', '').split(),
  750. index = self['buildout'].get('index'),
  751. path = [self['buildout']['develop-eggs-directory']],
  752. allow_hosts = self._allow_hosts
  753. )
  754. upgraded = []
  755. for project in 'zc.buildout', 'distribute':
  756. req = pkg_resources.Requirement.parse(project)
  757. project_location = pkg_resources.working_set.find(req).location
  758. if ws.find(req).location != project_location:
  759. upgraded.append(ws.find(req))
  760. if not upgraded:
  761. return
  762. __doing__ = 'Upgrading.'
  763. should_run = realpath(
  764. os.path.join(os.path.abspath(self['buildout']['bin-directory']),
  765. 'buildout')
  766. )
  767. if sys.platform == 'win32':
  768. should_run += '-script.py'
  769. if (realpath(os.path.abspath(sys.argv[0])) != should_run):
  770. self._logger.debug("Running %r.", realpath(sys.argv[0]))
  771. self._logger.debug("Local buildout is %r.", should_run)
  772. self._logger.warn("Not upgrading because not running a local "
  773. "buildout command.")
  774. return
  775. if sys.platform == 'win32' and not self.__windows_restart:
  776. args = list(map(zc.buildout.easy_install._safe_arg, sys.argv))
  777. args.insert(1, '-W')
  778. if not __debug__:
  779. args.insert(0, '-O')
  780. args.insert(0, zc.buildout.easy_install._safe_arg (sys.executable))
  781. os.execv(sys.executable, args)
  782. self._logger.info("Upgraded:\n %s;\nrestarting.",
  783. ",\n ".join([("%s version %s"
  784. % (dist.project_name, dist.version)
  785. )
  786. for dist in upgraded
  787. ]
  788. ),
  789. )
  790. # the new dist is different, so we've upgraded.
  791. # Update the scripts and return True
  792. zc.buildout.easy_install.scripts(
  793. ['zc.buildout'], ws, sys.executable,
  794. self['buildout']['bin-directory'],
  795. )
  796. # Restart
  797. args = sys.argv[:]
  798. if not __debug__:
  799. args.insert(0, '-O')
  800. args.insert(0, sys.executable)
  801. sys.exit(subprocess.call(args))
  802. def _load_extensions(self):
  803. __doing__ = 'Loading extensions.'
  804. specs = self['buildout'].get('extensions', '').split()
  805. if specs:
  806. path = [self['buildout']['develop-eggs-directory']]
  807. if self.offline:
  808. dest = None
  809. path.append(self['buildout']['eggs-directory'])
  810. else:
  811. dest = self['buildout']['eggs-directory']
  812. if not os.path.exists(dest):
  813. self._logger.info('Creating directory %r.', dest)
  814. os.mkdir(dest)
  815. zc.buildout.easy_install.install(
  816. specs, dest, path=path,
  817. working_set=pkg_resources.working_set,
  818. links = self['buildout'].get('find-links', '').split(),
  819. index = self['buildout'].get('index'),
  820. newest=self.newest, allow_hosts=self._allow_hosts)
  821. # Clear cache because extensions might now let us read pages we
  822. # couldn't read before.
  823. zc.buildout.easy_install.clear_index_cache()
  824. for ep in pkg_resources.iter_entry_points('zc.buildout.extension'):
  825. ep.load()(self)
  826. def _unload_extensions(self):
  827. __doing__ = 'Unloading extensions.'
  828. specs = self['buildout'].get('extensions', '').split()
  829. if specs:
  830. for ep in pkg_resources.iter_entry_points(
  831. 'zc.buildout.unloadextension'):
  832. ep.load()(self)
  833. def setup(self, args):
  834. if not args:
  835. raise zc.buildout.UserError(
  836. "The setup command requires the path to a setup script or \n"
  837. "directory containing a setup script, and its arguments."
  838. )
  839. setup = args.pop(0)
  840. if os.path.isdir(setup):
  841. setup = os.path.join(setup, 'setup.py')
  842. self._logger.info("Running setup script %r.", setup)
  843. setup = os.path.abspath(setup)
  844. fd, tsetup = tempfile.mkstemp()
  845. try:
  846. os.write(fd, (zc.buildout.easy_install.runsetup_template % dict(
  847. distribute=pkg_resources_loc,
  848. setupdir=os.path.dirname(setup),
  849. setup=setup,
  850. __file__ = setup,
  851. )).encode())
  852. args = [sys.executable, tsetup] + args
  853. zc.buildout.easy_install.call_subprocess(args)
  854. finally:
  855. os.close(fd)
  856. os.remove(tsetup)
  857. runsetup = setup # backward compat.
  858. def annotate(self, args):
  859. _print_annotate(self._annotated)
  860. def __getitem__(self, section):
  861. __doing__ = 'Getting section %s.', section
  862. try:
  863. return self._data[section]
  864. except KeyError:
  865. pass
  866. try:
  867. data = self._raw[section]
  868. except KeyError:
  869. raise MissingSection(section)
  870. options = Options(self, section, data)
  871. self._data[section] = options
  872. options._initialize()
  873. return options
  874. def __setitem__(self, key, value):
  875. raise NotImplementedError('__setitem__')
  876. def __delitem__(self, key):
  877. raise NotImplementedError('__delitem__')
  878. def keys(self):
  879. return list(self._raw.keys())
  880. def __iter__(self):
  881. return iter(self._raw)
  882. def __len__(self):
  883. return len(self._raw)
  884. def _install_and_load(spec, group, entry, buildout):
  885. __doing__ = 'Loading recipe %r.', spec
  886. try:
  887. req = pkg_resources.Requirement.parse(spec)
  888. buildout_options = buildout['buildout']
  889. if pkg_resources.working_set.find(req) is None:
  890. __doing__ = 'Installing recipe %s.', spec
  891. if buildout.offline:
  892. dest = None
  893. path = [buildout_options['develop-eggs-directory'],
  894. buildout_options['eggs-directory'],
  895. ]
  896. else:
  897. dest = buildout_options['eggs-directory']
  898. path = [buildout_options['develop-eggs-directory']]
  899. zc.buildout.easy_install.install(
  900. [spec], dest,
  901. links=buildout._links,
  902. index=buildout_options.get('index'),
  903. path=path,
  904. working_set=pkg_resources.working_set,
  905. newest=buildout.newest,
  906. allow_hosts=buildout._allow_hosts
  907. )
  908. __doing__ = 'Loading %s recipe entry %s:%s.', group, spec, entry
  909. return pkg_resources.load_entry_point(
  910. req.project_name, group, entry)
  911. except Exception:
  912. v = sys.exc_info()[1]
  913. buildout._logger.log(
  914. 1,
  915. "Could't load %s entry point %s\nfrom %s:\n%s.",
  916. group, entry, spec, v)
  917. raise
  918. class Options(DictMixin):
  919. def __init__(self, buildout, section, data):
  920. self.buildout = buildout
  921. self.name = section
  922. self._raw = data
  923. self._cooked = {}
  924. self._data = {}
  925. def _initialize(self):
  926. name = self.name
  927. __doing__ = 'Initializing section %s.', name
  928. if '<' in self._raw:
  929. self._raw = self._do_extend_raw(name, self._raw, [])
  930. # force substitutions
  931. for k, v in sorted(self._raw.items()):
  932. if '${' in v:
  933. self._dosub(k, v)
  934. if self.name == 'buildout':
  935. return # buildout section can never be a part
  936. recipe = self.get('recipe')
  937. if not recipe:
  938. return
  939. reqs, entry = _recipe(self._data)
  940. buildout = self.buildout
  941. recipe_class = _install_and_load(reqs, 'zc.buildout', entry, buildout)
  942. __doing__ = 'Initializing part %s.', name
  943. self.recipe = recipe_class(buildout, name, self)
  944. buildout._parts.append(name)
  945. def _do_extend_raw(self, name, data, doing):
  946. if name == 'buildout':
  947. return data
  948. if name in doing:
  949. raise zc.buildout.UserError("Infinite extending loop %r" % name)
  950. doing.append(name)
  951. try:
  952. to_do = data.get('<', None)
  953. if to_do is None:
  954. return data
  955. __doing__ = 'Loading input sections for %r', name
  956. result = {}
  957. for iname in to_do.split('\n'):
  958. iname = iname.strip()
  959. if not iname:
  960. continue
  961. raw = self.buildout._raw.get(iname)
  962. if raw is None:
  963. raise zc.buildout.UserError("No section named %r" % iname)
  964. result.update(self._do_extend_raw(iname, raw, doing))
  965. result.update(data)
  966. result.pop('<', None)
  967. return result
  968. finally:
  969. assert doing.pop() == name
  970. def _dosub(self, option, v):
  971. __doing__ = 'Getting option %s:%s.', self.name, option
  972. seen = [(self.name, option)]
  973. v = '$$'.join([self._sub(s, seen) for s in v.split('$$')])
  974. self._cooked[option] = v
  975. def get(self, option, default=None, seen=None):
  976. try:
  977. return self._data[option]
  978. except KeyError:
  979. pass
  980. v = self._cooked.get(option)
  981. if v is None:
  982. v = self._raw.get(option)
  983. if v is None:
  984. return default
  985. __doing__ = 'Getting option %s:%s.', self.name, option
  986. if '${' in v:
  987. key = self.name, option
  988. if seen is None:
  989. seen = [key]
  990. elif key in seen:
  991. raise zc.buildout.UserError(
  992. "Circular reference in substitutions.\n"
  993. )
  994. else:
  995. seen.append(key)
  996. v = '$$'.join([self._sub(s, seen) for s in v.split('$$')])
  997. seen.pop()
  998. self._data[option] = v
  999. return v
  1000. _template_split = re.compile('([$]{[^}]*})').split
  1001. _simple = re.compile('[-a-zA-Z0-9 ._]+$').match
  1002. _valid = re.compile('\${[-a-zA-Z0-9 ._]*:[-a-zA-Z0-9 ._]+}$').match
  1003. def _sub(self, template, seen):
  1004. value = self._template_split(template)
  1005. subs = []
  1006. for ref in value[1::2]:
  1007. s = tuple(ref[2:-1].split(':'))
  1008. if not self._valid(ref):
  1009. if len(s) < 2:
  1010. raise zc.buildout.UserError("The substitution, %s,\n"
  1011. "doesn't contain a colon."
  1012. % ref)
  1013. if len(s) > 2:
  1014. raise zc.buildout.UserError("The substitution, %s,\n"
  1015. "has too many colons."
  1016. % ref)
  1017. if not self._simple(s[0]):
  1018. raise zc.buildout.UserError(
  1019. "The section name in substitution, %s,\n"
  1020. "has invalid characters."
  1021. % ref)
  1022. if not self._simple(s[1]):
  1023. raise zc.buildout.UserError(
  1024. "The option name in substitution, %s,\n"
  1025. "has invalid characters."
  1026. % ref)
  1027. section, option = s
  1028. if not section:
  1029. section = self.name
  1030. v = self.buildout[section].get(option, None, seen)
  1031. if v is None:
  1032. if option == '_buildout_section_name_':
  1033. v = self.name
  1034. else:
  1035. raise MissingOption("Referenced option does not exist:",
  1036. section, option)
  1037. subs.append(v)
  1038. subs.append('')
  1039. return ''.join([''.join(v) for v in zip(value[::2], subs)])
  1040. def __getitem__(self, key):
  1041. try:
  1042. return self._data[key]
  1043. except KeyError:
  1044. pass
  1045. v = self.get(key)
  1046. if v is None:
  1047. raise MissingOption("Missing option: %s:%s" % (self.name, key))
  1048. return v
  1049. def __setitem__(self, option, value):
  1050. if not isinstance(value, str):
  1051. raise TypeError('Option values must be strings', value)
  1052. self._data[option] = value
  1053. def __delitem__(self, key):
  1054. if key in self._raw:
  1055. del self._raw[key]
  1056. if key in self._data:
  1057. del self._data[key]
  1058. if key in self._cooked:
  1059. del self._cooked[key]
  1060. elif key in self._data:
  1061. del self._data[key]
  1062. else:
  1063. raise KeyError(key)
  1064. def keys(self):
  1065. raw = self._raw
  1066. return list(self._raw) + [k for k in self._data if k not in raw]
  1067. def __iter__(self):
  1068. return iter(self.keys())
  1069. def __len__(self):
  1070. return len(self.keys())
  1071. def copy(self):
  1072. result = self._raw.copy()
  1073. result.update(self._cooked)
  1074. result.update(self._data)
  1075. return result
  1076. def _call(self, f):
  1077. buildout_directory = self.buildout['buildout']['directory']
  1078. self._created = []
  1079. try:
  1080. try:
  1081. os.chdir(buildout_directory)
  1082. return f()
  1083. except:
  1084. for p in self._created:
  1085. if os.path.isdir(p):
  1086. rmtree(p)
  1087. elif os.path.isfile(p):
  1088. os.remove(p)
  1089. else:
  1090. self.buildout._logger.warn("Couldn't clean up %r.", p)
  1091. raise
  1092. finally:
  1093. self._created = None
  1094. os.chdir(buildout_directory)
  1095. def created(self, *paths):
  1096. try:
  1097. self._created.extend(paths)
  1098. except AttributeError:
  1099. raise TypeError(
  1100. "Attempt to register a created path while not installing",
  1101. self.name)
  1102. return self._created
  1103. _spacey_nl = re.compile('[ \t\r\f\v]*\n[ \t\r\f\v\n]*'
  1104. '|'
  1105. '^[ \t\r\f\v]+'
  1106. '|'
  1107. '[ \t\r\f\v]+$'
  1108. )
  1109. _spacey_defaults = [
  1110. ('%(__buildout_space__)s', ' '),
  1111. ('%(__buildout_space_n__)s', '\n'),
  1112. ('%(__buildout_space_r__)s', '\r'),
  1113. ('%(__buildout_space_f__)s', '\f'),
  1114. ('%(__buildout_space_v__)s', '\v'),
  1115. ]
  1116. def _quote_spacey_nl(match):
  1117. match = match.group(0).split('\n', 1)
  1118. result = '\n\t'.join(
  1119. [(s
  1120. .replace(' ', '%(__buildout_space__)s')
  1121. .replace('\r', '%(__buildout_space_r__)s')
  1122. .replace('\f', '%(__buildout_space_f__)s')
  1123. .replace('\v', '%(__buildout_space_v__)s')
  1124. .replace('\n', '%(__buildout_space_n__)s')
  1125. )
  1126. for s in match]
  1127. )
  1128. return result
  1129. def _save_option(option, value, f):
  1130. value = _spacey_nl.sub(_quote_spacey_nl, value)
  1131. if value.startswith('\n\t'):
  1132. value = '%(__buildout_space_n__)s' + value[2:]
  1133. if value.endswith('\n\t'):
  1134. value = value[:-2] + '%(__buildout_space_n__)s'
  1135. print_(option, '=', value, file=f)
  1136. def _save_options(section, options, f):
  1137. print_('[%s]' % section, file=f)
  1138. items = list(options.items())
  1139. items.sort()
  1140. for option, value in items:
  1141. _save_option(option, value, f)
  1142. def _convert_bool(name, value):
  1143. if value not in ('true', 'false'):
  1144. raise zc.buildout.UserError(
  1145. 'Invalid value for %s option: %s' % (name, value))
  1146. else:
  1147. return value == 'true'
  1148. def _open(base, filename, seen, dl_options, override, downloaded):
  1149. """Open a configuration file and return the result as a dictionary,
  1150. Recursively open other files based on buildout options found.
  1151. """
  1152. _update_section(dl_options, override)
  1153. _dl_options = _unannotate_section(dl_options.copy())
  1154. newest = _convert_bool('newest', _dl_options.get('newest', 'false'))
  1155. fallback = newest and not (filename in downloaded)
  1156. download = zc.buildout.download.Download(
  1157. _dl_options, cache=_dl_options.get('extends-cache'),
  1158. fallback=fallback, hash_name=True)
  1159. is_temp = False
  1160. if _isurl(filename):
  1161. path, is_temp = download(filename)
  1162. fp = open(path)
  1163. base = filename[:filename.rfind('/')]
  1164. elif _isurl(base):
  1165. if os.path.isabs(filename):
  1166. fp = open(filename)
  1167. base = os.path.dirname(filename)
  1168. else:
  1169. filename = base + '/' + filename
  1170. path, is_temp = download(filename)
  1171. fp = open(path)
  1172. base = filename[:filename.rfind('/')]
  1173. else:
  1174. filename = os.path.join(base, filename)
  1175. fp = open(filename)
  1176. base = os.path.dirname(filename)
  1177. downloaded.add(filename)
  1178. if filename in seen:
  1179. if is_temp:
  1180. fp.close()
  1181. os.remove(path)
  1182. raise zc.buildout.UserError("Recursive file include", seen, filename)
  1183. root_config_file = not seen
  1184. seen.append(filename)
  1185. result = zc.buildout.configparser.parse(fp, filename)
  1186. fp.close()
  1187. if is_temp:
  1188. os.remove(path)
  1189. options = result.get('buildout', {})
  1190. extends = options.pop('extends', None)
  1191. if 'extended-by' in options:
  1192. raise zc.buildout.UserError(
  1193. 'No-longer supported "extended-by" option found in %s.' %
  1194. filename)
  1195. result = _annotate(result, filename)
  1196. if root_config_file and 'buildout' in result:
  1197. dl_options = _update_section(dl_options, result['buildout'])
  1198. if extends:
  1199. extends = extends.split()
  1200. eresult = _open(base, extends.pop(0), seen, dl_options, override,
  1201. downloaded)
  1202. for fname in extends:
  1203. _update(eresult, _open(base, fname, seen, dl_options, override,
  1204. downloaded))
  1205. result = _update(eresult, result)
  1206. seen.pop()
  1207. return result
  1208. ignore_directories = '.svn', 'CVS', '__pycache__'
  1209. _dir_hashes = {}
  1210. def _dir_hash(dir):
  1211. dir_hash = _dir_hashes.get(dir, None)
  1212. if dir_hash is not None:
  1213. return dir_hash
  1214. hash = md5()
  1215. for (dirpath, dirnames, filenames) in os.walk(dir):
  1216. dirnames[:] = sorted(n for n in dirnames if n not in ignore_directories)
  1217. filenames[:] = sorted(f for f in filenames
  1218. if (not (f.endswith('pyc') or f.endswith('pyo'))
  1219. and os.path.exists(os.path.join(dirpath, f)))
  1220. )
  1221. hash.update(' '.join(dirnames).encode())
  1222. hash.update(' '.join(filenames).encode())
  1223. for name in filenames:
  1224. path = os.path.join(dirpath, name)
  1225. if name == 'entry_points.txt':
  1226. f = open(path)
  1227. # Entry points aren't written in stable order. :(
  1228. try:
  1229. sections = zc.buildout.configparser.parse(f, path)
  1230. data = repr([(sname, sorted(sections[sname].items()))
  1231. for sname in sorted(sections)]).encode('utf-8')
  1232. except Exception:
  1233. f.close()
  1234. f = open(path, 'rb')
  1235. data = f.read()
  1236. else:
  1237. f = open(path, 'rb')
  1238. data = f.read()
  1239. f.close()
  1240. hash.update(data)
  1241. _dir_hashes[dir] = dir_hash = hash.hexdigest()
  1242. return dir_hash
  1243. def _dists_sig(dists):
  1244. result = []
  1245. for dist in dists:
  1246. location = dist.location
  1247. if dist.precedence == pkg_resources.DEVELOP_DIST:
  1248. result.append(dist.project_name + '-' + _dir_hash(location))
  1249. else:
  1250. result.append(os.path.basename(location))
  1251. return result
  1252. def _update_section(s1, s2):
  1253. s2 = s2.copy() # avoid mutating the second argument, which is unexpected
  1254. for k, v in list(s2.items()):
  1255. v2, note2 = v
  1256. if k.endswith('+'):
  1257. key = k.rstrip(' +')
  1258. v1, note1 = s1.get(key, ("", ""))
  1259. newnote = ' [+] '.join((note1, note2)).strip()
  1260. s2[key] = "\n".join((v1).split('\n') +
  1261. v2.split('\n')), newnote
  1262. del s2[k]
  1263. elif k.endswith('-'):
  1264. key = k.rstrip(' -')
  1265. v1, note1 = s1.get(key, ("", ""))
  1266. newnote = ' [-] '.join((note1, note2)).strip()
  1267. s2[key] = ("\n".join(
  1268. [v for v in v1.split('\n')
  1269. if v not in v2.split('\n')]), newnote)
  1270. del s2[k]
  1271. s1.update(s2)
  1272. return s1
  1273. def _update(d1, d2):
  1274. for section in d2:
  1275. if section in d1:
  1276. d1[section] = _update_section(d1[section], d2[section])
  1277. else:
  1278. d1[section] = d2[section]
  1279. return d1
  1280. def _recipe(options):
  1281. recipe = options['recipe']
  1282. if ':' in recipe:
  1283. recipe, entry = recipe.split(':')
  1284. else:
  1285. entry = 'default'
  1286. return recipe, entry
  1287. def _doing():
  1288. _, v, tb = sys.exc_info()
  1289. message = str(v)
  1290. doing = []
  1291. while tb is not None:
  1292. d = tb.tb_frame.f_locals.get('__doing__')
  1293. if d:
  1294. doing.append(d)
  1295. tb = tb.tb_next
  1296. if doing:
  1297. sys.stderr.write('While:\n')
  1298. for d in doing:
  1299. if not isinstance(d, str):
  1300. d = d[0] % d[1:]
  1301. sys.stderr.write(' %s\n' % d)
  1302. def _error(*message):
  1303. sys.stderr.write('Error: ' + ' '.join(message) +'\n')
  1304. sys.exit(1)
  1305. _internal_error_template = """
  1306. An internal error occured due to a bug in either zc.buildout or in a
  1307. recipe being used:
  1308. """
  1309. def _check_for_unused_options_in_section(buildout, section):
  1310. options = buildout[section]
  1311. unused = [option for option in sorted(options._raw)
  1312. if option not in options._data]
  1313. if unused:
  1314. buildout._logger.warn("Unused options for %s: %s."
  1315. % (section, ' '.join(map(repr, unused)))
  1316. )
  1317. _usage = """\
  1318. Usage: buildout [options] [assignments] [command [command arguments]]
  1319. Options:
  1320. -h, --help
  1321. Print this message and exit.
  1322. -v
  1323. Increase the level of verbosity. This option can be used multiple times.
  1324. -q
  1325. Decrease the level of verbosity. This option can be used multiple times.
  1326. -c config_file
  1327. Specify the path to the buildout configuration file to be used.
  1328. This defaults to the file named "buildout.cfg" in the current
  1329. working directory.
  1330. -t socket_timeout
  1331. Specify the socket timeout in seconds.
  1332. -U
  1333. Don't read user defaults.
  1334. -o
  1335. Run in off-line mode. This is equivalent to the assignment
  1336. buildout:offline=true.
  1337. -O
  1338. Run in non-off-line mode. This is equivalent to the assignment
  1339. buildout:offline=false. This is the default buildout mode. The
  1340. -O option would normally be used to override a true offline
  1341. setting in a configuration file.
  1342. -n
  1343. Run in newest mode. This is equivalent to the assignment
  1344. buildout:newest=true. With this setting, which is the default,
  1345. buildout will try to find the newest versions of distributions
  1346. available that satisfy its requirements.
  1347. -N
  1348. Run in non-newest mode. This is equivalent to the assignment
  1349. buildout:newest=false. With this setting, buildout will not seek
  1350. new distributions if installed distributions satisfy it's
  1351. requirements.
  1352. -D
  1353. Debug errors. If an error occurs, then the post-mortem debugger
  1354. will be started. This is especially useful for debuging recipe
  1355. problems.
  1356. Assignments are of the form: section:option=value and are used to
  1357. provide configuration options that override those given in the
  1358. configuration file. For example, to run the buildout in offline mode,
  1359. use buildout:offline=true.
  1360. Options and assignments can be interspersed.
  1361. Commands:
  1362. install [parts]
  1363. Install parts. If no command arguments are given, then the parts
  1364. definition from the configuration file is used. Otherwise, the
  1365. arguments specify the parts to be installed.
  1366. Note that the semantics differ depending on whether any parts are
  1367. specified. If parts are specified, then only those parts will be
  1368. installed. If no parts are specified, then the parts specified by
  1369. the buildout parts option will be installed along with all of
  1370. their dependencies.
  1371. bootstrap
  1372. Create a new buildout in the current working directory, copying
  1373. the buildout and distribute eggs and, creating a basic directory
  1374. structure and a buildout-local buildout script.
  1375. init
  1376. Initialize a buildout, creating a buildout.cfg file if it doesn't
  1377. exist and then performing the same actions as for the buildout
  1378. command.
  1379. setup script [setup command and options]
  1380. Run a given setup script arranging that distribute is in the
  1381. script's path and and that it has been imported so that
  1382. distribute-provided commands (like bdist_egg) can be used even if
  1383. the setup script doesn't import setuptools.
  1384. The script can be given either as a script path or a path to a
  1385. directory containing a setup.py script.
  1386. annotate
  1387. Display annotated sections. All sections are displayed, sorted
  1388. alphabetically. For each section, all key-value pairs are displayed,
  1389. sorted alphabetically, along with the origin of the value (file name or
  1390. COMPUTED_VALUE, DEFAULT_VALUE, COMMAND_LINE_VALUE).
  1391. """
  1392. def _help():
  1393. print_(_usage)
  1394. sys.exit(0)
  1395. def main(args=None):
  1396. if args is None:
  1397. args = sys.argv[1:]
  1398. config_file = 'buildout.cfg'
  1399. verbosity = 0
  1400. options = []
  1401. windows_restart = False
  1402. user_defaults = True
  1403. debug = False
  1404. while args:
  1405. if args[0][0] == '-':
  1406. op = orig_op = args.pop(0)
  1407. op = op[1:]
  1408. while op and op[0] in 'vqhWUoOnNDA':
  1409. if op[0] == 'v':
  1410. verbosity += 10
  1411. elif op[0] == 'q':
  1412. verbosity -= 10
  1413. elif op[0] == 'W':
  1414. windows_restart = True
  1415. elif op[0] == 'U':
  1416. user_defaults = False
  1417. elif op[0] == 'o':
  1418. options.append(('buildout', 'offline', 'true'))
  1419. elif op[0] == 'O':
  1420. options.append(('buildout', 'offline', 'false'))
  1421. elif op[0] == 'n':
  1422. options.append(('buildout', 'newest', 'true'))
  1423. elif op[0] == 'N':
  1424. options.append(('buildout', 'newest', 'false'))
  1425. elif op[0] == 'D':
  1426. debug = True
  1427. else:
  1428. _help()
  1429. op = op[1:]
  1430. if op[:1] in ('c', 't'):
  1431. op_ = op[:1]
  1432. op = op[1:]
  1433. if op_ == 'c':
  1434. if op:
  1435. config_file = op
  1436. else:
  1437. if args:
  1438. config_file = args.pop(0)
  1439. else:
  1440. _error("No file name specified for option", orig_op)
  1441. elif op_ == 't':
  1442. try:
  1443. timeout_string = args.pop(0)
  1444. timeout = int(timeout_string)
  1445. options.append(
  1446. ('buildout', 'socket-timeout', timeout_string))
  1447. except IndexError:
  1448. _error("No timeout value specified for option", orig_op)
  1449. except ValueError:
  1450. _error("Timeout value must be numeric", orig_op)
  1451. elif op:
  1452. if orig_op == '--help':
  1453. _help()
  1454. _error("Invalid option", '-'+op[0])
  1455. elif '=' in args[0]:
  1456. option, value = args.pop(0).split('=', 1)
  1457. if len(option.split(':')) != 2:
  1458. _error('Invalid option:', option)
  1459. section, option = option.split(':')
  1460. options.append((section.strip(), option.strip(), value.strip()))
  1461. else:
  1462. # We've run out of command-line options and option assignnemnts
  1463. # The rest should be commands, so we'll stop here
  1464. break
  1465. if verbosity:
  1466. options.append(('buildout', 'verbosity', str(verbosity)))
  1467. if args:
  1468. command = args.pop(0)
  1469. if command not in (
  1470. 'install', 'bootstrap', 'runsetup', 'setup', 'init',
  1471. 'annotate',
  1472. ):
  1473. _error('invalid command:', command)
  1474. else:
  1475. command = 'install'
  1476. try:
  1477. try:
  1478. buildout = Buildout(config_file, options,
  1479. user_defaults, windows_restart,
  1480. command, args)
  1481. getattr(buildout, command)(args)
  1482. except SystemExit:
  1483. pass
  1484. except Exception:
  1485. v = sys.exc_info()[1]
  1486. _doing()
  1487. exc_info = sys.exc_info()
  1488. import pdb, traceback
  1489. if debug:
  1490. traceback.print_exception(*exc_info)
  1491. sys.stderr.write('\nStarting pdb:\n')
  1492. pdb.post_mortem(exc_info[2])
  1493. else:
  1494. if isinstance(v, (zc.buildout.UserError,
  1495. distutils.errors.DistutilsError
  1496. )
  1497. ):
  1498. _error(str(v))
  1499. else:
  1500. sys.stderr.write(_internal_error_template)
  1501. traceback.print_exception(*exc_info)
  1502. sys.exit(1)
  1503. finally:
  1504. logging.shutdown()
  1505. if sys.version_info[:2] < (2, 4):
  1506. def reversed(iterable):
  1507. result = list(iterable);
  1508. result.reverse()
  1509. return result