Merge lp://staging/~gary/zc.buildout/support-system-python into lp://staging/~gary/zc.buildout/oldtrunk
- support-system-python
- Merge into oldtrunk
Status: | Needs review |
---|---|
Proposed branch: | lp://staging/~gary/zc.buildout/support-system-python |
Merge into: | lp://staging/~gary/zc.buildout/oldtrunk |
Diff against target: | None lines |
To merge this branch: | bzr merge lp://staging/~gary/zc.buildout/support-system-python |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Francis J. Lacoste (community) | Approve | ||
Jim Fulton | Pending | ||
Review via email:
|
Commit message
Description of the change
- 495. By Gary Poster
-
merge fro svn branch: corrects bootstrap for Windows, hopefully.
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Gary Poster (gary) wrote : | # |
I effectively reverted a change I had made to bootstrap.py that tried to get rid of the is_jython code. I had thought we could rely on subprocess generally, if it exists, but I'm told (by Sidnei, thanks to him) that my version of bootstrap failed on Windows, but changing it back to use spawnle worked. Therefore, I've changed the branch back to use spawnle unless is_jython. I still suspect that this could be done more elegantly, but solving that is not a goal I want for this branch.
The following is the incremental diff for this change.
Thanks.
Gary
=== modified file 'bootstrap/
--- bootstrap/
+++ bootstrap/
@@ -139,16 +139,17 @@
os.environ,
PYTHONPATH
-try:
+is_jython = sys.platform.
+if is_jython:
import subprocess
-except ImportError:
+ exitcode = subprocess.
+else: # Windows needs this, apparently; otherwise we would prefer subprocess
exitcode = os.spawnle(
-else:
- # Jython can use subprocess but not spawn. We prefer it generally.
- exitcode = subprocess.
if exitcode != 0:
- # we shouldn't need an error message because a failure
- # should have generated a visible traceback in the subprocess.
+ sys.flush()
+ print ("An error occured when trying to install zc.buildout. "
+ "Look above this message for any errors that "
+ "were output by easy_install.")
sys.
ws.add_
=== modified file 'src/zc/
--- src/zc/
+++ src/zc/
@@ -419,8 +419,8 @@
if exit_code:
- "An error occured when trying to install %s."
- "Look above this message for any errors that"
+ "An error occured when trying to install %s. "
+ "Look above this message for any errors that "
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Francis J. Lacoste (flacoste) wrote : | # |
On July 11, 2009, Gary Poster wrote:
> Gary Poster has proposed merging lp:~gary/zc.buildout/support-system-python
> into lp:~gary/zc.buildout/trunk.
>
> Requested reviews:
> Francis J. Lacoste (flacoste)
>
> I have made a number of changes to zc.buildout in the
> gary-support-
> support Launchpad or Landscape's use of Buildout with a system Python,
> directly or indirectly.
>
Wow, this was a lot of changes!
From my cursory understanding, these changes looks good. I have a bunch of
questions / suggestions. So from the Launchpad point of view, it seems to
satisfy our use case.
Thanks a lot, this will make zc.buildout a lot more robust for our use-case.
> +# We have to manually parse our options rather than using one of the stdlib
> +# tools because we want to pass the ones we don't recognize along to
> +# zc.buildout.
Wouldn't it have been possible to use a '--' marker to delimit the bootstrap
options from the buildout ones:
./bootstrap.py --eggs eggs -- ZC.buildout options follows.
That's a common idiom I think.
> +match_equals = re.compile(
By using this regex, you preclude any paths with spaces in them. I know many
people avoid them because a lot of UNIX programs break on them, but I'm sure
you'll encounter a lot of Mac OS X users that have spaces in some of their
paths :-)
> +# defaults
> +tmpeggs = None
The above comment doesn't make sense to me.
> +if (configuration[
> + not configuration[
> + # download base needs a trailing slash to make the world happy
> + configuration[
> +
I know this is something specific to our coding conventions, but comments are
sentences needing a capital and a period ;-)
> +if configuration[
> + configuration[
I don't understand the reason for that code? I'm guessing it's because you are
going to pass it over to setuptools? Maybe add a comment?
> === modified file 'src/zc/
> - prefer_final = options.
> + prefer_final = options.
Is there any reason for the switch to setdefault? If it's because you are
reusing options in other places, then I guess that's fine. Otherwise, I know
some people find using setdefault() with it's return value a little confusing
to read.
> + options = self['buildout']
> +
> + # Get a base working set for our distributions that corresponds to
the
> + # stated desires in the configuration.
> + distributions = ['setuptools', 'zc.buildout']
You have trailing white space on that previous line.
> === modified file 'src/zc/
I like the merging of the sections into the general option list. It might make
them harder to find from the table of contents though.
> === modified file 'src/zc/
> +
> +def _get_system_
> + """return a pair of the standard lib and site packages for the
executable.
...
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Gary Poster (gary) wrote : | # |
On Jul 13, 2009, at 5:06 PM, Francis J. Lacoste wrote:
> On July 11, 2009, Gary Poster wrote:
>> Gary Poster has proposed merging lp:~gary/zc.buildout/support-
>> system-python
>> into lp:~gary/zc.buildout/trunk.
>>
>> Requested reviews:
>> Francis J. Lacoste (flacoste)
>>
>> I have made a number of changes to zc.buildout in the
>> gary-support-
>> They all
>> support Launchpad or Landscape's use of Buildout with a system
>> Python,
>> directly or indirectly.
>>
>
> Wow, this was a lot of changes!
Yeah, sorry.
>> From my cursory understanding, these changes looks good. I have a
>> bunch of
> questions / suggestions. So from the Launchpad point of view, it
> seems to
> satisfy our use case.
>
> Thanks a lot, this will make zc.buildout a lot more robust for our
> use-case.
>
>> +# We have to manually parse our options rather than using one of
>> the stdlib
>> +# tools because we want to pass the ones we don't recognize along to
>> +# zc.buildout.
>
> Wouldn't it have been possible to use a '--' marker to delimit the
> bootstrap
> options from the buildout ones:
>
> ./bootstrap.py --eggs eggs -- ZC.buildout options follows.
>
> That's a common idiom I think.
It is, but it would break backwards compatibility of the usage of this
script. This was a design decision from before I came a long. If Jim
were OK with breaking backwards compatibility I'd be happy to go this
way.
>> +match_equals = re.compile(
>> ('|'.join(
>
> By using this regex, you preclude any paths with spaces in them. I
> know many
> people avoid them because a lot of UNIX programs break on them, but
> I'm sure
> you'll encounter a lot of Mac OS X users that have spaces in some of
> their
> paths :-)
Yes, that was silly, thanks. (.*) should be sufficient. See
incremental diff.
>
>> +# defaults
>> +tmpeggs = None
>
> The above comment doesn't make sense to me.
Agreed. It was a bit of a legacy comment--at one point in development
I had set a lot of default values there. Now there is only one. I
removed "default" and added a more pertinent comment. See incremental
diff.
>
>> +if (configuration[
>> + not configuration[
>> + # download base needs a trailing slash to make the world happy
>> + configuration[
>> +
>
> I know this is something specific to our coding conventions, but
> comments are
> sentences needing a capital and a period ;-)
Ack, see diff.
>
>> +if configuration[
>> + configuration[
>
> I don't understand the reason for that code? I'm guessing it's
> because you are
> going to pass it over to setuptools? Maybe add a comment?
This is legacy code to some degree, but yes. I changed this approach
entirely to try to clarify, and added a comment.
> === modified file 'src/zc/
>> - prefer_final = options.
>> + prefer_final = options.
>
> Is there any reason for th...
- 496. By Gary Poster
-
changes from flacosate review, merged from svn
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Francis J. Lacoste (flacoste) wrote : | # |
On July 13, 2009, Gary Poster wrote:
> On Jul 13, 2009, at 5:06 PM, Francis J. Lacoste wrote:
> > On July 11, 2009, Gary Poster wrote:
> >> Gary Poster has proposed merging lp:~gary/zc.buildout/support-
> >> system-python
> >> into lp:~gary/zc.buildout/trunk.
> >>
> >> Requested reviews:
> >> Francis J. Lacoste (flacoste)
> >>
> >> I have made a number of changes to zc.buildout in the
> >> gary-support-
> >> They all
> >> support Launchpad or Landscape's use of Buildout with a system
> >> Python,
> >> directly or indirectly.
> >
> > Wow, this was a lot of changes!
>
> Yeah, sorry.
>
> >> From my cursory understanding, these changes looks good. I have a
> >> bunch of
> >
> > questions / suggestions. So from the Launchpad point of view, it
> > seems to
> > satisfy our use case.
> >
> > Thanks a lot, this will make zc.buildout a lot more robust for our
> > use-case.
> >
> >> +# We have to manually parse our options rather than using one of
> >> the stdlib
> >> +# tools because we want to pass the ones we don't recognize along to
> >> +# zc.buildout.
> >
> > Wouldn't it have been possible to use a '--' marker to delimit the
> > bootstrap
> > options from the buildout ones:
> >
> > ./bootstrap.py --eggs eggs -- ZC.buildout options follows.
> >
> > That's a common idiom I think.
>
> It is, but it would break backwards compatibility of the usage of this
> script. This was a design decision from before I came a long. If Jim
> were OK with breaking backwards compatibility I'd be happy to go this
> way.
>
I see, it's fine like it is then.
> > === modified file 'src/zc/
> >
> >> - prefer_final = options.
> >> + prefer_final = options.
> >
> > Is there any reason for the switch to setdefault? If it's because
> > you are
> > reusing options in other places, then I guess that's fine.
> > Otherwise, I know
> > some people find using setdefault() with it's return value a little
> > confusing
> > to read.
>
> It is because when buildout uses -vv, it is supposed to show you all
> configuration values, as shown in buildout.txt in the "Predefined
> buildout options" section. To appear in this output, they need to be
> in the options dict. Therefore, when appropriate, I switched
> from .get to .setdefault so that the options would get the default.
> It seemed like a reasonable, concise, and idiomatic way of
> accomplishing this. Otherwise, we'd need something like this.
>
> prefer_final = options.
> options[
>
> I prefer the setdefault approach, but I'm happy to change.
No, setdefault is fine then.
> >
> >> + # one minus the set of the ones in ``python -S`` is the set of
> >> packages
> >> + # that are effectively site-packages.
> >> + def get_sys_
> >> + cmd = [executable, "-c",
> >> + "import sys, os;"
> >> + "print repr([os.
> >> sys.path])"]
> >> + if clean:
> >> + cmd.insert(1, '-S')
> >> + _proc = subprocess.Popen(
> >...
- 497. By Gary Poster
-
merge from svn
- 498. By Gary Poster
-
merge from svn branch
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Gary Poster (gary) wrote : | # |
So, I have a, um, 1500+ line additional diff. This further breaks our review policies, which might mean we should think further about how to do these upstream-project reviews in the future. But meanwhile...
https:/
It was developed to prepare some previous bugfixes for upstream review by adding tests, and to address and give diagnostic tools for bug 407408 ( https:/
This diff does the following:
- Add new option and tests: ``allowed-
to specify a glob-aware whitelist of project names that may come from
site-packages. This defaults to '*', meaning there is no filtering.
- Add feature and test to let you see what eggs have been selected from
site-packages: "Egg from site-packages: ..." in the output of
``bin/buildout -v``.
- Add new option and tests: ``include-
you to control if site-packages are used for the bin/buildout script.
This defaults to "false," which is a change in behavior! (Rationale is in
docs.)
- Standardize on one of the several competing approaches for default options
in the [buildout] section. This removes my previous use of setdefault,
discussed with flacoste.
- Make generated script paths prettier by eliminating duplicate paths.
- Add comment about recipes using buildout options, not buildout attributes.
Practice what I preach in zc.recipe.egg.
- Standardize on one approach for handling bool options in zc.recipe.egg. Not
sure I like it but it is preexisting, and now it is consistent, and it
behaves well in terms of letting buildout be configured before it looks too
hard at it.
- Normalize tests.py function docstrings to begin at col 0
- Correct some typos
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Francis J. Lacoste (flacoste) wrote : | # |
On August 5, 2009, Gary Poster wrote:
> So, I have a, um, 1500+ line additional diff. This further breaks our
> review policies, which might mean we should think further about how to do
> these upstream-project reviews in the future. But meanwhile...
>
> https:/
Hi Gary,
Thanks for fixing this. Hopefully, this is the last changes we need to support
our use case properly. A good way to split a branch like this is to start by
doing all the clean-ups you want to do first (option changes, reformmating,
etc) and then do your actual changes. Keep that in mind for another time.
I don't have much comments, so feel free to land this.
> === modified file 'CHANGES.txt'
> --- CHANGES.txt 2009-07-11 17:15:31 +0000
> +++ CHANGES.txt 2009-08-04 23:57:12 +0000
> @@ -13,13 +13,28 @@
>
> * A new boolean option, 'include-
site
> packages from finding requirements, and from generated scripts.
> - zc.buildout's own buildout.cfg dogfoods this option.
> + zc.buildout's own buildout.cfg dogfoods this option. This defaults
> + to 'true', which is very similar to buildout's previous behavior.
> +
> + * A new boolean option, 'include-
> + same thing but only for the bin/buildout script. This can be important
> + for getting recipes and their dependencies without conflicts. This
> + defaults to 'false', which is different from buildout's previous
behavior.
> +
> + * Another new option, 'allowed-
> + a whitelist of project names of eggs that are allowed to come from
> + your Python's site-packages. This lets you more tightly control your
use
> + of site-packages.
>
You should explain how this option interacts with include-
include-
include-
I see that you explained this in the documentation, although you didn't
explain how it interacted with the buildout variant.
> === modified file 'src/zc/
> +def allowed_
> + """
> +As introduced in the previous test, the allowed-
option
> +allows you to specify a whitelist of project names that may be included
from
> +site-packages.
> +
> +This test shows the option being used in a buildout.
> +
> +The buildout defaults to a whitelist of ('*',), or any project name.
> +
Is it really necessary here to duplicate all the options you already tested
directly using the API?
--
Francis J. Lacoste
<email address hidden>
Unmerged revisions
- 498. By Gary Poster
-
merge from svn branch
- 497. By Gary Poster
-
merge from svn
- 496. By Gary Poster
-
changes from flacosate review, merged from svn
- 495. By Gary Poster
-
merge fro svn branch: corrects bootstrap for Windows, hopefully.
- 494. By Gary Poster
-
merge from trunk
- 493. By gary
-
make bootstrap produce prettier bin/buildout that honors more of the configuration settings.
- 492. By gary
-
Make buildout's cfg (for zc.buildout developers) set include_
site_packages = false. When I did that, I discovered that the testselectingpy
thon.py test was pretty
fragile. I made it less so, though my fix makes the test setup conditionally
rely on the same code that the test itself is supposed to demonstrate... :-/ - 491. By gary
-
Make the interpreter script a bit more like a Python interpreter.
In this case, now I can use it with setup.py files that refer to their
__file__.Also try to put in some diagnostics for when getting the site packages doesn't
work. This is hopefully only a convenience for developers of zc.buildout
itself. - 490. By gary
-
try to explain how the two kinds of bootstrap options work a bit better
- 489. By gary
-
switch to version numbers I can actually use elsewhere
Preview Diff
1 | === modified file 'CHANGES.txt' |
2 | --- CHANGES.txt 2009-06-22 16:41:40 +0000 |
3 | +++ CHANGES.txt 2009-07-11 17:15:31 +0000 |
4 | @@ -1,6 +1,53 @@ |
5 | Change History |
6 | ************** |
7 | |
8 | +1.4.0 (unreleased) |
9 | +================== |
10 | + |
11 | +- Support and bugfixes for using a system Python with buildout. |
12 | + |
13 | + In all of these descriptions, "site-packages" is an imprecise term for a |
14 | + precise definition: the packages that are added by the Python's site.py. |
15 | + Practically, this is the difference of the set of paths normally used by |
16 | + Python minus those used when Python is started with the -S flag. |
17 | + |
18 | + * A new boolean option, 'include-site-packages', includes or excludes site |
19 | + packages from finding requirements, and from generated scripts. |
20 | + zc.buildout's own buildout.cfg dogfoods this option. |
21 | + |
22 | + * Script generation pushes dependency paths that are in site-packages to |
23 | + the end of the dependency paths in sys.path (but, as before, these are |
24 | + still before extra paths, the standard library, and the rest of the |
25 | + site-package paths). |
26 | + |
27 | + * Fix an error when at least two dependencies were in a shared location like |
28 | + site-packages, and the first one met the "versions" setting. The first |
29 | + dependency would be added, but subsequent dependencies from the same |
30 | + location (e.g., site-packages) would use the version of the package found |
31 | + in the shared location, ignoring the version setting. |
32 | + |
33 | +- The generated interpreter scripts now have a few more similarities to a |
34 | + real Python interpreter. |
35 | + |
36 | + * __file__ is set correctly for executed files. |
37 | + |
38 | + * -c incorporates all subsequent arguments as part of the command. |
39 | + |
40 | + * -V returns the version. |
41 | + |
42 | + * -S causes the script to not modify the standard path (for tests) |
43 | + |
44 | +- Improve bootstrap. |
45 | + |
46 | + * New options let you specify where to find ez_setup.py and where to find |
47 | + a download cache. These options can keep bootstrap from going over the |
48 | + network. |
49 | + |
50 | + * Another new option lets you specify where to put generated eggs. |
51 | + |
52 | + * The buildout script generated by bootstrap honors more of the settings |
53 | + in the designated configuration file (e.g., buildout.cfg). |
54 | + |
55 | 1.3.0 (2009-06-22) |
56 | ================== |
57 | |
58 | |
59 | === modified file 'bootstrap/bootstrap.py' |
60 | --- bootstrap/bootstrap.py 2009-06-22 13:05:44 +0000 |
61 | +++ bootstrap/bootstrap.py 2009-07-09 23:55:19 +0000 |
62 | @@ -20,19 +20,97 @@ |
63 | $Id$ |
64 | """ |
65 | |
66 | -import os, shutil, sys, tempfile, urllib2 |
67 | - |
68 | -tmpeggs = tempfile.mkdtemp() |
69 | - |
70 | -is_jython = sys.platform.startswith('java') |
71 | +import os, re, shutil, sys, tempfile, textwrap, urllib, urllib2 |
72 | + |
73 | +# We have to manually parse our options rather than using one of the stdlib |
74 | +# tools because we want to pass the ones we don't recognize along to |
75 | +# zc.buildout.buildout.main. |
76 | + |
77 | +configuration = { |
78 | + '--ez_setup-source': 'http://peak.telecommunity.com/dist/ez_setup.py', |
79 | + '--version': '', |
80 | + '--download-base': None, |
81 | + '--eggs': None} |
82 | + |
83 | +helpstring = __doc__ + textwrap.dedent(''' |
84 | + This script recognizes the following options itself. The first option it |
85 | + encounters that is not one of these will cause the script to stop parsing |
86 | + options and pass the rest on to buildout. Therefore, if you want to use |
87 | + any of the following options *and* buildout command-line options like |
88 | + -c, first use the following options, and then use the buildout options. |
89 | + |
90 | + Options: |
91 | + --version=ZC_BUILDOUT_VERSION |
92 | + Specify a version number of the zc.buildout to use |
93 | + --ez_setup-source=URL_OR_FILE |
94 | + Specify a URL or file location for the ez_setup file. |
95 | + Defaults to |
96 | + %(--ez_setup-source)s |
97 | + --download-base=URL_OR_DIRECTORY |
98 | + Specify a URL or directory for downloading setuptools and |
99 | + zc.buildout. Defaults to PyPI. |
100 | + --eggs=DIRECTORY |
101 | + Specify a directory for storing eggs. Defaults to a temporary |
102 | + directory that is deleted when the bootstrap script completes. |
103 | + |
104 | + By using --ez_setup-source and --download-base to point to local resources, |
105 | + you can keep this script from going over the network. |
106 | + ''' % configuration) |
107 | +match_equals = re.compile(r'(%s)=(\S*)' % ('|'.join(configuration),)).match |
108 | +args = sys.argv[1:] |
109 | +if args == ['--help']: |
110 | + print helpstring |
111 | + sys.exit(0) |
112 | + |
113 | +# defaults |
114 | +tmpeggs = None |
115 | + |
116 | +while args: |
117 | + val = args[0] |
118 | + if val in configuration: |
119 | + del args[0] |
120 | + if not args or args[0].startswith('-'): |
121 | + print "ERROR: %s requires an argument." |
122 | + print helpstring |
123 | + sys.exit(1) |
124 | + configuration[val] = args[0] |
125 | + else: |
126 | + match = match_equals(val) |
127 | + if match and match.group(1) in configuration: |
128 | + configuration[match.group(1)] = match.group(2) |
129 | + else: |
130 | + break |
131 | + del args[0] |
132 | + |
133 | +for name in ('--ez_setup-source', '--download-base'): |
134 | + val = configuration[name] |
135 | + if val is not None and '://' not in val: # we're being lazy. |
136 | + configuration[name] = 'file://%s' % ( |
137 | + urllib.pathname2url(os.path.abspath(os.path.expanduser(val))),) |
138 | + |
139 | +if (configuration['--download-base'] and |
140 | + not configuration['--download-base'].endswith('/')): |
141 | + # download base needs a trailing slash to make the world happy |
142 | + configuration['--download-base'] += '/' |
143 | + |
144 | +if not configuration['--eggs']: |
145 | + configuration['--eggs'] = tmpeggs = tempfile.mkdtemp() |
146 | +else: |
147 | + configuration['--eggs'] = os.path.abspath( |
148 | + os.path.expanduser(configuration['--eggs'])) |
149 | + |
150 | +if configuration['--version']: |
151 | + configuration['--version'] = '==' + configuration['--version'] |
152 | |
153 | try: |
154 | import pkg_resources |
155 | except ImportError: |
156 | ez = {} |
157 | - exec urllib2.urlopen('http://peak.telecommunity.com/dist/ez_setup.py' |
158 | - ).read() in ez |
159 | - ez['use_setuptools'](to_dir=tmpeggs, download_delay=0) |
160 | + exec urllib2.urlopen(configuration['--ez_setup-source']).read() in ez |
161 | + setuptools_args = dict(to_dir=configuration['--eggs'], download_delay=0) |
162 | + if configuration['--download-base']: |
163 | + setuptools_args['download_base'] = configuration['--download-base'] |
164 | + ez['use_setuptools'](**setuptools_args) |
165 | |
166 | import pkg_resources |
167 | |
168 | @@ -45,40 +123,38 @@ |
169 | else: |
170 | def quote (c): |
171 | return c |
172 | - |
173 | -cmd = 'from setuptools.command.easy_install import main; main()' |
174 | -ws = pkg_resources.working_set |
175 | - |
176 | -if len(sys.argv) > 2 and sys.argv[1] == '--version': |
177 | - VERSION = '==%s' % sys.argv[2] |
178 | - args = sys.argv[3:] + ['bootstrap'] |
179 | -else: |
180 | - VERSION = '' |
181 | - args = sys.argv[1:] + ['bootstrap'] |
182 | - |
183 | -if is_jython: |
184 | +cmd = [quote(sys.executable), |
185 | + '-c', |
186 | + quote('from setuptools.command.easy_install import main; main()'), |
187 | + '-mqNxd', |
188 | + quote(configuration['--eggs'])] |
189 | + |
190 | +if configuration['--download-base']: |
191 | + cmd.extend(['-f', quote(configuration['--download-base'])]) |
192 | + |
193 | +cmd.append('zc.buildout' + configuration['--version']) |
194 | + |
195 | +ws = pkg_resources.working_set |
196 | +env = dict( |
197 | + os.environ, |
198 | + PYTHONPATH=ws.find(pkg_resources.Requirement.parse('setuptools')).location) |
199 | + |
200 | +try: |
201 | import subprocess |
202 | - |
203 | - assert subprocess.Popen([sys.executable] + ['-c', quote(cmd), '-mqNxd', |
204 | - quote(tmpeggs), 'zc.buildout' + VERSION], |
205 | - env=dict(os.environ, |
206 | - PYTHONPATH= |
207 | - ws.find(pkg_resources.Requirement.parse('setuptools')).location |
208 | - ), |
209 | - ).wait() == 0 |
210 | - |
211 | +except ImportError: |
212 | + exitcode = os.spawnle(*([os.P_WAIT, sys.executable] + cmd + [env])) |
213 | else: |
214 | - assert os.spawnle( |
215 | - os.P_WAIT, sys.executable, quote (sys.executable), |
216 | - '-c', quote (cmd), '-mqNxd', quote (tmpeggs), 'zc.buildout' + VERSION, |
217 | - dict(os.environ, |
218 | - PYTHONPATH= |
219 | - ws.find(pkg_resources.Requirement.parse('setuptools')).location |
220 | - ), |
221 | - ) == 0 |
222 | + # Jython can use subprocess but not spawn. We prefer it generally. |
223 | + exitcode = subprocess.Popen(cmd, env=env).wait() |
224 | +if exitcode != 0: |
225 | + # we shouldn't need an error message because a failure |
226 | + # should have generated a visible traceback in the subprocess. |
227 | + sys.exit(exitcode) |
228 | |
229 | -ws.add_entry(tmpeggs) |
230 | -ws.require('zc.buildout' + VERSION) |
231 | +ws.add_entry(configuration['--eggs']) |
232 | +ws.require('zc.buildout' + configuration['--version']) |
233 | import zc.buildout.buildout |
234 | +args.append('bootstrap') |
235 | zc.buildout.buildout.main(args) |
236 | -shutil.rmtree(tmpeggs) |
237 | +if tmpeggs is not None: |
238 | + shutil.rmtree(tmpeggs) |
239 | |
240 | === modified file 'buildout.cfg' |
241 | --- buildout.cfg 2009-03-10 20:13:57 +0000 |
242 | +++ buildout.cfg 2009-07-10 00:02:25 +0000 |
243 | @@ -1,6 +1,7 @@ |
244 | [buildout] |
245 | develop = zc.recipe.egg_ . |
246 | parts = test oltest py |
247 | +include-site-packages = false |
248 | |
249 | [py] |
250 | recipe = zc.recipe.egg |
251 | |
252 | === modified file 'setup.py' |
253 | --- setup.py 2009-06-22 17:48:51 +0000 |
254 | +++ setup.py 2009-07-09 18:17:00 +0000 |
255 | @@ -12,7 +12,7 @@ |
256 | # |
257 | ############################################################################## |
258 | |
259 | -version = "1.3.1dev" |
260 | +version = "1.4.0dev" |
261 | |
262 | import os |
263 | from setuptools import setup, find_packages |
264 | |
265 | === modified file 'src/zc/buildout/bootstrap.txt' |
266 | --- src/zc/buildout/bootstrap.txt 2009-06-22 13:05:44 +0000 |
267 | +++ src/zc/buildout/bootstrap.txt 2009-07-09 23:55:19 +0000 |
268 | @@ -120,4 +120,74 @@ |
269 | zc.buildout.buildout.main() |
270 | <BLANKLINE> |
271 | |
272 | +You can specify a location of ez_setup.py, so you can rely on a local or remote |
273 | +location. We'll write our own ez_setup.py that we will also use to test some |
274 | +other bootstrap options. |
275 | + |
276 | + >>> write('ez_setup.py', '''\ |
277 | + ... def use_setuptools(**kwargs): |
278 | + ... import sys, pprint |
279 | + ... pprint.pprint(kwargs) |
280 | + ... sys.exit() |
281 | + ... ''') |
282 | + >>> print system( |
283 | + ... zc.buildout.easy_install._safe_arg(sys.executable)+' '+ |
284 | + ... 'bootstrap.py --ez_setup-source=./ez_setup.py') |
285 | + ... # doctest: +ELLIPSIS |
286 | + {'download_delay': 0, |
287 | + 'to_dir': '...'} |
288 | + <BLANKLINE> |
289 | + |
290 | +You can also pass a download-cache, and a place in which eggs should be stored |
291 | +(they are normally stored in a temporary directory). |
292 | + |
293 | + >>> print system( |
294 | + ... zc.buildout.easy_install._safe_arg(sys.executable)+' '+ |
295 | + ... 'bootstrap.py --ez_setup-source=./ez_setup.py '+ |
296 | + ... '--download-base=./download-cache --eggs=eggs') |
297 | + ... # doctest: +ELLIPSIS |
298 | + {'download_base': '/sample/download-cache/', |
299 | + 'download_delay': 0, |
300 | + 'to_dir': '/sample/eggs'} |
301 | + <BLANKLINE> |
302 | + |
303 | +Here's the entire help text. |
304 | + |
305 | + >>> print system( |
306 | + ... zc.buildout.easy_install._safe_arg(sys.executable)+' '+ |
307 | + ... 'bootstrap.py --help') |
308 | + ... # doctest: +ELLIPSIS |
309 | + Bootstrap a buildout-based project |
310 | + <BLANKLINE> |
311 | + Simply run this script in a directory containing a buildout.cfg. |
312 | + The script accepts buildout command-line options, so you can |
313 | + use the -c option to specify an alternate configuration file. |
314 | + <BLANKLINE> |
315 | + ... |
316 | + <BLANKLINE> |
317 | + This script recognizes the following options itself. The first option it |
318 | + encounters that is not one of these will cause the script to stop parsing |
319 | + options and pass the rest on to buildout. Therefore, if you want to use |
320 | + any of the following options *and* buildout command-line options like |
321 | + -c, first use the following options, and then use the buildout options. |
322 | + <BLANKLINE> |
323 | + Options: |
324 | + --version=ZC_BUILDOUT_VERSION |
325 | + Specify a version number of the zc.buildout to use |
326 | + --ez_setup-source=URL_OR_FILE |
327 | + Specify a URL or file location for the ez_setup file. |
328 | + Defaults to |
329 | + http://peak.telecommunity.com/dist/ez_setup.py |
330 | + --download-base=URL_OR_DIRECTORY |
331 | + Specify a URL or directory for downloading setuptools and |
332 | + zc.buildout. Defaults to PyPI. |
333 | + --eggs=DIRECTORY |
334 | + Specify a directory for storing eggs. Defaults to a temporary |
335 | + directory that is deleted when the bootstrap script completes. |
336 | + <BLANKLINE> |
337 | + By using --ez_setup-source and --download-base to point to local resources, |
338 | + you can keep this script from going over the network. |
339 | + <BLANKLINE> |
340 | + <BLANKLINE> |
341 | + |
342 | |
343 | |
344 | === modified file 'src/zc/buildout/buildout.py' |
345 | --- src/zc/buildout/buildout.py 2009-06-19 19:56:53 +0000 |
346 | +++ src/zc/buildout/buildout.py 2009-07-10 01:37:32 +0000 |
347 | @@ -59,7 +59,7 @@ |
348 | """ |
349 | |
350 | class MissingSection(zc.buildout.UserError, KeyError): |
351 | - """A required section is missinh |
352 | + """A required section is missing |
353 | """ |
354 | |
355 | def __str__(self): |
356 | @@ -211,20 +211,30 @@ |
357 | if versions: |
358 | zc.buildout.easy_install.default_versions(dict(self[versions])) |
359 | |
360 | - prefer_final = options.get('prefer-final', 'false') |
361 | + prefer_final = options.setdefault('prefer-final', 'false') |
362 | if prefer_final not in ('true', 'false'): |
363 | self._error('Invalid value for prefer-final option: %s', |
364 | prefer_final) |
365 | zc.buildout.easy_install.prefer_final(prefer_final=='true') |
366 | |
367 | - use_dependency_links = options.get('use-dependency-links', 'true') |
368 | + include_site_packages = options.setdefault( |
369 | + 'include-site-packages', 'true') |
370 | + if include_site_packages not in ('true', 'false'): |
371 | + self._error('Invalid value for include-site-packages option: %s', |
372 | + include_site_packages) |
373 | + zc.buildout.easy_install.include_site_packages( |
374 | + include_site_packages=='true') |
375 | + |
376 | + use_dependency_links = options.setdefault( |
377 | + 'use-dependency-links', 'true') |
378 | if use_dependency_links not in ('true', 'false'): |
379 | self._error('Invalid value for use-dependency-links option: %s', |
380 | use_dependency_links) |
381 | zc.buildout.easy_install.use_dependency_links( |
382 | - use_dependency_links == 'true') |
383 | + use_dependency_links=='true') |
384 | |
385 | - allow_picked_versions = options.get('allow-picked-versions', 'true') |
386 | + allow_picked_versions = options.setdefault( |
387 | + 'allow-picked-versions', 'true') |
388 | if allow_picked_versions not in ('true', 'false'): |
389 | self._error('Invalid value for allow-picked-versions option: %s', |
390 | allow_picked_versions) |
391 | @@ -246,22 +256,19 @@ |
392 | |
393 | zc.buildout.easy_install.download_cache(download_cache) |
394 | |
395 | - install_from_cache = options.get('install-from-cache') |
396 | - if install_from_cache: |
397 | - if install_from_cache not in ('true', 'false'): |
398 | - self._error('Invalid value for install-from-cache option: %s', |
399 | - install_from_cache) |
400 | - if install_from_cache == 'true': |
401 | - zc.buildout.easy_install.install_from_cache(True) |
402 | - |
403 | - |
404 | - always_unzip = options.get('unzip') |
405 | - if always_unzip: |
406 | - if always_unzip not in ('true', 'false'): |
407 | - self._error('Invalid value for unzip option: %s', |
408 | - always_unzip) |
409 | - if always_unzip == 'true': |
410 | - zc.buildout.easy_install.always_unzip(True) |
411 | + install_from_cache = options.setdefault( |
412 | + 'install-from-cache', 'false') |
413 | + if install_from_cache not in ('true', 'false'): |
414 | + self._error('Invalid value for install-from-cache option: %s', |
415 | + install_from_cache) |
416 | + zc.buildout.easy_install.install_from_cache( |
417 | + install_from_cache=='true') |
418 | + |
419 | + always_unzip = options.setdefault('unzip', 'false') |
420 | + if always_unzip not in ('true', 'false'): |
421 | + self._error('Invalid value for unzip option: %s', |
422 | + always_unzip) |
423 | + zc.buildout.easy_install.always_unzip(always_unzip=='true') |
424 | |
425 | # "Use" each of the defaults so they aren't reported as unused options. |
426 | for name in _buildout_default_options: |
427 | @@ -275,15 +282,35 @@ |
428 | return os.path.join(self._buildout_dir, name) |
429 | |
430 | def bootstrap(self, args): |
431 | - __doing__ = 'Bootstraping.' |
432 | + __doing__ = 'Bootstrapping.' |
433 | |
434 | self._setup_directories() |
435 | |
436 | - # Now copy buildout and setuptools eggs, amd record destination eggs: |
437 | + options = self['buildout'] |
438 | + |
439 | + # Get a base working set for our distributions that corresponds to the |
440 | + # stated desires in the configuration. |
441 | + distributions = ['setuptools', 'zc.buildout'] |
442 | + if options.get('offline') == 'true': |
443 | + ws = zc.buildout.easy_install.working_set( |
444 | + distributions, options['executable'], |
445 | + [options['develop-eggs-directory'], options['eggs-directory']] |
446 | + ) |
447 | + else: |
448 | + ws = zc.buildout.easy_install.install( |
449 | + distributions, options['eggs-directory'], |
450 | + links=self._links, |
451 | + index=options.get('index'), |
452 | + executable=options['executable'], |
453 | + path=[options['develop-eggs-directory']], |
454 | + newest=self.newest, |
455 | + allow_hosts=self._allow_hosts,) |
456 | + |
457 | + # Now copy buildout and setuptools eggs, and record destination eggs: |
458 | entries = [] |
459 | for name in 'setuptools', 'zc.buildout': |
460 | r = pkg_resources.Requirement.parse(name) |
461 | - dist = pkg_resources.working_set.find(r) |
462 | + dist = ws.find(r) |
463 | if dist.precedence == pkg_resources.DEVELOP_DIST: |
464 | dest = os.path.join(self['buildout']['develop-eggs-directory'], |
465 | name+'.egg-link') |
466 | @@ -303,8 +330,10 @@ |
467 | ws = pkg_resources.WorkingSet(entries) |
468 | ws.require('zc.buildout') |
469 | zc.buildout.easy_install.scripts( |
470 | - ['zc.buildout'], ws, sys.executable, |
471 | - self['buildout']['bin-directory']) |
472 | + ['zc.buildout'], ws, options['executable'], |
473 | + options['bin-directory'], |
474 | + include_site_packages= |
475 | + zc.buildout.easy_install.include_site_packages()) |
476 | |
477 | init = bootstrap |
478 | |
479 | |
480 | === modified file 'src/zc/buildout/buildout.txt' |
481 | --- src/zc/buildout/buildout.txt 2009-06-19 19:56:53 +0000 |
482 | +++ src/zc/buildout/buildout.txt 2009-07-07 17:17:40 +0000 |
483 | @@ -2029,11 +2029,14 @@ |
484 | <BLANKLINE> |
485 | Configuration data: |
486 | [buildout] |
487 | + allow-picked-versions = true |
488 | bin-directory = /sample-buildout/bin |
489 | develop-eggs-directory = /sample-buildout/develop-eggs |
490 | directory = /sample-buildout |
491 | eggs-directory = /sample-buildout/eggs |
492 | executable = /usr/local/bin/python2.3 |
493 | + include-site-packages = true |
494 | + install-from-cache = false |
495 | installed = /sample-buildout/.installed.cfg |
496 | log-format = |
497 | log-level = INFO |
498 | @@ -2041,7 +2044,10 @@ |
499 | offline = false |
500 | parts = |
501 | parts-directory = /sample-buildout/parts |
502 | + prefer-final = false |
503 | python = buildout |
504 | + unzip = false |
505 | + use-dependency-links = true |
506 | verbosity = 20 |
507 | <BLANKLINE> |
508 | |
509 | @@ -2049,6 +2055,14 @@ |
510 | command-line assignments. We've discussed most of these options |
511 | already, but let's review them and touch on some we haven't discussed: |
512 | |
513 | +allow-picked-versions |
514 | + By default, the buildout will choose the best match for a given requirement |
515 | + if the requirement is not specified precisely (for instance, using the |
516 | + "versions" option. This behavior corresponds to the |
517 | + "allow-picked-versions" being set to its default value, "true". If |
518 | + "allow-picked-versions" is "false," instead of picking the best match, |
519 | + buildout will raise an error. This helps enforce repeatability. |
520 | + |
521 | bin-directory |
522 | The directory path where scripts are written. This can be a |
523 | relative path, which is interpreted relative to the directory |
524 | @@ -2073,6 +2087,24 @@ |
525 | The Python executable used to run the buildout. See the python |
526 | option below. |
527 | |
528 | +include-site-packages |
529 | + By default, buildout will look for dependencies in the system's |
530 | + site-packages. For this purpose, paths outside of Python's standard |
531 | + library--or more precisely, those that are not included when Python is |
532 | + started with the -S argument--are loosely referred to as "site-packages" |
533 | + here. The include-site-packages buildout option can be used to override |
534 | + the default behavior of using site packages |
535 | + ("include-site-packages = false"). |
536 | + |
537 | +install-from-cache |
538 | + A download cache can be used as the basis of application source releases. |
539 | + In an application source release, we want to distribute an application that |
540 | + can be built without making any network accesses. In this case, we |
541 | + distribute a buildout with download cache and tell the buildout to install |
542 | + from the download cache only, without making network accesses. The |
543 | + buildout install-from-cache option can be used to signal that packages |
544 | + should be installed only from the download cache. |
545 | + |
546 | installed |
547 | The file path where information about the results of the previous |
548 | buildout run is written. This can be a relative path, which is |
549 | @@ -2086,12 +2118,51 @@ |
550 | log-level |
551 | The log level before verbosity adjustment |
552 | |
553 | +newest |
554 | + By default buildout and recipes will try to find the newest versions of |
555 | + distributions needed to satisfy requirements. This can be very time |
556 | + consuming, especially when incrementally working on setting up a buildout |
557 | + or working on a recipe. The buildout "newest" option can be used to to |
558 | + suppress this. If the "newest" option is set to false, then new |
559 | + distributions won't be sought if an installed distribution meets |
560 | + requirements. The "newest" option can also be set to false using the -N |
561 | + command-line option. See also the "offline" option. |
562 | + |
563 | +offline |
564 | + The "offline" option goes a bit further than the "newest" option. If the |
565 | + buildout "offline" option is given a value of "true", the buildout and |
566 | + recipes that are aware of the option will avoid doing network access. This |
567 | + is handy when running the buildout when not connected to the internet. It |
568 | + also makes buildouts run much faster. This option is typically set using |
569 | + the buildout -o option. |
570 | + |
571 | parts |
572 | A white space separated list of parts to be installed. |
573 | |
574 | parts-directory |
575 | A working directory that parts can used to store data. |
576 | |
577 | +prefer-final |
578 | + Currently, when searching for new releases, the newest available |
579 | + release is used. This isn't usually ideal, as you may get a |
580 | + development release or alpha releases not ready to be widely used. |
581 | + You can request that final releases be preferred using the prefer |
582 | + final option in the buildout section:: |
583 | + |
584 | + [buildout] |
585 | + ... |
586 | + prefer-final = true |
587 | + |
588 | + When the prefer-final option is set to true, then when searching for |
589 | + new releases, final releases are preferred. If there are final |
590 | + releases that satisfy distribution requirements, then those releases |
591 | + are used even if newer non-final releases are available. The buildout |
592 | + prefer-final option can be used to override this behavior. |
593 | + |
594 | + In buildout version 2, final releases will be preferred by default. |
595 | + You will then need to use a false value for prefer-final to get the |
596 | + newest releases. |
597 | + |
598 | python |
599 | The name of a section containing information about the default |
600 | Python interpreter. Recipes that need a installation |
601 | @@ -2102,6 +2173,26 @@ |
602 | Python executable. By default, the buildout section defines the |
603 | default Python as the Python used to run the buildout. |
604 | |
605 | +unzip |
606 | + By default, zc.buildout doesn't unzip zip-safe eggs ("unzip = false"). |
607 | + This follows the policy followed by setuptools itself. Experience shows |
608 | + this policy to to be inconvenient. Zipped eggs make debugging more |
609 | + difficult and often import more slowly. You can include an unzip option in |
610 | + the buildout section to change the default unzipping policy ("unzip = |
611 | + true"). |
612 | + |
613 | +use-dependency-links |
614 | + By default buildout will obey the setuptools dependency_links metadata |
615 | + when it looks for dependencies. This behavior can be controlled with |
616 | + the use-dependency-links buildout option:: |
617 | + |
618 | + [buildout] |
619 | + ... |
620 | + use-dependency-links = false |
621 | + |
622 | + The option defaults to true. If you set it to false, then dependency |
623 | + links are only looked for in the locations specified by find-links. |
624 | + |
625 | verbosity |
626 | A log-level adjustment. Typically, this is set via the -q and -v |
627 | command-line options. |
628 | @@ -2180,48 +2271,6 @@ |
629 | Generated script '/sample-bootstrapped2/bin/buildout'. |
630 | |
631 | |
632 | -Newest and Offline Modes |
633 | ------------------------- |
634 | - |
635 | -By default buildout and recipes will try to find the newest versions |
636 | -of distributions needed to satisfy requirements. This can be very |
637 | -time consuming, especially when incrementally working on setting up a |
638 | -buildout or working on a recipe. The buildout newest option can be |
639 | -used to to suppress this. If the newest option is set to false, then |
640 | -new distributions won't be sought if an installed distribution meets |
641 | -requirements. The newest option can be set to false using the -N |
642 | -command-line option. |
643 | - |
644 | -The offline option goes a bit further. If the buildout offline option |
645 | -is given a value of "true", the buildout and recipes that are aware of |
646 | -the option will avoid doing network access. This is handy when |
647 | -running the buildout when not connected to the internet. It also |
648 | -makes buildouts run much faster. This option is typically set using |
649 | -the buildout -o option. |
650 | - |
651 | -Preferring Final Releases |
652 | -------------------------- |
653 | - |
654 | -Currently, when searching for new releases, the newest available |
655 | -release is used. This isn't usually ideal, as you may get a |
656 | -development release or alpha releases not ready to be widely used. |
657 | -You can request that final releases be preferred using the prefer |
658 | -final option in the buildout section:: |
659 | - |
660 | - [buildout] |
661 | - ... |
662 | - prefer-final = true |
663 | - |
664 | -When the prefer-final option is set to true, then when searching for |
665 | -new releases, final releases are preferred. If there are final |
666 | -releases that satisfy distribution requirements, then those releases |
667 | -are used even if newer non-final releases are available. The buildout |
668 | -prefer-final option can be used to override this behavior. |
669 | - |
670 | -In buildout version 2, final releases will be preferred by default. |
671 | -You will then need to use a false value for prefer-final to get the |
672 | -newest releases. |
673 | - |
674 | Finding distributions |
675 | --------------------- |
676 | |
677 | @@ -2270,19 +2319,6 @@ |
678 | /some/otherpath |
679 | /some/path/someegg-1.0.0-py2.3.egg |
680 | |
681 | -Dependency links |
682 | ----------------- |
683 | - |
684 | -By default buildout will obey the setuptools dependency_links metadata |
685 | -when it looks for dependencies. This behavior can be controlled with |
686 | -the use-dependency-links buildout option:: |
687 | - |
688 | - [buildout] |
689 | - ... |
690 | - use-dependency-links = false |
691 | - |
692 | -The option defaults to true. If you set it to false, then dependency |
693 | -links are only looked for in the locations specified by find-links. |
694 | |
695 | Controlling the installation database |
696 | ------------------------------------- |
697 | |
698 | === modified file 'src/zc/buildout/easy_install.py' |
699 | --- src/zc/buildout/easy_install.py 2009-06-22 16:41:40 +0000 |
700 | +++ src/zc/buildout/easy_install.py 2009-07-11 15:49:15 +0000 |
701 | @@ -64,12 +64,54 @@ |
702 | pkg_resources.Requirement.parse('setuptools') |
703 | ).location |
704 | |
705 | -# Include buildout and setuptools eggs in paths |
706 | -buildout_and_setuptools_path = [ |
707 | - setuptools_loc, |
708 | - pkg_resources.working_set.find( |
709 | - pkg_resources.Requirement.parse('zc.buildout')).location, |
710 | - ] |
711 | +# Include buildout and setuptools eggs in paths. We prevent dupes just to |
712 | +# keep from duplicating any log messages about them. |
713 | +buildout_loc = pkg_resources.working_set.find( |
714 | + pkg_resources.Requirement.parse('zc.buildout')).location |
715 | +buildout_and_setuptools_path = [setuptools_loc] |
716 | +if os.path.normpath(setuptools_loc) != os.path.normpath(buildout_loc): |
717 | + buildout_and_setuptools_path.append(buildout_loc) |
718 | + |
719 | +def _get_system_packages(executable): |
720 | + """return a pair of the standard lib and site packages for the executable. |
721 | + """ |
722 | + # We want to get a list of the site packages, which is not easy. The |
723 | + # canonical way to do this is to use distutils.sysconfig.get_python_lib(), |
724 | + # but that only returns a single path, which does not reflect reality for |
725 | + # many system Pythons, which have multiple additions. Instead, we start |
726 | + # Python with -S, which does not import site.py and set up the extra paths |
727 | + # like site-packages or (Ubuntu/Debian) dist-packages and python-support. |
728 | + # We then compare that sys.path with the normal one. The set of the normal |
729 | + # one minus the set of the ones in ``python -S`` is the set of packages |
730 | + # that are effectively site-packages. |
731 | + def get_sys_path(clean=False): |
732 | + cmd = [executable, "-c", |
733 | + "import sys, os;" |
734 | + "print repr([os.path.normpath(p) for p in sys.path])"] |
735 | + if clean: |
736 | + cmd.insert(1, '-S') |
737 | + _proc = subprocess.Popen( |
738 | + cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) |
739 | + stdout, stderr = _proc.communicate(); |
740 | + if _proc.returncode: |
741 | + raise RuntimeError( |
742 | + 'error trying to get system packages:\n%s' % (stderr,)) |
743 | + res = eval(stdout) |
744 | + try: |
745 | + res.remove('.') |
746 | + except ValueError: |
747 | + pass |
748 | + return res |
749 | + stdlib = get_sys_path(clean=True) |
750 | + # The given executable might not be the current executable, so it is |
751 | + # appropriate to do another subprocess to figure out what the additional |
752 | + # site-package paths are. Moreover, even if this executable *is* the |
753 | + # current executable, this code might be run in the context of code that |
754 | + # has manipulated the sys.path--for instance, to add local zc.buildout or |
755 | + # setuptools eggs. |
756 | + site_packages = [p for p in get_sys_path() if p not in stdlib] |
757 | + return (stdlib, site_packages) |
758 | + |
759 | |
760 | class IncompatibleVersionError(zc.buildout.UserError): |
761 | """A specified version is incompatible with a given requirement. |
762 | @@ -99,6 +141,7 @@ |
763 | |
764 | FILE_SCHEME = re.compile('file://', re.I).match |
765 | |
766 | + |
767 | class AllowHostsPackageIndex(setuptools.package_index.PackageIndex): |
768 | """Will allow urls that are local to the system. |
769 | |
770 | @@ -111,7 +154,12 @@ |
771 | |
772 | |
773 | _indexes = {} |
774 | -def _get_index(executable, index_url, find_links, allow_hosts=('*',)): |
775 | +def _get_index(executable, index_url, find_links, allow_hosts=('*',), |
776 | + path=None): |
777 | + # If path is None, the index will use sys.path. If you provide an empty |
778 | + # path ([]), it will complain uselessly about missing index pages for |
779 | + # packages found in the paths that you expect to use. Therefore, this path |
780 | + # is always the same as the _env path in the Installer. |
781 | key = executable, index_url, tuple(find_links) |
782 | index = _indexes.get(key) |
783 | if index is not None: |
784 | @@ -120,7 +168,8 @@ |
785 | if index_url is None: |
786 | index_url = default_index_url |
787 | index = AllowHostsPackageIndex( |
788 | - index_url, hosts=allow_hosts, python=_get_version(executable) |
789 | + index_url, hosts=allow_hosts, search_path=path, |
790 | + python=_get_version(executable) |
791 | ) |
792 | |
793 | if find_links: |
794 | @@ -152,6 +201,7 @@ |
795 | _use_dependency_links = True |
796 | _allow_picked_versions = True |
797 | _always_unzip = False |
798 | + _include_site_packages = True |
799 | |
800 | def __init__(self, |
801 | dest=None, |
802 | @@ -163,6 +213,7 @@ |
803 | newest=True, |
804 | versions=None, |
805 | use_dependency_links=None, |
806 | + include_site_packages=None, |
807 | allow_hosts=('*',) |
808 | ): |
809 | self._dest = dest |
810 | @@ -185,7 +236,16 @@ |
811 | self._executable = executable |
812 | if always_unzip is not None: |
813 | self._always_unzip = always_unzip |
814 | - path = (path and path[:] or []) + buildout_and_setuptools_path |
815 | + path = (path and path[:] or []) |
816 | + if include_site_packages is not None: |
817 | + self._include_site_packages = include_site_packages |
818 | + stdlib, self._site_packages = _get_system_packages(executable) |
819 | + if self._include_site_packages: |
820 | + path.extend(buildout_and_setuptools_path) |
821 | + path.extend(self._site_packages) |
822 | + # else we could try to still include the buildout_and_setuptools_path |
823 | + # if the elements are not in site_packages, but we're not bothering |
824 | + # with this optimization for now, in the name of code simplicity. |
825 | if dest is not None and dest not in path: |
826 | path.insert(0, dest) |
827 | self._path = path |
828 | @@ -194,13 +254,26 @@ |
829 | self._newest = newest |
830 | self._env = pkg_resources.Environment(path, |
831 | python=_get_version(executable)) |
832 | - self._index = _get_index(executable, index, links, self._allow_hosts) |
833 | + self._index = _get_index(executable, index, links, self._allow_hosts, |
834 | + self._path) |
835 | |
836 | if versions is not None: |
837 | self._versions = versions |
838 | |
839 | def _satisfied(self, req, source=None): |
840 | - dists = [dist for dist in self._env[req.project_name] if dist in req] |
841 | + # We get all distributions that match the given requirement. If we |
842 | + # are not supposed to include site-packages, we also filter those out. |
843 | + # We need to do the filtering here even though we have exluded |
844 | + # site packages from the _env's paths (see Installer.__init__) because |
845 | + # an .egg-link, such as one for setuptools or zc.buildout installed |
846 | + # by zc.buildout.buildout.Buildout.bootstrap, can indirectly include |
847 | + # a path in our _site_packages. |
848 | + dists = [dist for dist in self._env[req.project_name] if ( |
849 | + dist in req and ( |
850 | + self._include_site_packages or |
851 | + dist.location not in self._site_packages) |
852 | + ) |
853 | + ] |
854 | if not dists: |
855 | logger.debug('We have no distributions for %s that satisfies %r.', |
856 | req.project_name, str(req)) |
857 | @@ -404,10 +477,19 @@ |
858 | # Nothing is available. |
859 | return None |
860 | |
861 | - # Filter the available dists for the requirement and source flag |
862 | + # Filter the available dists for the requirement and source flag. If we |
863 | + # are not supposed to include site-packages, we also filter those out. |
864 | + # We need to do the filtering here even though we have exluded site |
865 | + # packages from the _index's paths (see Installer.__init__) because an |
866 | + # .egg-link, such as one for setuptools or zc.buildout installed by |
867 | + # zc.buildout.buildout.Buildout.bootstrap, can indirectly include a |
868 | + # path in our _site_packages. |
869 | dists = [dist for dist in index[requirement.project_name] |
870 | if ((dist in requirement) |
871 | and |
872 | + (self._include_site_packages or |
873 | + dist.location not in self._site_packages) |
874 | + and |
875 | ((not source) or |
876 | (dist.precedence == pkg_resources.SOURCE_DIST) |
877 | ) |
878 | @@ -571,7 +653,7 @@ |
879 | self._links.append(link) |
880 | self._index = _get_index(self._executable, |
881 | self._index_url, self._links, |
882 | - self._allow_hosts) |
883 | + self._allow_hosts, self._path) |
884 | |
885 | for dist in dists: |
886 | # Check whether we picked a version and, if we did, report it: |
887 | @@ -650,34 +732,52 @@ |
888 | self._maybe_add_setuptools(ws, dist) |
889 | |
890 | # OK, we have the requested distributions and they're in the working |
891 | - # set, but they may have unmet requirements. We'll simply keep |
892 | - # trying to resolve requirements, adding missing requirements as they |
893 | - # are reported. |
894 | - # |
895 | - # Note that we don't pass in the environment, because we want |
896 | + # set, but they may have unmet requirements. We'll resolve these |
897 | + # requirements. This is code modified from |
898 | + # pkg_resources.WorkingSet.resolve. We can't reuse that code directly |
899 | + # because we have to constrain our requirements (see |
900 | + # versions_section_ignored_for_dependency_in_favor_of_site_packages in |
901 | + # zc.buildout.tests). |
902 | + # |
903 | + requirements.reverse() # set up the stack |
904 | + processed = {} # set of processed requirements |
905 | + best = {} # key -> dist |
906 | + # |
907 | + # Note that we don't use the existing environment, because we want |
908 | # to look for new eggs unless what we have is the best that |
909 | # matches the requirement. |
910 | - while 1: |
911 | - try: |
912 | - ws.resolve(requirements) |
913 | - except pkg_resources.DistributionNotFound, err: |
914 | - [requirement] = err |
915 | - requirement = self._constrain(requirement) |
916 | - if dest: |
917 | - logger.debug('Getting required %r', str(requirement)) |
918 | - else: |
919 | - logger.debug('Adding required %r', str(requirement)) |
920 | - _log_requirement(ws, requirement) |
921 | - |
922 | - for dist in self._get_dist(requirement, ws, self._always_unzip |
923 | - ): |
924 | - |
925 | - ws.add(dist) |
926 | - self._maybe_add_setuptools(ws, dist) |
927 | - except pkg_resources.VersionConflict, err: |
928 | - raise VersionConflict(err, ws) |
929 | - else: |
930 | - break |
931 | + env = pkg_resources.Environment(ws.entries) |
932 | + while requirements: |
933 | + # process dependencies breadth-first |
934 | + req = self._constrain(requirements.pop(0)) |
935 | + if req in processed: |
936 | + # Ignore cyclic or redundant dependencies |
937 | + continue |
938 | + dist = best.get(req.key) |
939 | + if dist is None: |
940 | + # Find the best distribution and add it to the map |
941 | + dist = ws.by_key.get(req.key) |
942 | + if dist is None: |
943 | + try: |
944 | + dist = best[req.key] = env.best_match(req, ws) |
945 | + except pkg_resources.VersionConflict, err: |
946 | + raise VersionConflict(err, ws) |
947 | + if dist is None: |
948 | + if dest: |
949 | + logger.debug('Getting required %r', str(req)) |
950 | + else: |
951 | + logger.debug('Adding required %r', str(req)) |
952 | + _log_requirement(ws, req) |
953 | + for dist in self._get_dist(req, |
954 | + ws, self._always_unzip): |
955 | + ws.add(dist) |
956 | + self._maybe_add_setuptools(ws, dist) |
957 | + if dist not in req: |
958 | + # Oops, the "best" so far conflicts with a dependency |
959 | + raise VersionConflict( |
960 | + pkg_resources.VersionConflict(dist, req), ws) |
961 | + requirements.extend(dist.requires(req.extras)[::-1]) |
962 | + processed[req] = True |
963 | |
964 | return ws |
965 | |
966 | @@ -773,6 +873,12 @@ |
967 | Installer._prefer_final = bool(setting) |
968 | return old |
969 | |
970 | +def include_site_packages(setting=None): |
971 | + old = Installer._include_site_packages |
972 | + if setting is not None: |
973 | + Installer._include_site_packages = bool(setting) |
974 | + return old |
975 | + |
976 | def use_dependency_links(setting=None): |
977 | old = Installer._use_dependency_links |
978 | if setting is not None: |
979 | @@ -795,19 +901,21 @@ |
980 | links=(), index=None, |
981 | executable=sys.executable, always_unzip=None, |
982 | path=None, working_set=None, newest=True, versions=None, |
983 | - use_dependency_links=None, allow_hosts=('*',)): |
984 | + use_dependency_links=None, include_site_packages=None, |
985 | + allow_hosts=('*',)): |
986 | installer = Installer(dest, links, index, executable, always_unzip, path, |
987 | newest, versions, use_dependency_links, |
988 | - allow_hosts=allow_hosts) |
989 | + include_site_packages, allow_hosts=allow_hosts) |
990 | return installer.install(specs, working_set) |
991 | |
992 | |
993 | def build(spec, dest, build_ext, |
994 | links=(), index=None, |
995 | executable=sys.executable, |
996 | - path=None, newest=True, versions=None, allow_hosts=('*',)): |
997 | + path=None, newest=True, versions=None, include_site_packages=None, |
998 | + allow_hosts=('*',)): |
999 | installer = Installer(dest, links, index, executable, True, path, newest, |
1000 | - versions, allow_hosts=allow_hosts) |
1001 | + versions, include_site_packages, allow_hosts=allow_hosts) |
1002 | return installer.build(spec, build_ext) |
1003 | |
1004 | |
1005 | @@ -903,8 +1011,54 @@ |
1006 | [f() for f in undo] |
1007 | |
1008 | |
1009 | -def working_set(specs, executable, path): |
1010 | - return install(specs, None, executable=executable, path=path) |
1011 | +def working_set(specs, executable, path, include_site_packages=None): |
1012 | + return install( |
1013 | + specs, None, executable=executable, path=path, |
1014 | + include_site_packages=include_site_packages) |
1015 | + |
1016 | +def get_path(working_set, executable, extra_paths=(), |
1017 | + include_site_packages=True): |
1018 | + """Given working set and path to executable, return value for sys.path. |
1019 | + |
1020 | + Distribution locations from the working set come first in the list. Within |
1021 | + that collection, this function pushes site-packages-based distribution |
1022 | + locations to the end of the list, so that they don't mask eggs. |
1023 | + |
1024 | + This expects that the working_set has already been created to honor a |
1025 | + include_site_packages setting. That is, if include_site_packages is False, |
1026 | + this function does *not* verify that the working_set's distributions are |
1027 | + not in site packages. |
1028 | + |
1029 | + However, it does explicitly include site packages if include_site_packages |
1030 | + is True. |
1031 | + |
1032 | + The standard library (defined as what the given Python executable has on |
1033 | + the path before its site.py is run) is always included. |
1034 | + """ |
1035 | + stdlib, site_packages = _get_system_packages(executable) |
1036 | + postponed = [] |
1037 | + path = [] |
1038 | + for dist in working_set: |
1039 | + location = os.path.normpath(dist.location) |
1040 | + if location in path: |
1041 | + path.remove(location) |
1042 | + postponed.append(location) |
1043 | + elif location in site_packages: |
1044 | + postponed.append(location) |
1045 | + elif location not in postponed: |
1046 | + path.append(location) |
1047 | + path.extend(postponed) |
1048 | + path.extend(extra_paths) |
1049 | + # now we add in all paths |
1050 | + if include_site_packages: |
1051 | + # err a bit on the side of cleanliness, avoiding dupes just to look |
1052 | + # pretty. |
1053 | + for location in site_packages: |
1054 | + if location not in path: |
1055 | + path.append(location) |
1056 | + path.extend(stdlib) |
1057 | + path = map(realpath, path) |
1058 | + return path |
1059 | |
1060 | def scripts(reqs, working_set, executable, dest, |
1061 | scripts=None, |
1062 | @@ -912,13 +1066,11 @@ |
1063 | arguments='', |
1064 | interpreter=None, |
1065 | initialization='', |
1066 | - relative_paths=False, |
1067 | + include_site_packages=True, |
1068 | + relative_paths=False |
1069 | ): |
1070 | - |
1071 | - path = [dist.location for dist in working_set] |
1072 | - path.extend(extra_paths) |
1073 | - path = map(realpath, path) |
1074 | - |
1075 | + path = get_path( |
1076 | + working_set, executable, extra_paths, include_site_packages) |
1077 | generated = [] |
1078 | |
1079 | if isinstance(reqs, str): |
1080 | @@ -969,7 +1121,7 @@ |
1081 | if relative_paths: |
1082 | relative_paths = os.path.normcase(relative_paths) |
1083 | sname = os.path.normcase(os.path.abspath(sname)) |
1084 | - spath = ',\n '.join( |
1085 | + spath = ',\n '.join( |
1086 | [_relativitize(os.path.normcase(path_item), sname, relative_paths) |
1087 | for path_item in path] |
1088 | ) |
1089 | @@ -977,7 +1129,7 @@ |
1090 | for i in range(_relative_depth(relative_paths, sname)): |
1091 | rpsetup += "base = os.path.dirname(base)\n" |
1092 | else: |
1093 | - spath = repr(path)[1:-1].replace(', ', ',\n ') |
1094 | + spath = repr(path)[1:-1].replace(', ', ',\n ') |
1095 | rpsetup = '' |
1096 | return spath, rpsetup |
1097 | |
1098 | @@ -1075,9 +1227,9 @@ |
1099 | |
1100 | %(relative_paths_setup)s |
1101 | import sys |
1102 | -sys.path[0:0] = [ |
1103 | - %(path)s, |
1104 | - ] |
1105 | +sys.path[:] = [ |
1106 | + %(path)s, |
1107 | + ] |
1108 | %(initialization)s |
1109 | import %(module_name)s |
1110 | |
1111 | @@ -1120,31 +1272,60 @@ |
1112 | |
1113 | py_script_template = script_header + '''\ |
1114 | |
1115 | +globs = globals().copy() # get a clean copy early |
1116 | + |
1117 | %(relative_paths_setup)s |
1118 | import sys |
1119 | |
1120 | -sys.path[0:0] = [ |
1121 | - %(path)s, |
1122 | - ] |
1123 | - |
1124 | -_interactive = True |
1125 | -if len(sys.argv) > 1: |
1126 | - import getopt |
1127 | - _options, _args = getopt.getopt(sys.argv[1:], 'ic:') |
1128 | +_set_path = _interactive = True |
1129 | +_force_interactive = False |
1130 | + |
1131 | +_command = None |
1132 | +_args = sys.argv[1:] |
1133 | + |
1134 | +while _args: |
1135 | + if _args[0].startswith('-'): |
1136 | + _arg = _args.pop(0) |
1137 | + for _ix, _opt in enumerate(_arg[1:]): |
1138 | + if _opt == 'i': |
1139 | + _force_interactive = True |
1140 | + elif _opt == 'c': |
1141 | + _interactive = False |
1142 | + _command = _args.pop(0) # Argument expected for the -c option |
1143 | + _args.insert(0, '-c') |
1144 | + break |
1145 | + elif _opt == 'S': |
1146 | + # We'll approximate this. It is mostly convenient for tests. |
1147 | + _set_path = False |
1148 | + elif _opt == 'V': |
1149 | + print 'Python ' + sys.version.split()[0] |
1150 | + _interactive = False |
1151 | + break |
1152 | + else: |
1153 | + continue |
1154 | + break |
1155 | + else: |
1156 | + break |
1157 | + |
1158 | +if _set_path: |
1159 | + sys.path[:] = [ |
1160 | + %(path)s, |
1161 | + ] |
1162 | +sys.path.insert(0, '.') |
1163 | + |
1164 | +sys.argv[:] = _args |
1165 | + |
1166 | +if _command: |
1167 | + exec _command |
1168 | +elif _args: |
1169 | _interactive = False |
1170 | - for (_opt, _val) in _options: |
1171 | - if _opt == '-i': |
1172 | - _interactive = True |
1173 | - elif _opt == '-c': |
1174 | - exec _val |
1175 | - |
1176 | - if _args: |
1177 | - sys.argv[:] = _args |
1178 | - execfile(sys.argv[0]) |
1179 | - |
1180 | -if _interactive: |
1181 | + globs['__file__'] = sys.argv[0] |
1182 | + execfile(sys.argv[0], globs) |
1183 | + |
1184 | +if _interactive or _force_interactive: |
1185 | import code |
1186 | - code.interact(banner="", local=globals()) |
1187 | + del globs['__file__'] |
1188 | + code.interact(banner="", local=globs) |
1189 | ''' |
1190 | |
1191 | runsetup_template = """ |
1192 | |
1193 | === modified file 'src/zc/buildout/easy_install.txt' |
1194 | --- src/zc/buildout/easy_install.txt 2009-06-22 16:41:40 +0000 |
1195 | +++ src/zc/buildout/easy_install.txt 2009-07-10 00:00:06 +0000 |
1196 | @@ -89,6 +89,14 @@ |
1197 | for using dependency_links in preference to other |
1198 | locations. Defaults to true. |
1199 | |
1200 | +include_site_packages |
1201 | + A flag indicating whether Python's non-standard-library packages should |
1202 | + be available for finding dependencies. Defaults to true. |
1203 | + |
1204 | + Paths outside of Python's standard library--or more precisely, those that |
1205 | + are not included when Python is started with the -S argument--are loosely |
1206 | + referred to as "site-packages" here. |
1207 | + |
1208 | relative_paths |
1209 | Adjust egg paths so they are relative to the script path. This |
1210 | allows scripts to work when scripts and eggs are moved, as long as |
1211 | @@ -399,6 +407,65 @@ |
1212 | >>> [d.version for d in ws] |
1213 | ['0.3', '1.1'] |
1214 | |
1215 | +Dependencies in Site Packages |
1216 | +----------------------------- |
1217 | + |
1218 | +Paths outside of Python's standard library--or more precisely, those that are |
1219 | +not included when Python is started with the -S argument--are loosely referred |
1220 | +to as "site-packages" here. These site-packages are searched by default for |
1221 | +distributions. This can be disabled, so that, for instance, a system Python |
1222 | +can be used with buildout, cleaned of any packages installed by a user or |
1223 | +system package manager. |
1224 | + |
1225 | +The default behavior can be controlled and introspected using |
1226 | +zc.buildout.easy_install.include_site_packages. |
1227 | + |
1228 | + >>> zc.buildout.easy_install.include_site_packages() |
1229 | + True |
1230 | + |
1231 | +Here's an example of using a Python executable that includes our dependencies. |
1232 | + |
1233 | +Our "primed_executable" has the "demoneeded," "other," and "setuptools" |
1234 | +packages available. We'll simply be asking for "other" here. |
1235 | + |
1236 | + >>> primed_executable = get_executable_with_site_packages() |
1237 | + |
1238 | + >>> example_dest = tmpdir('site-packages-example-install') |
1239 | + >>> workingset = zc.buildout.easy_install.install( |
1240 | + ... ['other'], example_dest, links=[], executable=primed_executable, |
1241 | + ... index=None) |
1242 | + >>> [dist.project_name for dist in workingset] |
1243 | + ['other'] |
1244 | + |
1245 | +That worked fine. Let's try again with site packages not allowed. We'll |
1246 | +change the policy by changing the default. Notice that the function for |
1247 | +changing the default value returns the previous value. |
1248 | + |
1249 | + >>> zc.buildout.easy_install.include_site_packages(False) |
1250 | + True |
1251 | + |
1252 | + >>> zc.buildout.easy_install.include_site_packages() |
1253 | + False |
1254 | + |
1255 | + >>> zc.buildout.easy_install.clear_index_cache() |
1256 | + >>> rmdir(example_dest) |
1257 | + >>> example_dest = tmpdir('site-packages-example-install') |
1258 | + >>> workingset = zc.buildout.easy_install.install( |
1259 | + ... ['other'], example_dest, links=[], executable=primed_executable, |
1260 | + ... index=None) |
1261 | + Traceback (most recent call last): |
1262 | + ... |
1263 | + MissingDistribution: Couldn't find a distribution for 'other'. |
1264 | + >>> zc.buildout.easy_install.clear_index_cache() |
1265 | + |
1266 | +Now we'll reset the default. |
1267 | + |
1268 | + >>> zc.buildout.easy_install.include_site_packages(True) |
1269 | + False |
1270 | + |
1271 | + >>> zc.buildout.easy_install.include_site_packages() |
1272 | + True |
1273 | + |
1274 | Dependency links |
1275 | ---------------- |
1276 | |
1277 | @@ -580,14 +647,15 @@ |
1278 | |
1279 | The demo script run the entry point defined in the demo egg: |
1280 | |
1281 | - >>> cat(bin, 'demo') # doctest: +NORMALIZE_WHITESPACE |
1282 | + >>> cat(bin, 'demo') # doctest: +NORMALIZE_WHITESPACE +ELLIPSIS |
1283 | #!/usr/local/bin/python2.4 |
1284 | <BLANKLINE> |
1285 | import sys |
1286 | - sys.path[0:0] = [ |
1287 | - '/sample-install/demo-0.3-py2.4.egg', |
1288 | - '/sample-install/demoneeded-1.1-py2.4.egg', |
1289 | - ] |
1290 | + sys.path[:] = [ |
1291 | + '/sample-install/demo-0.3-py2.4.egg', |
1292 | + '/sample-install/demoneeded-1.1-py2.4.egg', |
1293 | + ... |
1294 | + ] |
1295 | <BLANKLINE> |
1296 | import eggrecipedemo |
1297 | <BLANKLINE> |
1298 | @@ -596,7 +664,8 @@ |
1299 | |
1300 | Some things to note: |
1301 | |
1302 | -- The demo and demoneeded eggs are added to the beginning of sys.path. |
1303 | +- The demo and demoneeded eggs are at the beginning of sys.path. The script |
1304 | + controls the entire path. |
1305 | |
1306 | - The module for the script entry point is imported and the entry |
1307 | point, in this case, 'main', is run. |
1308 | @@ -617,14 +686,15 @@ |
1309 | ... [('demo', 'eggrecipedemo', 'main')], |
1310 | ... ws, sys.executable, bin) |
1311 | |
1312 | - >>> cat(bin, 'demo') # doctest: +NORMALIZE_WHITESPACE |
1313 | + >>> cat(bin, 'demo') # doctest: +NORMALIZE_WHITESPACE +ELLIPSIS |
1314 | #!/usr/local/bin/python2.4 |
1315 | <BLANKLINE> |
1316 | import sys |
1317 | - sys.path[0:0] = [ |
1318 | - '/sample-install/demo-0.3-py2.4.egg', |
1319 | - '/sample-install/demoneeded-1.1-py2.4.egg', |
1320 | - ] |
1321 | + sys.path[:] = [ |
1322 | + '/sample-install/demo-0.3-py2.4.egg', |
1323 | + '/sample-install/demoneeded-1.1-py2.4.egg', |
1324 | + ... |
1325 | + ] |
1326 | <BLANKLINE> |
1327 | import eggrecipedemo |
1328 | <BLANKLINE> |
1329 | @@ -661,33 +731,63 @@ |
1330 | The py script simply runs the Python interactive interpreter with |
1331 | the path set: |
1332 | |
1333 | - >>> cat(bin, 'py') # doctest: +NORMALIZE_WHITESPACE |
1334 | + >>> cat(bin, 'py') # doctest: +NORMALIZE_WHITESPACE +ELLIPSIS |
1335 | #!/usr/local/bin/python2.4 |
1336 | + globs = globals().copy() # get a clean copy early |
1337 | + <BLANKLINE> |
1338 | import sys |
1339 | <BLANKLINE> |
1340 | - sys.path[0:0] = [ |
1341 | - '/sample-install/demo-0.3-py2.4.egg', |
1342 | - '/sample-install/demoneeded-1.1-py2.4.egg', |
1343 | - ] |
1344 | - <BLANKLINE> |
1345 | - _interactive = True |
1346 | - if len(sys.argv) > 1: |
1347 | - import getopt |
1348 | - _options, _args = getopt.getopt(sys.argv[1:], 'ic:') |
1349 | + _set_path = _interactive = True |
1350 | + _force_interactive = False |
1351 | + <BLANKLINE> |
1352 | + _command = None |
1353 | + _args = sys.argv[1:] |
1354 | + <BLANKLINE> |
1355 | + while _args: |
1356 | + if _args[0].startswith('-'): |
1357 | + _arg = _args.pop(0) |
1358 | + for _ix, _opt in enumerate(_arg[1:]): |
1359 | + if _opt == 'i': |
1360 | + _force_interactive = True |
1361 | + elif _opt == 'c': |
1362 | + _interactive = False |
1363 | + _command = _args.pop(0) # Argument expected for the -c option |
1364 | + _args.insert(0, '-c') |
1365 | + break |
1366 | + elif _opt == 'S': |
1367 | + # We'll approximate this. It is mostly convenient for tests. |
1368 | + _set_path = False |
1369 | + elif _opt == 'V': |
1370 | + print 'Python ' + sys.version.split()[0] |
1371 | + _interactive = False |
1372 | + break |
1373 | + else: |
1374 | + continue |
1375 | + break |
1376 | + else: |
1377 | + break |
1378 | + <BLANKLINE> |
1379 | + if _set_path: |
1380 | + sys.path[:] = [ |
1381 | + '/sample-install/demo-0.3-pyN.N.egg', |
1382 | + '/sample-install/demoneeded-1.1-pyN.N.egg', |
1383 | + ... |
1384 | + ] |
1385 | + sys.path.insert(0, '.') |
1386 | + <BLANKLINE> |
1387 | + sys.argv[:] = _args |
1388 | + <BLANKLINE> |
1389 | + if _command: |
1390 | + exec _command |
1391 | + elif _args: |
1392 | _interactive = False |
1393 | - for (_opt, _val) in _options: |
1394 | - if _opt == '-i': |
1395 | - _interactive = True |
1396 | - elif _opt == '-c': |
1397 | - exec _val |
1398 | - <BLANKLINE> |
1399 | - if _args: |
1400 | - sys.argv[:] = _args |
1401 | - execfile(sys.argv[0]) |
1402 | - <BLANKLINE> |
1403 | - if _interactive: |
1404 | + globs['__file__'] = sys.argv[0] |
1405 | + execfile(sys.argv[0], globs) |
1406 | + <BLANKLINE> |
1407 | + if _interactive or _force_interactive: |
1408 | import code |
1409 | - code.interact(banner="", local=globals()) |
1410 | + del globs['__file__'] |
1411 | + code.interact(banner="", local=globs) |
1412 | |
1413 | If invoked with a script name and arguments, it will run that script, instead. |
1414 | |
1415 | @@ -722,14 +822,15 @@ |
1416 | ... ['demo'], ws, sys.executable, bin, dict(demo='run'), |
1417 | ... extra_paths=[foo]) |
1418 | |
1419 | - >>> cat(bin, 'run') # doctest: +NORMALIZE_WHITESPACE |
1420 | + >>> cat(bin, 'run') # doctest: +NORMALIZE_WHITESPACE +ELLIPSIS |
1421 | #!/usr/local/bin/python2.4 |
1422 | <BLANKLINE> |
1423 | import sys |
1424 | - sys.path[0:0] = [ |
1425 | + sys.path[:] = [ |
1426 | '/sample-install/demo-0.3-py2.4.egg', |
1427 | '/sample-install/demoneeded-1.1-py2.4.egg', |
1428 | '/foo', |
1429 | + ... |
1430 | ] |
1431 | <BLANKLINE> |
1432 | import eggrecipedemo |
1433 | @@ -737,6 +838,68 @@ |
1434 | if __name__ == '__main__': |
1435 | eggrecipedemo.main() |
1436 | |
1437 | +Ordering paths |
1438 | +-------------- |
1439 | + |
1440 | +We have already seen that we have a precise definition for a loose term: |
1441 | +"site-packages". Paths outside of Python's standard library--or more |
1442 | +precisely, those that are not included when Python is started with the -S |
1443 | +argument--are loosely referred to as "site-packages" here. |
1444 | + |
1445 | +When generating scripts, paths that come from the site-packages are ordered |
1446 | +after the other specific dependencies generated from the working set. This |
1447 | +is so that directories such as "site-packages" that can contain multiple |
1448 | +dependencies come after the more specific distributions found by setuptools, |
1449 | +reducing the chance of the distributions being masked by the system folders. |
1450 | + |
1451 | +This is controlled by the ``get_path`` function, which is available for |
1452 | +other script recipes to use. |
1453 | + |
1454 | +As a demonstration, we will have create a working set that has dependencies |
1455 | +on "bigdemo" and "other". In our first case, we will use a clean Python |
1456 | +without any of these dependencies installed. |
1457 | + |
1458 | + >>> dest1 = tmpdir('path-install-1') |
1459 | + >>> ws1 = zc.buildout.easy_install.install( |
1460 | + ... ['other', 'bigdemo'], dest1, |
1461 | + ... links=[link_server], index=link_server+'index/') |
1462 | + >>> path1 = zc.buildout.easy_install.get_path(ws1, sys.executable) |
1463 | + |
1464 | + >>> import pprint |
1465 | + >>> pprint.pprint(path1) # doctest: +ELLIPSIS |
1466 | + ['.../path-install-1/other-1.0-py...egg', |
1467 | + '.../path-install-1/bigdemo-0.1-py...egg', |
1468 | + '.../path-install-1/demo-0.3-py...egg', |
1469 | + '.../path-install-1/demoneeded-1.1-py...egg', |
1470 | + ...] |
1471 | + |
1472 | +We will now compare the results using a Python that has bigdemo's indirect |
1473 | +dependency available, "demoneeded," and "other," but not "demo" or "bigdemo". |
1474 | + |
1475 | + >>> dest2 = tmpdir('path-install-2') |
1476 | + >>> ws2 = zc.buildout.easy_install.install( |
1477 | + ... ['other', 'bigdemo'], dest2, |
1478 | + ... links=[link_server], index=link_server+'index/', |
1479 | + ... executable=primed_executable) |
1480 | + >>> path2 = zc.buildout.easy_install.get_path(ws2, primed_executable) |
1481 | + >>> pprint.pprint(path2) # doctest: +ELLIPSIS |
1482 | + ['.../path-install-2/bigdemo-0.1-py...egg', |
1483 | + '.../path-install-2/demo-0.3-py...egg', |
1484 | + '.../executable/eggs/other-1.0-py...egg', |
1485 | + '.../executable/eggs/demoneeded-1.1-py...egg', |
1486 | + '.../executable/eggs/setuptools-0.6c9-py...egg', |
1487 | + '.../executable/bin', |
1488 | + ...] |
1489 | + >>> zc.buildout.easy_install.clear_index_cache() # clean up |
1490 | + |
1491 | +Notice that the paths from the executable come after the ones for this |
1492 | +buildout. This is most evident in the change of order for the "other" egg. |
1493 | + |
1494 | +In fact, this ordering is not important in this example, because the |
1495 | +executable's paths all are individual packages; but if a path were a directory |
1496 | +that shared many packages, like a classic "site-packages" directory, its shared |
1497 | +packages would not mask those selected by the buildout. |
1498 | + |
1499 | Providing script arguments |
1500 | -------------------------- |
1501 | |
1502 | @@ -748,12 +911,13 @@ |
1503 | ... ['demo'], ws, sys.executable, bin, dict(demo='run'), |
1504 | ... arguments='1, 2') |
1505 | |
1506 | - >>> cat(bin, 'run') # doctest: +NORMALIZE_WHITESPACE |
1507 | + >>> cat(bin, 'run') # doctest: +NORMALIZE_WHITESPACE +ELLIPSIS |
1508 | #!/usr/local/bin/python2.4 |
1509 | import sys |
1510 | - sys.path[0:0] = [ |
1511 | + sys.path[:] = [ |
1512 | '/sample-install/demo-0.3-py2.4.egg', |
1513 | '/sample-install/demoneeded-1.1-py2.4.egg', |
1514 | + ... |
1515 | ] |
1516 | <BLANKLINE> |
1517 | import eggrecipedemo |
1518 | @@ -771,13 +935,14 @@ |
1519 | ... arguments='1, 2', |
1520 | ... initialization='import os\nos.chdir("foo")') |
1521 | |
1522 | - >>> cat(bin, 'run') # doctest: +NORMALIZE_WHITESPACE |
1523 | + >>> cat(bin, 'run') # doctest: +NORMALIZE_WHITESPACE +ELLIPSIS |
1524 | #!/usr/local/bin/python2.4 |
1525 | import sys |
1526 | - sys.path[0:0] = [ |
1527 | - '/sample-install/demo-0.3-py2.4.egg', |
1528 | - '/sample-install/demoneeded-1.1-py2.4.egg', |
1529 | - ] |
1530 | + sys.path[:] = [ |
1531 | + '/sample-install/demo-0.3-py2.4.egg', |
1532 | + '/sample-install/demoneeded-1.1-py2.4.egg', |
1533 | + ... |
1534 | + ] |
1535 | <BLANKLINE> |
1536 | import os |
1537 | os.chdir("foo") |
1538 | @@ -811,7 +976,7 @@ |
1539 | ... interpreter='py', |
1540 | ... relative_paths=bo) |
1541 | |
1542 | - >>> cat(bo, 'bin', 'run') |
1543 | + >>> cat(bo, 'bin', 'run') # doctest: +ELLIPSIS |
1544 | #!/usr/local/bin/python2.4 |
1545 | <BLANKLINE> |
1546 | import os |
1547 | @@ -821,12 +986,13 @@ |
1548 | base = os.path.dirname(base) |
1549 | <BLANKLINE> |
1550 | import sys |
1551 | - sys.path[0:0] = [ |
1552 | - join(base, 'eggs/demo-0.3-pyN.N.egg'), |
1553 | - join(base, 'eggs/demoneeded-1.1-pyN.N.egg'), |
1554 | - '/ba', |
1555 | - join(base, 'bar'), |
1556 | - ] |
1557 | + sys.path[:] = [ |
1558 | + join(base, 'eggs/demo-0.3-pyN.N.egg'), |
1559 | + join(base, 'eggs/demoneeded-1.1-pyN.N.egg'), |
1560 | + '/ba', |
1561 | + join(base, 'bar'), |
1562 | + ... |
1563 | + ] |
1564 | <BLANKLINE> |
1565 | import eggrecipedemo |
1566 | <BLANKLINE> |
1567 | @@ -843,8 +1009,10 @@ |
1568 | |
1569 | We specified an interpreter and its paths are adjusted too: |
1570 | |
1571 | - >>> cat(bo, 'bin', 'py') |
1572 | + >>> cat(bo, 'bin', 'py') # doctest: +ELLIPSIS |
1573 | #!/usr/local/bin/python2.4 |
1574 | + globs = globals().copy() # get a clean copy early |
1575 | + <BLANKLINE> |
1576 | <BLANKLINE> |
1577 | import os |
1578 | <BLANKLINE> |
1579 | @@ -854,32 +1022,59 @@ |
1580 | <BLANKLINE> |
1581 | import sys |
1582 | <BLANKLINE> |
1583 | - sys.path[0:0] = [ |
1584 | - join(base, 'eggs/demo-0.3-pyN.N.egg'), |
1585 | - join(base, 'eggs/demoneeded-1.1-pyN.N.egg'), |
1586 | - '/ba', |
1587 | - join(base, 'bar'), |
1588 | - ] |
1589 | - <BLANKLINE> |
1590 | - _interactive = True |
1591 | - if len(sys.argv) > 1: |
1592 | - import getopt |
1593 | - _options, _args = getopt.getopt(sys.argv[1:], 'ic:') |
1594 | + _set_path = _interactive = True |
1595 | + _force_interactive = False |
1596 | + <BLANKLINE> |
1597 | + _command = None |
1598 | + _args = sys.argv[1:] |
1599 | + <BLANKLINE> |
1600 | + while _args: |
1601 | + if _args[0].startswith('-'): |
1602 | + _arg = _args.pop(0) |
1603 | + for _ix, _opt in enumerate(_arg[1:]): |
1604 | + if _opt == 'i': |
1605 | + _force_interactive = True |
1606 | + elif _opt == 'c': |
1607 | + _interactive = False |
1608 | + _command = _args.pop(0) # Argument expected for the -c option |
1609 | + _args.insert(0, '-c') |
1610 | + break |
1611 | + elif _opt == 'S': |
1612 | + # We'll approximate this. It is mostly convenient for tests. |
1613 | + _set_path = False |
1614 | + elif _opt == 'V': |
1615 | + print 'Python ' + sys.version.split()[0] |
1616 | + _interactive = False |
1617 | + break |
1618 | + else: |
1619 | + continue |
1620 | + break |
1621 | + else: |
1622 | + break |
1623 | + <BLANKLINE> |
1624 | + if _set_path: |
1625 | + sys.path[:] = [ |
1626 | + join(base, 'eggs/demo-0.3-pyN.N.egg'), |
1627 | + join(base, 'eggs/demoneeded-1.1-pyN.N.egg'), |
1628 | + '/ba', |
1629 | + join(base, 'bar'), |
1630 | + ..., |
1631 | + ] |
1632 | + sys.path.insert(0, '.') |
1633 | + <BLANKLINE> |
1634 | + sys.argv[:] = _args |
1635 | + <BLANKLINE> |
1636 | + if _command: |
1637 | + exec _command |
1638 | + elif _args: |
1639 | _interactive = False |
1640 | - for (_opt, _val) in _options: |
1641 | - if _opt == '-i': |
1642 | - _interactive = True |
1643 | - elif _opt == '-c': |
1644 | - exec _val |
1645 | - <BLANKLINE> |
1646 | - if _args: |
1647 | - sys.argv[:] = _args |
1648 | - execfile(sys.argv[0]) |
1649 | - <BLANKLINE> |
1650 | - if _interactive: |
1651 | + globs['__file__'] = sys.argv[0] |
1652 | + execfile(sys.argv[0], globs) |
1653 | + <BLANKLINE> |
1654 | + if _interactive or _force_interactive: |
1655 | import code |
1656 | - code.interact(banner="", local=globals()) |
1657 | - |
1658 | + del globs['__file__'] |
1659 | + code.interact(banner="", local=globs) |
1660 | |
1661 | Handling custom build options for extensions provided in source distributions |
1662 | ----------------------------------------------------------------------------- |
1663 | |
1664 | === modified file 'src/zc/buildout/testing.py' |
1665 | --- src/zc/buildout/testing.py 2009-06-18 09:54:24 +0000 |
1666 | +++ src/zc/buildout/testing.py 2009-07-11 15:49:15 +0000 |
1667 | @@ -116,12 +116,19 @@ |
1668 | args = [zc.buildout.easy_install._safe_arg(arg) |
1669 | for arg in args] |
1670 | args.insert(0, '-q') |
1671 | - args.append(dict(os.environ, PYTHONPATH=setuptools_location)) |
1672 | + |
1673 | + env = dict(os.environ) |
1674 | + if executable == sys.executable: |
1675 | + env['PYTHONPATH'] = setuptools_location |
1676 | + # else pass an executable that has setuptools! See testselectingpython.py. |
1677 | + args.append(env) |
1678 | |
1679 | here = os.getcwd() |
1680 | try: |
1681 | os.chdir(d) |
1682 | - os.spawnle(os.P_WAIT, executable, zc.buildout.easy_install._safe_arg (executable), setup, *args) |
1683 | + os.spawnle(os.P_WAIT, executable, |
1684 | + zc.buildout.easy_install._safe_arg(executable), |
1685 | + setup, *args) |
1686 | if os.path.exists('build'): |
1687 | rmtree('build') |
1688 | finally: |
1689 | @@ -133,6 +140,11 @@ |
1690 | def bdist_egg(setup, executable, dest): |
1691 | _runsetup(setup, executable, 'bdist_egg', '-d', dest) |
1692 | |
1693 | +def sys_install(setup, dest): |
1694 | + _runsetup(setup, sys.executable, 'install', '--home', dest, |
1695 | + '--single-version-externally-managed', |
1696 | + '--record', os.path.join(dest, 'added')) |
1697 | + |
1698 | def find_python(version): |
1699 | e = os.environ.get('PYTHON%s' % version) |
1700 | if e is not None: |
1701 | @@ -272,7 +284,7 @@ |
1702 | |
1703 | |
1704 | # Create the develop-eggs dir, which didn't get created the usual |
1705 | - # way due to thr trick above: |
1706 | + # way due to the trick above: |
1707 | os.mkdir('develop-eggs') |
1708 | |
1709 | def start_server(path): |
1710 | |
1711 | === modified file 'src/zc/buildout/tests.py' |
1712 | --- src/zc/buildout/tests.py 2009-06-19 19:56:53 +0000 |
1713 | +++ src/zc/buildout/tests.py 2009-07-11 15:49:15 +0000 |
1714 | @@ -16,7 +16,7 @@ |
1715 | $Id$ |
1716 | """ |
1717 | |
1718 | -import os, re, shutil, sys, tempfile, unittest, zipfile |
1719 | +import os, re, shutil, sys, tempfile, textwrap, unittest, zipfile |
1720 | from zope.testing import doctest, renormalizing |
1721 | import pkg_resources |
1722 | import zc.buildout.testing, zc.buildout.easy_install |
1723 | @@ -1768,6 +1768,91 @@ |
1724 | 1 2 |
1725 | """ |
1726 | |
1727 | +def versions_section_ignored_for_dependency_in_favor_of_site_packages(): |
1728 | + r""" |
1729 | +This is a test for a bugfix. |
1730 | + |
1731 | +The error showed itself when at least two dependencies were in a shared |
1732 | +location like site-packages, and the first one met the "versions" setting. The |
1733 | +first dependency would be added, but subsequent dependencies from the same |
1734 | +location (e.g., site-packages) would use the version of the package found in |
1735 | +the shared location, ignoring the version setting. |
1736 | + |
1737 | +We begin with a Python that has demoneeded version 1.1 installed and a demo |
1738 | +version 0.3, all in a site-packages-like shared directory. We need to create |
1739 | +this. |
1740 | + |
1741 | + >>> executable_buildout = tmpdir('executable_buildout') |
1742 | + >>> old_wd = os.getcwd() |
1743 | + >>> os.chdir(executable_buildout) |
1744 | + >>> import textwrap |
1745 | + >>> write('buildout.cfg', textwrap.dedent( |
1746 | + ... ''' |
1747 | + ... [buildout] |
1748 | + ... parts = interpreter |
1749 | + ... |
1750 | + ... [interpreter] |
1751 | + ... recipe = zc.recipe.egg |
1752 | + ... scripts = py |
1753 | + ... interpreter = py |
1754 | + ... extra-paths = %(site-packages)s |
1755 | + ... include-site-packages = false |
1756 | + ... eggs = setuptools |
1757 | + ... ''') % {'site-packages': join(site_packages, 'lib', 'python')}) |
1758 | + >>> zc.buildout.buildout.Buildout( |
1759 | + ... 'buildout.cfg', |
1760 | + ... [('buildout', 'log-level', 'WARNING'), |
1761 | + ... # trick bootstrap into putting the buildout develop egg |
1762 | + ... # in the eggs dir. |
1763 | + ... ('buildout', 'develop-eggs-directory', 'eggs'), |
1764 | + ... ] |
1765 | + ... ).bootstrap([]) |
1766 | + >>> os.mkdir('develop-eggs') |
1767 | + >>> zc.buildout.testing.install_develop( |
1768 | + ... 'zc.recipe.egg', |
1769 | + ... os.path.join(executable_buildout, 'develop-eggs')) |
1770 | + >>> print system( |
1771 | + ... os.path.join(executable_buildout, 'bin', 'buildout')) |
1772 | + Installing interpreter. |
1773 | + Generated interpreter '/executable_buildout/bin/py'. |
1774 | + <BLANKLINE> |
1775 | + >>> os.chdir(old_wd) |
1776 | + >>> primed_executable = os.path.join(executable_buildout, 'bin', 'py') |
1777 | + |
1778 | +``eggrecipedemo.main()`` shows the number after the dot (that is, ``X`` in |
1779 | +``1.X``), for the demo package and the demoneeded package, so this demonstrates |
1780 | +that our Python does in fact have demo version 0.3 and demoneeded version 1.1. |
1781 | + |
1782 | + >>> print system(primed_executable+" -c "+ |
1783 | + ... "'import eggrecipedemo; eggrecipedemo.main()'") |
1784 | + 3 1 |
1785 | + <BLANKLINE> |
1786 | + |
1787 | +Now we will install bigdemo, specifying different versions of demo |
1788 | +and demoneeded in a versions section. Before the bugfix, the demo version |
1789 | +would be honored, but not the demoneeded. |
1790 | + |
1791 | +Now here's a setup that would expose the bug, using the |
1792 | +zc.buildout.easy_install API. |
1793 | + |
1794 | + >>> example_dest = tmpdir('example_dest') |
1795 | + >>> workingset = zc.buildout.easy_install.install( |
1796 | + ... ['bigdemo'], example_dest, links=[sample_eggs], |
1797 | + ... executable=primed_executable, |
1798 | + ... index=None, include_site_packages=True, |
1799 | + ... versions={'demoneeded': '1.2c1', 'demo': '0.3'}) |
1800 | + >>> for dist in workingset: |
1801 | + ... print dist |
1802 | + bigdemo 0.1 |
1803 | + demo 0.3 |
1804 | + demoneeded 1.2c1 |
1805 | + |
1806 | +Before the bugfix, the demoneeded distribution was not included in the working |
1807 | +set, and the demoneeded in site-packages (of the wrong number) would have been |
1808 | +used. |
1809 | + |
1810 | + """ |
1811 | + |
1812 | if sys.version_info > (2, 4): |
1813 | def test_exit_codes(): |
1814 | """ |
1815 | @@ -2156,7 +2241,7 @@ |
1816 | """ |
1817 | This test tests several permutations: |
1818 | |
1819 | -Using different version numbers to work around zip impporter cache problems. :( |
1820 | +Using different version numbers to work around zip importer cache problems. :( |
1821 | |
1822 | - With prefer final: |
1823 | |
1824 | @@ -2338,6 +2423,177 @@ |
1825 | |
1826 | """ |
1827 | |
1828 | +def isolated_include_site_packages(): |
1829 | + """ |
1830 | + |
1831 | +This is an isolated test of the include_site_packages functionality, passing |
1832 | +the argument directly to install, overriding a default. |
1833 | + |
1834 | +Our "primed_executable" has the "demoneeded," "other," and "setuptools" |
1835 | +packages available. We'll simply be asking for "other" here. |
1836 | + |
1837 | + >>> primed_executable = get_executable_with_site_packages() |
1838 | + >>> zc.buildout.easy_install.include_site_packages(False) |
1839 | + True |
1840 | + |
1841 | + >>> example_dest = tmpdir('site-packages-example-install') |
1842 | + >>> workingset = zc.buildout.easy_install.install( |
1843 | + ... ['other'], example_dest, links=[], executable=primed_executable, |
1844 | + ... index=None, include_site_packages=True) |
1845 | + >>> [dist.project_name for dist in workingset] |
1846 | + ['other'] |
1847 | + |
1848 | +That worked fine. Let's try again with site packages not allowed (and |
1849 | +reversing the default). |
1850 | + |
1851 | + >>> zc.buildout.easy_install.include_site_packages(True) |
1852 | + False |
1853 | + |
1854 | + >>> zc.buildout.easy_install.clear_index_cache() |
1855 | + >>> rmdir(example_dest) |
1856 | + >>> example_dest = tmpdir('site-packages-example-install') |
1857 | + >>> workingset = zc.buildout.easy_install.install( |
1858 | + ... ['other'], example_dest, links=[], executable=primed_executable, |
1859 | + ... index=None, include_site_packages=False) |
1860 | + Traceback (most recent call last): |
1861 | + ... |
1862 | + MissingDistribution: Couldn't find a distribution for 'other'. |
1863 | + |
1864 | +That's a failure, as expected. |
1865 | + |
1866 | +Now we explore an important edge case. |
1867 | + |
1868 | +Some system Pythons include setuptools (and other Python packages) in their |
1869 | +site-packages (or equivalent) using a .egg-info directory. The pkg_resources |
1870 | +module (from setuptools) considers a package installed using .egg-info to be a |
1871 | +develop egg. |
1872 | + |
1873 | +zc.buildout.buildout.Buildout.bootstrap will make setuptools and zc.buildout |
1874 | +available to the buildout via the eggs directory, for normal eggs; or the |
1875 | +develop-eggs directory, for develop-eggs. |
1876 | + |
1877 | +If setuptools or zc.buildout is found in site-packages and considered by |
1878 | +pkg_resources to be a develop egg, then the bootstrap code will use a .egg-link |
1879 | +in the local develop-eggs, pointing to site-packages, in its entirety. Because |
1880 | +develop-eggs must always be available for searching for distributions, this |
1881 | +indirectly brings site-packages back into the search path for distributions. |
1882 | + |
1883 | +Because of this, we have to take special care that we still exclude |
1884 | +site-packages even in this case. See the comments about site packages in the |
1885 | +Installer._satisfied and Installer._obtain methods for the implementation |
1886 | +(as of this writing). |
1887 | + |
1888 | +In this demonstration, we insert a link to the "other" distribution in our |
1889 | +develop-eggs, which would bring the package back in, except for the special |
1890 | +care we have taken to exclude it. |
1891 | + |
1892 | + >>> zc.buildout.easy_install.clear_index_cache() |
1893 | + >>> rmdir(example_dest) |
1894 | + >>> example_dest = tmpdir('site-packages-example-install') |
1895 | + >>> mkdir(example_dest, 'develop-eggs') |
1896 | + >>> stdlib, site_packages = ( |
1897 | + ... zc.buildout.easy_install._get_system_packages(primed_executable)) |
1898 | + >>> path_to_other = [p for p in site_packages if 'other' in p][0] |
1899 | + >>> write(example_dest, 'develop-eggs', 'other.egg-link', path_to_other) |
1900 | + >>> workingset = zc.buildout.easy_install.install( |
1901 | + ... ['other'], example_dest, links=[], |
1902 | + ... path=[join(example_dest, 'develop-eggs')], |
1903 | + ... executable=primed_executable, |
1904 | + ... index=None, include_site_packages=False) |
1905 | + Traceback (most recent call last): |
1906 | + ... |
1907 | + MissingDistribution: Couldn't find a distribution for 'other'. |
1908 | + |
1909 | +The MissingDistribution error shows that buildout correctly excluded the |
1910 | +"site-packages" source even though it was indirectly included in the path |
1911 | +via a .egg-link file. |
1912 | + |
1913 | + """ |
1914 | + |
1915 | +def buildout_include_site_packages_option(): |
1916 | + """ |
1917 | +The include-site-packages buildout option can be used to override the default |
1918 | +behavior of using site packages. |
1919 | + |
1920 | +The default is include-site-packages = true. As a demonstration, notice we do |
1921 | +not set find-links, but the eggs are still found because they are in the |
1922 | +executable's path. |
1923 | + |
1924 | +Our "primed_executable" has the "demoneeded," "other," and "setuptools" |
1925 | +packages available. We'll simply be asking for "other" here. |
1926 | + |
1927 | + >>> primed_executable = get_executable_with_site_packages() |
1928 | + >>> write('buildout.cfg', |
1929 | + ... ''' |
1930 | + ... [buildout] |
1931 | + ... parts = eggs |
1932 | + ... find-links = |
1933 | + ... |
1934 | + ... [primed_python] |
1935 | + ... executable = %(primed_executable)s |
1936 | + ... |
1937 | + ... [eggs] |
1938 | + ... recipe = zc.recipe.egg:eggs |
1939 | + ... python = primed_python |
1940 | + ... eggs = other |
1941 | + ... ''' % globals()) |
1942 | + |
1943 | + >>> print system(primed_executable+" "+buildout) |
1944 | + Installing eggs. |
1945 | + <BLANKLINE> |
1946 | + |
1947 | +However, if we set include-site-packages to false, we get an error, because |
1948 | +the packages are not available in any links, and they are not allowed to be |
1949 | +obtained from the executable's site packages. |
1950 | + |
1951 | + >>> zc.buildout.easy_install.clear_index_cache() |
1952 | + >>> write('buildout.cfg', |
1953 | + ... ''' |
1954 | + ... [buildout] |
1955 | + ... parts = eggs |
1956 | + ... find-links = |
1957 | + ... include-site-packages = false |
1958 | + ... |
1959 | + ... [primed_python] |
1960 | + ... executable = %(primed_executable)s |
1961 | + ... |
1962 | + ... [eggs] |
1963 | + ... recipe = zc.recipe.egg:eggs |
1964 | + ... eggs = other |
1965 | + ... ''' % globals()) |
1966 | + >>> print system(primed_executable+" "+buildout) |
1967 | + Uninstalling eggs. |
1968 | + Installing eggs. |
1969 | + Couldn't find index page for 'other' (maybe misspelled?) |
1970 | + Getting distribution for 'other'. |
1971 | + While: |
1972 | + Installing eggs. |
1973 | + Getting distribution for 'other'. |
1974 | + Error: Couldn't find a distribution for 'other'. |
1975 | + <BLANKLINE> |
1976 | + |
1977 | +We get an error if we specify anything but true or false: |
1978 | + |
1979 | + >>> write('buildout.cfg', |
1980 | + ... ''' |
1981 | + ... [buildout] |
1982 | + ... parts = eggs |
1983 | + ... find-links = %(link_server)s |
1984 | + ... include-site-packages = no |
1985 | + ... |
1986 | + ... [eggs] |
1987 | + ... recipe = zc.recipe.egg:eggs |
1988 | + ... eggs = other |
1989 | + ... ''' % globals()) |
1990 | + |
1991 | + >>> print system(primed_executable+" "+buildout) |
1992 | + While: |
1993 | + Initializing. |
1994 | + Error: Invalid value for include-site-packages option: no |
1995 | + <BLANKLINE> |
1996 | + |
1997 | + """ |
1998 | + |
1999 | def develop_with_modules(): |
2000 | """ |
2001 | Distribution setup scripts can import modules in the distribution directory: |
2002 | @@ -2533,6 +2789,8 @@ |
2003 | def create_sample_eggs(test, executable=sys.executable): |
2004 | write = test.globs['write'] |
2005 | dest = test.globs['sample_eggs'] |
2006 | + site_packages = test.globs['tmpdir']('site_packages') |
2007 | + test.globs['site_packages'] = site_packages |
2008 | tmp = tempfile.mkdtemp() |
2009 | try: |
2010 | write(tmp, 'README.txt', '') |
2011 | @@ -2549,6 +2807,8 @@ |
2012 | % (i, c1) |
2013 | ) |
2014 | zc.buildout.testing.sdist(tmp, dest) |
2015 | + if i==1: |
2016 | + zc.buildout.testing.sys_install(tmp, site_packages) |
2017 | |
2018 | write( |
2019 | tmp, 'setup.py', |
2020 | @@ -2578,6 +2838,8 @@ |
2021 | " zip_safe=True, version='0.%s%s')\n" % (i, c1) |
2022 | ) |
2023 | zc.buildout.testing.bdist_egg(tmp, executable, dest) |
2024 | + if i==3: |
2025 | + zc.buildout.testing.sys_install(tmp, site_packages) |
2026 | |
2027 | write(tmp, 'eggrecipebigdemo.py', 'import eggrecipedemo') |
2028 | write( |
2029 | @@ -2652,6 +2914,49 @@ |
2030 | test.globs['sample_eggs']) |
2031 | test.globs['update_extdemo'] = lambda : add_source_dist(test, 1.5) |
2032 | zc.buildout.testing.install_develop('zc.recipe.egg', test) |
2033 | + # most tests don't need this set up, and it takes some time, so we just |
2034 | + # make it available as a convenience. |
2035 | + def get_executable_with_site_packages(requirements=None): |
2036 | + executable_buildout = test.globs['tmpdir']('executable') |
2037 | + old_wd = os.getcwd() |
2038 | + os.chdir(executable_buildout) |
2039 | + if requirements is None: |
2040 | + requirements = ['demoneeded', 'setuptools', 'other'] |
2041 | + elif len([req for req in requirements |
2042 | + if req.startswith('setuptools')]) == 0: |
2043 | + requirements.append('setuptools') # you always need that. |
2044 | + requirements = '\n '.join(requirements) |
2045 | + test.globs['write']('buildout.cfg', textwrap.dedent( |
2046 | + ''' |
2047 | + [buildout] |
2048 | + parts = interpreter |
2049 | + find-links = %(link_server)s |
2050 | + prefer-final = true |
2051 | + |
2052 | + [interpreter] |
2053 | + recipe = zc.recipe.egg |
2054 | + interpreter = py |
2055 | + eggs = %(requirements)s |
2056 | + ''') % {'requirements': requirements, |
2057 | + 'link_server': test.globs['link_server']}) |
2058 | + zc.buildout.buildout.Buildout( |
2059 | + 'buildout.cfg', |
2060 | + [('buildout', 'log-level', 'WARNING'), |
2061 | + # trick bootstrap into putting the buildout develop egg |
2062 | + # in the eggs dir. |
2063 | + ('buildout', 'develop-eggs-directory', 'eggs'), |
2064 | + ] |
2065 | + ).bootstrap([]) |
2066 | + os.mkdir('develop-eggs') |
2067 | + zc.buildout.testing.install_develop( |
2068 | + 'zc.recipe.egg', |
2069 | + os.path.join(executable_buildout, 'develop-eggs')) |
2070 | + test.globs['system']( |
2071 | + os.path.join(executable_buildout, 'bin', 'buildout')) |
2072 | + os.chdir(old_wd) |
2073 | + return os.path.join(executable_buildout, 'bin', 'py') |
2074 | + test.globs['get_executable_with_site_packages'] = ( |
2075 | + get_executable_with_site_packages) |
2076 | |
2077 | egg_parse = re.compile('([0-9a-zA-Z_.]+)-([0-9a-zA-Z_.]+)-py(\d[.]\d).egg$' |
2078 | ).match |
2079 | |
2080 | === modified file 'src/zc/buildout/testselectingpython.py' |
2081 | --- src/zc/buildout/testselectingpython.py 2008-01-14 00:46:41 +0000 |
2082 | +++ src/zc/buildout/testselectingpython.py 2009-07-10 00:02:25 +0000 |
2083 | @@ -11,8 +11,9 @@ |
2084 | # FOR A PARTICULAR PURPOSE. |
2085 | # |
2086 | ############################################################################## |
2087 | -import os, re, sys, unittest |
2088 | +import os, re, subprocess, sys, textwrap, unittest |
2089 | from zope.testing import doctest, renormalizing |
2090 | +import zc.buildout.easy_install |
2091 | import zc.buildout.tests |
2092 | import zc.buildout.testing |
2093 | |
2094 | @@ -25,13 +26,14 @@ |
2095 | test_selecting_python_via_easy_install= |
2096 | """\ |
2097 | |
2098 | -We can specify an specific Python executable. |
2099 | +We can specify a specific Python executable. |
2100 | |
2101 | >>> dest = tmpdir('sample-install') |
2102 | >>> ws = zc.buildout.easy_install.install( |
2103 | ... ['demo'], dest, links=[link_server], |
2104 | ... index='http://www.python.org/pypi/', |
2105 | - ... always_unzip=True, executable= other_executable) |
2106 | + ... always_unzip=True, executable= other_executable, |
2107 | + ... include_site_packages=False) |
2108 | |
2109 | >>> ls(dest) |
2110 | d demo-0.3-py%(other_version)s.egg |
2111 | @@ -43,6 +45,31 @@ |
2112 | |
2113 | def multi_python(test): |
2114 | other_executable = zc.buildout.testing.find_python(other_version) |
2115 | + command = textwrap.dedent('''\ |
2116 | + try: |
2117 | + import setuptools |
2118 | + except ImportError: |
2119 | + import sys |
2120 | + sys.exit(1) |
2121 | + ''') |
2122 | + if subprocess.call([other_executable, '-c', command], |
2123 | + env=os.environ): |
2124 | + # the other executable does not have setuptools. Get setuptools. |
2125 | + # We will do this using the same tools we are testing, for better or |
2126 | + # worse. Alternatively, we could try using bootstrap. |
2127 | + executable_dir = test.globs['tmpdir']('executable_dir') |
2128 | + ws = zc.buildout.easy_install.install( |
2129 | + ['setuptools'], executable_dir, |
2130 | + index='http://www.python.org/pypi/', |
2131 | + always_unzip=True, executable=other_executable) |
2132 | + zc.buildout.easy_install.scripts( |
2133 | + ['setuptools'], ws, other_executable, executable_dir, |
2134 | + interpreter='py') |
2135 | + original_executable = other_executable |
2136 | + other_executable = os.path.join(executable_dir, 'py') |
2137 | + assert not subprocess.call( |
2138 | + [other_executable, '-c', command], env=os.environ), ( |
2139 | + 'test set up failed') |
2140 | sample_eggs = test.globs['tmpdir']('sample_eggs') |
2141 | os.mkdir(os.path.join(sample_eggs, 'index')) |
2142 | test.globs['sample_eggs'] = sample_eggs |
2143 | |
2144 | === modified file 'src/zc/buildout/unzip.txt' |
2145 | --- src/zc/buildout/unzip.txt 2008-07-18 19:51:43 +0000 |
2146 | +++ src/zc/buildout/unzip.txt 2009-07-08 13:10:16 +0000 |
2147 | @@ -21,9 +21,8 @@ |
2148 | d setuptools-0.6c8-py2.4.egg |
2149 | - zc.buildout.egg-link |
2150 | |
2151 | -This follows the |
2152 | -policy followed by setuptools itself. Experience shows this policy |
2153 | -to to be inconvenient. Zipped eggs make debugging more difficult and |
2154 | +This follows the policy followed by setuptools itself. Experience shows this |
2155 | +policy to to be inconvenient. Zipped eggs make debugging more difficult and |
2156 | often import more slowly. |
2157 | |
2158 | You can include an unzip option in the buildout section to change the |
2159 | |
2160 | === modified file 'src/zc/buildout/update.txt' |
2161 | --- src/zc/buildout/update.txt 2008-07-15 22:01:29 +0000 |
2162 | +++ src/zc/buildout/update.txt 2009-07-07 14:40:47 +0000 |
2163 | @@ -80,14 +80,15 @@ |
2164 | |
2165 | Our buildout script has been updated to use the new eggs: |
2166 | |
2167 | - >>> cat(sample_buildout, 'bin', 'buildout') |
2168 | + >>> cat(sample_buildout, 'bin', 'buildout') # doctest: +ELLIPSIS |
2169 | #!/usr/local/bin/python2.4 |
2170 | <BLANKLINE> |
2171 | import sys |
2172 | - sys.path[0:0] = [ |
2173 | - '/sample-buildout/eggs/zc.buildout-99.99-py2.4.egg', |
2174 | - '/sample-buildout/eggs/setuptools-99.99-py2.4.egg', |
2175 | - ] |
2176 | + sys.path[:] = [ |
2177 | + '/sample-buildout/eggs/zc.buildout-99.99-py2.4.egg', |
2178 | + '/sample-buildout/eggs/setuptools-99.99-py2.4.egg', |
2179 | + ... |
2180 | + ] |
2181 | <BLANKLINE> |
2182 | import zc.buildout.buildout |
2183 | <BLANKLINE> |
2184 | |
2185 | === modified file 'zc.recipe.egg_/setup.py' |
2186 | --- zc.recipe.egg_/setup.py 2009-03-18 18:57:12 +0000 |
2187 | +++ zc.recipe.egg_/setup.py 2009-07-09 18:17:00 +0000 |
2188 | @@ -16,7 +16,7 @@ |
2189 | $Id$ |
2190 | """ |
2191 | |
2192 | -version = '0' |
2193 | +version = '1.3.0dev' |
2194 | |
2195 | import os |
2196 | from setuptools import setup, find_packages |
2197 | @@ -66,7 +66,7 @@ |
2198 | package_dir = {'':'src'}, |
2199 | namespace_packages = ['zc', 'zc.recipe'], |
2200 | install_requires = [ |
2201 | - 'zc.buildout >=1.2.0', |
2202 | + 'zc.buildout >=1.4.0dev', |
2203 | 'setuptools'], |
2204 | tests_require = ['zope.testing'], |
2205 | test_suite = name+'.tests.test_suite', |
2206 | |
2207 | === modified file 'zc.recipe.egg_/src/zc/recipe/egg/README.txt' |
2208 | --- zc.recipe.egg_/src/zc/recipe/egg/README.txt 2009-06-22 16:41:40 +0000 |
2209 | +++ zc.recipe.egg_/src/zc/recipe/egg/README.txt 2009-07-07 14:40:47 +0000 |
2210 | @@ -372,16 +372,18 @@ |
2211 | |
2212 | Let's look at the script that was generated: |
2213 | |
2214 | - >>> cat(sample_buildout, 'bin', 'foo') # doctest: +NORMALIZE_WHITESPACE |
2215 | + >>> cat(sample_buildout, 'bin', 'foo') |
2216 | + ... # doctest: +NORMALIZE_WHITESPACE +ELLIPSIS |
2217 | #!/usr/local/bin/python2.4 |
2218 | <BLANKLINE> |
2219 | import sys |
2220 | - sys.path[0:0] = [ |
2221 | - '/sample-buildout/eggs/demo-0.4c1-py2.4.egg', |
2222 | - '/sample-buildout/eggs/demoneeded-1.2c1-py2.4.egg', |
2223 | - '/foo/bar', |
2224 | - '/sample-buildout/spam', |
2225 | - ] |
2226 | + sys.path[:] = [ |
2227 | + '/sample-buildout/eggs/demo-0.4c1-py2.4.egg', |
2228 | + '/sample-buildout/eggs/demoneeded-1.2c1-py2.4.egg', |
2229 | + '/foo/bar', |
2230 | + '/sample-buildout/spam', |
2231 | + ... |
2232 | + ] |
2233 | <BLANKLINE> |
2234 | import eggrecipedemo |
2235 | <BLANKLINE> |
2236 | @@ -419,7 +421,8 @@ |
2237 | |
2238 | Let's look at the script that was generated: |
2239 | |
2240 | - >>> cat(sample_buildout, 'bin', 'foo') # doctest: +NORMALIZE_WHITESPACE |
2241 | + >>> cat(sample_buildout, 'bin', 'foo') |
2242 | + ... # doctest: +NORMALIZE_WHITESPACE +ELLIPSIS |
2243 | #!/usr/local/bin/python2.4 |
2244 | <BLANKLINE> |
2245 | import os |
2246 | @@ -429,12 +432,13 @@ |
2247 | base = os.path.dirname(base) |
2248 | <BLANKLINE> |
2249 | import sys |
2250 | - sys.path[0:0] = [ |
2251 | - join(base, 'eggs/demo-0.4c1-pyN.N.egg'), |
2252 | - join(base, 'eggs/demoneeded-1.2c1-pyN.N.egg'), |
2253 | - '/foo/bar', |
2254 | - join(base, 'spam'), |
2255 | - ] |
2256 | + sys.path[:] = [ |
2257 | + join(base, 'eggs/demo-0.4c1-pyN.N.egg'), |
2258 | + join(base, 'eggs/demoneeded-1.2c1-pyN.N.egg'), |
2259 | + '/foo/bar', |
2260 | + join(base, 'spam'), |
2261 | + ... |
2262 | + ] |
2263 | <BLANKLINE> |
2264 | import eggrecipedemo |
2265 | <BLANKLINE> |
2266 | @@ -466,7 +470,8 @@ |
2267 | Installing demo. |
2268 | Generated script '/sample-buildout/bin/foo'. |
2269 | |
2270 | - >>> cat(sample_buildout, 'bin', 'foo') # doctest: +NORMALIZE_WHITESPACE |
2271 | + >>> cat(sample_buildout, 'bin', 'foo') |
2272 | + ... # doctest: +NORMALIZE_WHITESPACE +ELLIPSIS |
2273 | #!/usr/local/bin/python2.4 |
2274 | <BLANKLINE> |
2275 | import os |
2276 | @@ -476,12 +481,13 @@ |
2277 | base = os.path.dirname(base) |
2278 | <BLANKLINE> |
2279 | import sys |
2280 | - sys.path[0:0] = [ |
2281 | - join(base, 'eggs/demo-0.4c1-pyN.N.egg'), |
2282 | - join(base, 'eggs/demoneeded-1.2c1-pyN.N.egg'), |
2283 | - '/foo/bar', |
2284 | - join(base, 'spam'), |
2285 | - ] |
2286 | + sys.path[:] = [ |
2287 | + join(base, 'eggs/demo-0.4c1-pyN.N.egg'), |
2288 | + join(base, 'eggs/demoneeded-1.2c1-pyN.N.egg'), |
2289 | + '/foo/bar', |
2290 | + join(base, 'spam'), |
2291 | + ... |
2292 | + ] |
2293 | <BLANKLINE> |
2294 | import eggrecipedemo |
2295 | <BLANKLINE> |
2296 | @@ -519,16 +525,18 @@ |
2297 | Installing demo. |
2298 | Generated script '/sample-buildout/bin/foo'. |
2299 | |
2300 | - >>> cat(sample_buildout, 'bin', 'foo') # doctest: +NORMALIZE_WHITESPACE |
2301 | + >>> cat(sample_buildout, 'bin', 'foo') |
2302 | + ... # doctest: +NORMALIZE_WHITESPACE +ELLIPSIS |
2303 | #!/usr/local/bin/python2.4 |
2304 | <BLANKLINE> |
2305 | import sys |
2306 | - sys.path[0:0] = [ |
2307 | - '/sample-buildout/eggs/demo-0.4c1-py2.4.egg', |
2308 | - '/sample-buildout/eggs/demoneeded-1.2c1-py2.4.egg', |
2309 | - '/foo/bar', |
2310 | - '/sample-buildout/spam', |
2311 | - ] |
2312 | + sys.path[:] = [ |
2313 | + '/sample-buildout/eggs/demo-0.4c1-py2.4.egg', |
2314 | + '/sample-buildout/eggs/demoneeded-1.2c1-py2.4.egg', |
2315 | + '/foo/bar', |
2316 | + '/sample-buildout/spam', |
2317 | + ... |
2318 | + ] |
2319 | <BLANKLINE> |
2320 | a = (1, 2 |
2321 | 3, 4) |
2322 | @@ -577,16 +585,17 @@ |
2323 | - demo |
2324 | - other |
2325 | |
2326 | - >>> cat(sample_buildout, 'bin', 'other') |
2327 | + >>> cat(sample_buildout, 'bin', 'other') # doctest: +ELLIPSIS |
2328 | #!/usr/local/bin/python2.4 |
2329 | <BLANKLINE> |
2330 | import sys |
2331 | - sys.path[0:0] = [ |
2332 | - '/sample-buildout/eggs/demo-0.4c1-py2.4.egg', |
2333 | - '/sample-buildout/eggs/demoneeded-1.2c1-py2.4.egg', |
2334 | - '/foo/bar', |
2335 | - '/sample-buildout/spam', |
2336 | - ] |
2337 | + sys.path[:] = [ |
2338 | + '/sample-buildout/eggs/demo-0.4c1-py2.4.egg', |
2339 | + '/sample-buildout/eggs/demoneeded-1.2c1-py2.4.egg', |
2340 | + '/foo/bar', |
2341 | + '/sample-buildout/spam', |
2342 | + ... |
2343 | + ] |
2344 | <BLANKLINE> |
2345 | import foo.bar |
2346 | <BLANKLINE> |
2347 | |
2348 | === modified file 'zc.recipe.egg_/src/zc/recipe/egg/egg.py' |
2349 | --- zc.recipe.egg_/src/zc/recipe/egg/egg.py 2009-03-17 12:09:25 +0000 |
2350 | +++ zc.recipe.egg_/src/zc/recipe/egg/egg.py 2009-07-06 23:14:39 +0000 |
2351 | @@ -54,6 +54,13 @@ |
2352 | |
2353 | python = options.get('python', buildout['buildout']['python']) |
2354 | options['executable'] = buildout[python]['executable'] |
2355 | + include_site_packages = self.options.get( |
2356 | + 'include-site-packages', |
2357 | + self.buildout['buildout'].get('include-site-packages', 'true')) |
2358 | + if include_site_packages not in ('true', 'false'): |
2359 | + self._error('Invalid value for include-site-packages option: %s', |
2360 | + include_site_packages) |
2361 | + self.include_site_packages = (include_site_packages=='true') |
2362 | |
2363 | def working_set(self, extra=()): |
2364 | """Separate method to just get the working set |
2365 | @@ -72,7 +79,8 @@ |
2366 | if self.buildout['buildout'].get('offline') == 'true': |
2367 | ws = zc.buildout.easy_install.working_set( |
2368 | distributions, options['executable'], |
2369 | - [options['develop-eggs-directory'], options['eggs-directory']] |
2370 | + [options['develop-eggs-directory'], options['eggs-directory']], |
2371 | + include_site_packages=self.include_site_packages |
2372 | ) |
2373 | else: |
2374 | kw = {} |
2375 | @@ -81,12 +89,13 @@ |
2376 | |
2377 | ws = zc.buildout.easy_install.install( |
2378 | distributions, options['eggs-directory'], |
2379 | - links = self.links, |
2380 | - index = self.index, |
2381 | - executable = options['executable'], |
2382 | + links=self.links, |
2383 | + index=self.index, |
2384 | + executable=options['executable'], |
2385 | path=[options['develop-eggs-directory']], |
2386 | newest=self.buildout['buildout'].get('newest') == 'true', |
2387 | allow_hosts=self.allow_hosts, |
2388 | + include_site_packages=self.include_site_packages, |
2389 | **kw) |
2390 | |
2391 | return orig_distributions, ws |
2392 | @@ -166,7 +175,8 @@ |
2393 | interpreter=options.get('interpreter'), |
2394 | initialization=options.get('initialization', ''), |
2395 | arguments=options.get('arguments', ''), |
2396 | - relative_paths=self._relative_paths, |
2397 | + include_site_packages=self.include_site_packages, |
2398 | + relative_paths=self._relative_paths |
2399 | ) |
2400 | |
2401 | return () |
I have made a number of changes to zc.buildout in the gary-support- system- python branch in zope.org's svn repository. They all support Launchpad or Landscape's use of Buildout with a system Python, directly or indirectly.
The following is a list of changes taken from my CHANGES.txt additions:
- Support and bugfixes for using a system Python with buildout.
In all of these descriptions, "site-packages" is an imprecise term for a
precise definition: the packages that are added by the Python's site.py.
Practically, this is the difference of the set of paths normally used by
Python minus those used when Python is started with the -S flag.
* A new boolean option, 'include- site-packages' , includes or excludes site
packages from finding requirements, and from generated scripts.
zc.buildout's own buildout.cfg dogfoods this option.
* Script generation pushes dependency paths that are in site-packages to
the end of the dependency paths in sys.path (but, as before, these are
still before extra paths, the standard library, and the rest of the
site-package paths).
* Fix an error when at least two dependencies were in a shared location like
site-packages, and the first one met the "versions" setting. The first
dependency would be added, but subsequent dependencies from the same
location (e.g., site-packages) would use the version of the package found
in the shared location, ignoring the version setting.
- The generated interpreter scripts now have a few more similarities to a
real Python interpreter.
* __file__ is set correctly for executed files.
* -c incorporates all subsequent arguments as part of the command.
* -V returns the version.
* -S causes the script to not modify the standard path (for tests)
- Improve bootstrap.
* New options let you specify where to find ez_setup.py and where to find
a download cache. These options can keep bootstrap from going over the
network.
* Another new option lets you specify where to put generated eggs.
* The buildout script generated by bootstrap honors more of the settings
in the designated configuration file (e.g., buildout.cfg).
I failed to implement one feature I had wanted: a way to cherrypick parts of a system Python's site-packages. I proposed an approach, but it ugly, fragile, and risky; and Jim proposed an approach, but it does not work for a modern Ubuntu.
Review requests for small changes to zc.recipe. testrunner and z3c.recipe. filetemplate, based on some of these changes, are also forthcoming.