1 |
On Thu, 2012-10-18 at 02:15 -0700, Brian Harring wrote: |
2 |
> If folks haven't looked at python_generate_wrapper_scripts in |
3 |
> python.eclass, I'd suggest doing so. For examples of it's usage, grep |
4 |
> for 'python_generate_wrapper_scripts' in /usr/bin/; any place you see |
5 |
> it, look for <that-script-name>-${PYTHON_TARGETS} (for example, |
6 |
> /usr/bin/sphinx-build{,-2.7,-3.2}. |
7 |
> |
8 |
> Each usage there is a separate custom script for that specific binary; |
9 |
> if there is a bug in the script, well, we're screwed- requires |
10 |
> re-merging the package. |
11 |
> |
12 |
> This setup, at least on my hardware, is .04s added to every |
13 |
> invocation; this is ignoring the inode cost for each, and the issue if |
14 |
> a bug ever appears in the script generation code (in which case we're |
15 |
> screwed- would require re-merging the package). |
16 |
> |
17 |
> In parallel, we've got python-wrapper (ls /usr/bin/python -l); this is |
18 |
> provided by eselect-python and basically discern what the active |
19 |
> python version is, and use that in the absense of any directives. |
20 |
> This is implemented in C, and is reasonably sane; the overhead for |
21 |
> that is basically non-existant. |
22 |
> |
23 |
> Roughly, I'm proposing we do away with python eclass's |
24 |
> generate_python_wrapper_scripts generation of a script, instead having |
25 |
> that just symlink to a binary provided by eselect-python that handles |
26 |
> this. This centralizes the implementation (fix in one spot), and |
27 |
> would allow a c version to be used- basically eliminating the |
28 |
> overhead. |
29 |
> |
30 |
> |
31 |
> There's a trick to this; currently, those generated scripts hardcode |
32 |
> the allowed/known python versions for that package. We obviously have |
33 |
> to preserve that; I propose we shove it into the symlink path. |
34 |
> |
35 |
> Basically, we add a /usr/libexec/python directory; within it, we have |
36 |
> a wrapper binary (explained below), and a set of symlinks pointing at |
37 |
> the root of that directory. To cover our current python versions, the |
38 |
> following would suffice: |
39 |
> |
40 |
> for x in {2.{4,5,6,7},3.{0,1,2,3,4}}-cpy 2.5-jython 2.7-pypy-1.{7,8} |
41 |
> \2.7-pypy-1.9; do |
42 |
> ln -s ./ /usr/libexec/python/$x |
43 |
> done |
44 |
> |
45 |
> While that seems insane, there is a reason; via that, we can encode |
46 |
> the allowed versions into the symlink. Using pkgcore's pquery for |
47 |
> example (which should support cpy: 2.5, 2.6, 2.7, 3.1, 3.2, 3.3) |
48 |
> instead of a wrapper script at /usr/bin/pquery, we'd have thus: |
49 |
> |
50 |
> targets=( 2.{5,6,7}-cpy 3.{1,2,3}-cpy ) |
51 |
> targets=$(IFS=/;echo -n "${targets[*]}") |
52 |
> # This results in |
53 |
> # targets=2.5-cpy/2.6-cpy/2.7-cpy/3.1-cpy/3.2-cpy/3.3-cpy |
54 |
> ln -s "/usr/libexec/python/${targets}/wrapper" \ |
55 |
> /usr/bin/pquery |
56 |
> |
57 |
> /usr/libexec/python/wrapper upon invocation, takes a look at argv[0]; |
58 |
> sees how it was invoked basically. This will be the /usr/bin/whatever |
59 |
> pathway. It reads the symlink, in the process getting the allowed |
60 |
> versions and preferred order of the versions. |
61 |
> |
62 |
> Few notes; vast majority of filesystems will store the symlink target |
63 |
> into the core inode if at all possible- in doing so, this avoids |
64 |
> wasting an inode and is only limited by the length of the target. |
65 |
> That length is capped by PATH_MAX- which can range from 256 to 4k (or |
66 |
> higher). |
67 |
> |
68 |
> For the pquery example above, that comes out to ~73 bytes for the |
69 |
> symlink pathway; well under PATH_MAX. |
70 |
> |
71 |
> For the scenarios where PATH_MAX caps the symlink pathway, or for |
72 |
> whatever reason we don't want to use that trick, a tree of files |
73 |
> contained within /usr/libexec/python/ holding the allowed versions for |
74 |
> the matching pathway would suffice. |
75 |
> |
76 |
> Either proposal here would be far faster than what we've got now; also |
77 |
> will use less space (ancillary benefit). |
78 |
> |
79 |
> One subtle aspect here is that if we did this, it makes it possible to |
80 |
> avoid losing the invocation information- currently if you did |
81 |
> `/usr/bin/python3.2 $(which sphinx-build) blah`, because of how things |
82 |
> are implemented now (specifically the two layers of wrappers)- you'll |
83 |
> get python2.7 running that sphinx-build invocation. |
84 |
> |
85 |
> This is wrong (it's directly discarding what the invocation |
86 |
> requested), although you're only going to see it for scripts that |
87 |
> do python introspection. |
88 |
> |
89 |
> Via doing the restructuring I'm mentioning above, that issue can be |
90 |
> fixed, while making things faster/saner. |
91 |
> |
92 |
> On a related note; we currently install multiple versions of the same |
93 |
> script- the only difference being the shebang. If one ignores the |
94 |
> shebang, in some cases this is necessary- where the script is 2to3 |
95 |
> translated, and the code for py2k vs py3k differs. For most, the only |
96 |
> difference is in the shebang however. |
97 |
> |
98 |
|
99 |
What if the invoking script is not needed to be 2to3 translated (super |
100 |
minimal python code) but the remaining python libs need to be? |
101 |
|
102 |
> While it's minor in space savings, it's possible to eliminate that |
103 |
> redundancy via a shebang target that looks at the pathway it was |
104 |
> invoked via. Fairly easy actually, and basically zero overhead if |
105 |
> done. |
106 |
> |
107 |
> Either way, thoughts? |
108 |
> |
109 |
> What I'm proposing isn't perfect, but I'm of the view it's a step up |
110 |
> from what's in place now- and via centralizing this crap, makes it |
111 |
> easier to change/maintain this going forward as necessary. |
112 |
> ~harring |
113 |
> |
114 |
|
115 |
+1 from me. |
116 |
|
117 |
Eclean has been checking the name it was invoked with long before I did |
118 |
the major re-write. From that it cleans either distfiles or packages if |
119 |
invoked by either the eclean-dist or eclean-pkg symlinks. If invoked by |
120 |
eclean itself then it looks for the target in the arguments. So Brian's |
121 |
proposal is not something totally new, never been done before... |
122 |
|
123 |
While this proposes something a little different. It is still very much |
124 |
along the same line and in my opinion a much better solution. |
125 |
-- |
126 |
Brian Dolbec <dolsen@g.o> |