Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(367)

Side by Side Diff: scripts/slave/recipe_modules/conda/resources/butcher_conda.py

Issue 1511383003: Add recipe to build CIPD package with relocatable Conda environment. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/tools/build
Patch Set: cleanup files Created 5 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
1 # Copyright 2015 The Chromium Authors. All rights reserved.
2 # Use of this source code is governed by a BSD-style license that can be
3 # found in the LICENSE file.
4
5 """Attempts to remove references to Conda installation directory to make the
6 environment more relocatable in exchange for its modifiability.
7
8 No new package can be installed into a butchered environment.
9
10 Works great on Mac and Win, but doesn't really makes the environment prefix
11 independent on Linux, since Linux binaries like to have prefix hardcoded.
12
13 Everything seems to work even on Linux though, but watch out for weirdness.
14
15 Helpful links:
16 https://github.com/conda/conda-recipes
17 http://conda.pydata.org/docs/building/meta-yaml.html#relocatable
18 """
19
20 import ast
21 import glob
22 import os
23 import shutil
24 import sys
25
26
27 IS_WIN = sys.platform in ('win32', 'cygwin')
28
29
30 def main(conda_dir):
31 butcher_bin(conda_dir)
32 butcher_conda_meta(conda_dir)
33 butcher_include(conda_dir)
34 butcher_lib(conda_dir)
35 butcher_pkgs(conda_dir)
36 butcher_pyqt(conda_dir)
37
38
39 def butcher_bin(conda_dir):
40 if IS_WIN:
41 bin_dir = os.path.join(conda_dir, 'Library', 'bin')
42 else:
43 bin_dir = os.path.join(conda_dir, 'bin')
44
45 whitelist = [
46 'python', # relative symlink to python2.7, keep it, it's cute
47 ]
48 blacklist = [
49 'c_rehash', # perl script with references to local prefix
50 'cairo-trace', # not needed
51 'freetype-config', # we won't be linking to freetype
52 'libpng16-config', # same
53 'xml2-config', # same
54 'pyuic4', # just use PyQt4/uic/pyuic.py directly
55 'pyuic4.bat', # same
56 'qt.conf', # Qt manages to work without it
iannucci 2015/12/14 20:44:05 it may be missing resources, depending on the cont
Vadim Sh. 2016/01/09 00:59:45 Yeah.. QtAssistant started normally though, so wha
57 ]
58
59 def is_naughty_shell_script(path):
60 """True if script's shebang points to local prefix."""
61 if IS_WIN:
62 return False
63 with open(path, 'r') as f:
64 return f.read(1024).startswith('#!' + bin_dir)
iannucci 2015/12/14 20:44:05 wouldn't '#!/' be enough to determine naughtiness?
Vadim Sh. 2016/01/09 00:59:45 hm? #!/bin/bash is acceptable script
65
66 # Remove meaningless symlinks and shell scripts that'll broke when relocated.
67 # 'python' stays, it is all that matters.
68 for p in os.listdir(bin_dir):
69 full = os.path.join(bin_dir, p)
70 kill_it = not (p in whitelist or os.path.isdir(full)) and (
71 p in blacklist or
72 os.path.islink(full) or
73 is_naughty_shell_script(full))
74 if kill_it:
75 kill_file(full)
76
77
78 def butcher_conda_meta(conda_dir):
79 # 'conda-meta' contains history of local commands with full paths, as well
80 # as ton of *.json files referencing local paths. We aren't going to install
81 # any more conda packages, no need for meta files.
82 kill_dir(os.path.join(conda_dir, 'conda-meta'))
83
84
85 def butcher_include(conda_dir):
86 # Header files? Where we're going we don't need header files.
87 # But in case we do, a special care must be given to openssl/opensslconf.h,
88 # it references local prefix.
89 kill_dir(os.path.join(conda_dir, 'include'))
90
91
92 def butcher_lib(conda_dir):
93 if IS_WIN:
94 lib = os.path.join(conda_dir, 'Library', 'lib')
95 else:
96 lib = os.path.join(conda_dir, 'lib')
97
98 # We aren't going to build Tk\Tcl extensions, it's not 80s.
iannucci 2015/12/14 20:44:05 http://45.media.tumblr.com/f01045dddb5a403dd140e0a
99 kill_file(os.path.join(lib, 'tclConfig.sh'))
100 kill_file(os.path.join(lib, 'tkConfig.sh'))
101
102 # That's all for Win.
103 if IS_WIN:
104 return
105
106 # We won't be using cmake.
107 kill_dir(os.path.join(lib, 'cmake'))
108
109 # We aren't going to build C stuff, kill libtool and pkg-config files.
110 kill_glob(os.path.join(lib, '*.la'))
111 kill_glob(os.path.join(lib, 'cairo', '*.la'))
112 kill_dir(os.path.join(lib, 'pkgconfig'))
113
114 # We aren't be building python extensions at all, in fact.
115 kill_file(os.path.join(lib, 'python2.7', 'config', 'Makefile'))
116
117 # This file looks important, let's patch it instead of removing.
118 sysconf = os.path.join(lib, 'python2.7', '_sysconfigdata.py')
119 if patch_file(sysconf, conda_dir):
120 kill_file(os.path.join(lib, 'python2.7', '_sysconfigdata.pyc'))
121 kill_file(os.path.join(lib, 'python2.7', '_sysconfigdata.pyo'))
122
123
124 def butcher_pkgs(conda_dir):
125 # pkgs contains unpacked Conda packages that act as source of hardlinks that
126 # gets installed into actual prefix. Since its hard links, it's OK to remove
127 # originals (thus "converting" hardlinks into regular files).
128 kill_dir(os.path.join(conda_dir, 'pkgs')) # TODO: Windows?
129
130
131 def butcher_pyqt(conda_dir):
132 if IS_WIN:
133 prefix = os.path.join(conda_dir, 'Library')
134 else:
135 prefix = conda_dir
136
137 # We won't be using qmake.
138 kill_glob(os.path.join(prefix, 'lib', '*.prl'))
139 kill_dir(os.path.join(prefix, 'mkspecs'))
140
141 # We don't care about Qt4 tests.
142 kill_dir(os.path.join(prefix, 'tests', 'qt4'))
143
144 if not IS_WIN:
145 # We won't by using PyQt build system.
146 kill_file(
147 os.path.join(
148 conda_dir, 'lib', 'python2.7', 'site-packages', 'sipconfig.py'))
149
150 # This file looks important, let's patch it instead.
151 patch_file(
152 os.path.join(
153 conda_dir, 'lib', 'python2.7', 'site-packages',
154 'PyQt4', 'pyqtconfig.py'),
155 conda_dir)
156 else:
157 kill_file(os.path.join(conda_dir, 'qt.conf'))
158
159
160 ###
161
162
163 def patch_file(path, prefix):
164 """Replaces references to 'prefix' with '/opt/fake-python-prefix'."""
165 with open(path, 'rb') as f:
166 blob = f.read()
167 if prefix.endswith('/') or prefix.endswith('\\'):
168 prefix = prefix[:-1]
169 if IS_WIN:
170 fake_prefix = 'C:\\fake-python-prefix'
171 else:
172 fake_prefix = '/opt/fake-python-prefix'
iannucci 2015/12/14 20:44:05 why not just FAKE_PYTHON_PREFIX, which we can then
Vadim Sh. 2016/01/09 00:59:45 That's what conda does itself actually. Except it
173 modified = blob.replace(prefix, fake_prefix)
174 if modified != blob:
175 print 'Patching %s' % os.path.basename(path)
176 with open(path, 'wb') as f:
177 f.write(modified)
178 return True
179 return False
180
181
182 def kill_file(path):
183 if os.path.exists(path) or os.path.lexists(path):
184 print 'Removing %s' % os.path.basename(path)
185 os.remove(path)
186
187
188 def kill_dir(path):
189 if os.path.exists(path):
190 print 'Removing %s directory' % os.path.basename(path)
191 shutil.rmtree(path)
192
193
194 def kill_glob(path):
195 for p in glob.glob(path):
196 kill_file(p)
197
198
199 if __name__ == '__main__':
200 sys.exit(main(os.path.abspath(sys.argv[1])))
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698