a/trunk/wharfie/wharfie.py | b/trunk/wharfie/wharfie.py | ||
---|---|---|---|
... |
... |
||
85 | import os |
85 | import os |
86 | import sys |
86 | import sys |
87 | import re |
87 | import re |
88 | import binascii |
88 | import binascii |
89 | import argparse |
89 | import argparse |
90 | 90 | from lib import makefile as make |
|
91 | regexCommand = '^[ \t]*(RUN HOST|RUN|FROM|TOOLCHAIN|TO|ADD|SOURCE|LICENSE|ENV)([^\n]*)'; |
91 | from lib import actions |
92 | g_depend = ''; |
92 | |
93 | g_makeTargets = list(); |
93 | regexCommand = '^[ \t]*(RUN HOST|RUN|FROM|TOOLCHAIN|TO|ADD|SOURCE|LICENSE|ENV)([^\n]*)'; |
94 | g_environment = list(); |
94 | g_depend = ''; |
95 | g_archiveName = 'rootfs.tar'; |
95 | |
96 | g_finalTarget = list(); |
96 | # |
97 | # We use templates, which are checking their execution context, |
97 | # Read a Wharfile |
98 | # to be sure, that target commands are really only executed |
98 | # |
99 | # in the change root of the image. |
99 | def read_wharfile(filename): |
100 | g_templateTrgCmd = "#!/bin/bash\n[ -f ../Wharfile ] && exit 2;\n%s\n" |
100 | content = open(filename, 'r').read() |
101 | g_templateHostCmd = "#!/bin/bash\n[ ! -f ../Wharfile ] && exit 2;\n%s" |
101 | content = content.replace('\\\n', '') |
102 | 102 | bld = '' |
|
103 | # |
103 | g_allDepends = ''; |
104 | # Read a Wharfile |
104 | g_depend = ''; |
105 | # |
105 | for cmd in re.findall(regexCommand, content, flags=re.MULTILINE): |
106 | def read_wharfile(filename): |
106 | # calculate current build target and dependency names |
107 | global g_archiveName |
107 | dep = list(); |
108 | content = open(filename, 'r').read() |
108 | if bld != '': |
109 | content = content.replace('\\\n', '') |
109 | dep.append(bld); |
110 | bld = '' |
110 | if g_depend != '': |
111 | g_allDepends = ''; |
111 | dep.append(g_depend); |
112 | g_depend = ''; |
112 | |
113 | for cmd in re.findall(regexCommand, content, flags=re.MULTILINE): |
113 | if cmd[0] not in ('FROM', 'TO', 'ENV'): |
114 | # calculate current build target and dependency names |
114 | g_allDepends += str(cmd); |
115 | dep = list(); |
115 | if g_allDepends != '': |
116 | if bld != '': |
116 | bld = format(0xFFFFFFFF & binascii.crc32(g_allDepends), '02X') + ".piling.tar"; |
117 | dep.append(bld); |
117 | |
118 | if g_depend != '': |
118 | # FROM |
119 | dep.append(g_depend); |
119 | if cmd[0] == 'FROM': |
120 | 120 | g_depend = cmd[1] + ".tar"; |
|
121 | if cmd[0] not in ('FROM', 'TO', 'ENV'): |
121 | |
122 | g_allDepends += str(cmd); |
122 | # ENV |
123 | if g_allDepends != '': |
123 | elif cmd[0] == 'ENV': |
124 | bld = format(0xFFFFFFFF & binascii.crc32(g_allDepends), '02X') + ".piling.tar"; |
124 | make.environment.append(cmd[1]); |
125 | 125 | ||
126 | # FROM |
126 | # RUN |
127 | if cmd[0] == 'FROM': |
127 | elif cmd[0] == 'RUN': |
128 | g_depend = cmd[1] + ".tar"; |
128 | makeTarget=actions.run(bld, dep, cmd) |
129 | 129 | make.makeTargets.append(makeTarget); |
|
130 | # ENV |
130 | g_depend = ''; |
131 | elif cmd[0] == 'ENV': |
131 | |
132 | g_environment.append(cmd[1]); |
132 | # RUN HOST |
133 | 133 | elif cmd[0] == 'RUN HOST': |
|
134 | # RUN |
134 | makeTarget=actions.run_host(bld, dep, cmd) |
135 | elif cmd[0] == 'RUN': |
135 | make.makeTargets.append(makeTarget); |
136 | makeTarget = { |
136 | g_depend = ''; |
137 | 'comment' : "%s %s" % (cmd[0], cmd[1]), |
137 | |
138 | 'name': bld, |
138 | # ADD (single file) |
139 | 'dep': dep, |
139 | elif cmd[0] == 'ADD': |
140 | 'trgcmd': cmd[1] |
140 | makeTarget=actions.add(bld, dep, cmd) |
141 | }; |
141 | make.makeTargets.append(makeTarget); |
142 | g_makeTargets.append(makeTarget); |
142 | g_depend = ''; |
143 | g_depend = ''; |
143 | |
144 | 144 | # TO |
|
145 | # RUN HOST |
145 | elif cmd[0] == 'TO': |
146 | elif cmd[0] == 'RUN HOST': |
146 | make.archiveName = cmd[1].lstrip(); |
147 | g_allDepends += str(cmd); |
147 | |
148 | 148 | # SOURCE |
|
149 | makeTarget = { |
149 | elif cmd[0] == 'SOURCE': |
150 | 'comment' : "%s %s" % (cmd[0], cmd[1]), |
150 | myTrgCmd = 'mkdir /sources; cd /sources; [ ! -f .pkg.list ] && dpkg-query -f \'${binary:Package}\\n\' -W > .pkg.list; apt-get install -y dpkg-dev; cat .pkg.list | xargs -n 1 apt-get source' |
151 | 'name': bld, |
151 | myHostCmd = 'tar -cf ../' + cmd[1].lstrip() + ' sources;' |
152 | 'dep': dep, |
152 | makeTarget = { |
153 | 'hostcmd': cmd[1] |
153 | 'comment' : "%s %s" % (cmd[0], cmd[1]), |
154 | }; |
154 | 'name': bld, |
155 | g_makeTargets.append(makeTarget); |
155 | 'dep': dep, |
156 | g_depend = ''; |
156 | 'trgcmd': myTrgCmd, |
157 | 157 | 'hostcmd': myHostCmd, |
|
158 | # ADD (single file) |
158 | 'temporary': True |
159 | elif cmd[0] == 'ADD': |
159 | }; |
160 | g_allDepends += str(cmd); |
160 | make.makeTargets.append(makeTarget); |
161 | src,dst = cmd[1].lstrip().split(" ") |
161 | g_depend = ''; |
162 | dep.append(src) |
162 | |
163 | myHostCmd = 'dest="$(pwd)"; cd ../; mkdir -p $(dirname "${dest}/%s"); cp -R --preserve=mode %s "${dest}/%s"' % (dst, src, dst) |
163 | # LICENSE |
164 | 164 | elif cmd[0] == 'LICENSE': |
|
165 | makeTarget = { |
165 | myTrgCmd = 'mkdir /licenses; for i in /usr/share/doc/*/; do [ -f $i/copyright ] && cp $i/copyright licenses/$(basename $i).txt || echo $(basename $i) >> licenses/___MISSING___.txt; done' |
166 | 'comment' : "%s %s" % (cmd[0], cmd[1]), |
166 | myHostCmd = 'tar -cf ../' + cmd[1].lstrip() + ' licenses;' |
167 | 'name': bld, |
167 | makeTarget = { |
168 | 'dep': dep, |
168 | 'comment' : "%s %s" % (cmd[0], cmd[1]), |
169 | 'hostcmd': myHostCmd |
169 | 'name': bld, |
170 | }; |
170 | 'dep': dep, |
171 | g_makeTargets.append(makeTarget); |
171 | 'trgcmd': myTrgCmd, |
172 | g_depend = ''; |
172 | 'hostcmd': myHostCmd, |
173 | 173 | 'temporary': True |
|
174 | # TO |
174 | }; |
175 | elif cmd[0] == 'TO': |
175 | make.makeTargets.append(makeTarget); |
176 | g_archiveName = cmd[1].lstrip(); |
176 | g_depend = ''; |
177 | 177 | ||
178 | # SOURCE |
178 | # TOOLCHAIN |
179 | elif cmd[0] == 'SOURCE': |
179 | elif cmd[0] == 'TOOLCHAIN': |
180 | myTrgCmd = 'mkdir /sources; cd /sources; [ ! -f .pkg.list ] && dpkg-query -f \'${binary:Package}\\n\' -W > .pkg.list; apt-get install -y dpkg-dev; cat .pkg.list | xargs -n 1 apt-get source' |
180 | myTrgCmd = 'apt-get install -y libc6-dev; [ -d ./usr/lib/arm-linux-gnueabi*/ ] && (cd ./usr/lib/arm-linux-gnueabi*/; ln -s crt1.o crt0.o)' |
181 | myHostCmd = 'tar -cf ../' + cmd[1].lstrip() + ' sources;' |
181 | myHostCmd = 'rm .hst.sh; mkdir target; mv ./* target; mkdir host; (cd host; tar -xf ../../debian_toolchain.tar); cp ../debian_toolchain_env.sh env.sh; tar -cf ../' + cmd[1].lstrip() + ' .;' |
182 | makeTarget = { |
182 | dep.append('debian_toolchain.tar') |
183 | 'comment' : "%s %s" % (cmd[0], cmd[1]), |
183 | dep.append('debian_toolchain_env.sh') |
184 | 'name': bld, |
184 | makeTarget = { |
185 | 'dep': dep, |
185 | 'comment' : "%s %s" % (cmd[0], cmd[1]), |
186 | 'trgcmd': myTrgCmd, |
186 | 'name': bld, |
187 | 'hostcmd': myHostCmd, |
187 | 'dep': dep, |
188 | 'temporary': True |
188 | 'trgcmd': myTrgCmd, |
189 | }; |
189 | 'hostcmd': myHostCmd, |
190 | g_makeTargets.append(makeTarget); |
190 | 'temporary': True |
191 | g_depend = ''; |
191 | }; |
192 | 192 | make.makeTargets.append(makeTarget); |
|
193 | # LICENSE |
193 | g_depend = ''; |
194 | elif cmd[0] == 'LICENSE': |
194 | |
195 | myTrgCmd = 'mkdir /licenses; for i in /usr/share/doc/*/; do [ -f $i/copyright ] && cp $i/copyright licenses/$(basename $i).txt || echo $(basename $i) >> licenses/___MISSING___.txt; done' |
195 | else: |
196 | myHostCmd = 'tar -cf ../' + cmd[1].lstrip() + ' licenses;' |
196 | print ('unknown command: ' + cmd[0] + ' ' + cmd[1]); |
197 | makeTarget = { |
197 | |
198 | 'comment' : "%s %s" % (cmd[0], cmd[1]), |
198 | make.finalTarget.append(bld); |
199 | 'name': bld, |
199 | |
200 | 'dep': dep, |
200 | |
201 | 'trgcmd': myTrgCmd, |
201 | |
202 | 'hostcmd': myHostCmd, |
202 | # |
203 | 'temporary': True |
203 | # Main |
204 | }; |
204 | # |
205 | g_makeTargets.append(makeTarget); |
205 | def main(): |
206 | g_depend = ''; |
206 | parser = argparse.ArgumentParser() |
207 | 207 | parser.add_argument('--clean', action='store_true', help="Clear intermediate files" ) |
|
208 | # TOOLCHAIN |
208 | parser.add_argument('--info', action='store_true', help="Print info about already generated image" ) |
209 | elif cmd[0] == 'TOOLCHAIN': |
209 | parser.add_argument('--gen-only', action='store_true', help="Generate makefile only, but don't build it" ) |
210 | myTrgCmd = 'apt-get install -y libc6-dev; [ -d ./usr/lib/arm-linux-gnueabi*/ ] && (cd ./usr/lib/arm-linux-gnueabi*/; ln -s crt1.o crt0.o)' |
210 | parser.add_argument('--dry-run', action='store_true', help="Generate makefile with disabled run actions and don't build it" ) |
211 | myHostCmd = 'rm .hst.sh; mkdir target; mv ./* target; mkdir host; (cd host; tar -xf ../../debian_toolchain.tar); cp ../debian_toolchain_env.sh env.sh; tar -cf ../' + cmd[1].lstrip() + ' .;' |
211 | parser.add_argument('wharfile', default='Wharfile', nargs='?', help="Filename of a 'Wharfile'. By default ./Wharfile is used." ) |
212 | dep.append('debian_toolchain.tar') |
212 | args = parser.parse_args() |
213 | dep.append('debian_toolchain_env.sh') |
213 | |
214 | makeTarget = { |
214 | # generate makefile |
215 | 'comment' : "%s %s" % (cmd[0], cmd[1]), |
215 | if os.path.isfile(args.wharfile): |
216 | 'name': bld, |
216 | read_wharfile(args.wharfile); |
217 | 'dep': dep, |
217 | else: |
218 | 'trgcmd': myTrgCmd, |
218 | print("error: Wharfile '%s' not found." % args.wharfile) |
219 | 'hostcmd': myHostCmd, |
219 | exit(1) |
220 | 'temporary': True |
220 | |
221 | }; |
221 | if os.path.isfile(os.path.abspath(os.path.dirname(sys.argv[0])) + "/wharfie.mk"): |
222 | g_makeTargets.append(makeTarget); |
222 | make.write_makefile('Makefile', args.dry_run, os.path.dirname(sys.argv[0])); |
223 | g_depend = ''; |
223 | else: |
224 | 224 | make.write_makefile('Makefile', args.dry_run, os.path.abspath(os.path.dirname(sys.argv[0])) + "/../share/wharfie"); |
|
225 | else: |
||
226 | print ('unknown command: ' + cmd[0] + ' ' + cmd[1]); |
||
227 | |||
228 | g_finalTarget.append(bld); |
||
229 | |||
230 | |||
231 | # |
||
232 | # Write a Makefile |
||
233 | # |
||
234 | def write_makefile(filename, dry_run, installpath='.'): |
||
235 | f = open(filename, 'w'); |
||
236 | # write header |
||
237 | f.write("ifneq (VERBOSE,y)\n") |
||
238 | f.write("Q=@\n") |
||
239 | f.write("endif\n") |
||
240 | f.write("\n") |
||
241 | f.write("OUTPUT_FILE=%s\n" % g_archiveName) |
||
242 | f.write("%s: %s\n" % (g_archiveName, "".join(g_finalTarget))); |
||
243 | f.write("\tcp $< $@\n"); |
||
244 | f.write("\n"); |
||
245 | |||
246 | |||
247 | # write all environment variables |
||
248 | for env in g_environment: |
||
249 | l = env.lstrip().split(" ") |
||
250 | f.write("export %s=%s\n" % (l[0], " ".join(l[1:]))); |
||
251 | |||
252 | # write all targets |
||
253 | for target in g_makeTargets: |
||
254 | if 'comment' in target: |
||
255 | f.write("# %s\n" % target['comment']); |
||
256 | f.write("%s: %s\n" % (target['name'], " ".join(target['dep']))); |
||
257 | f.write("\t${Q}-mkdir $$(basename $@ .tar)\n"); |
||
258 | |||
259 | if 'trgcmd' in target: |
||
260 | cmd = g_templateTrgCmd % (target['trgcmd'].replace('$', '\\$$').replace('"', '\\"')); |
||
261 | f.write("\t${Q}echo '******************************'\n"); |
||
262 | f.write("\t${Q}echo '%s'\n" % target['comment']); |
||
263 | f.write("\t${Q}echo '******************************'\n"); |
||
264 | f.write("\t${Q}(echo -e \"%s\") | tee ./$$(basename $@ .tar)/.trg.sh\n" % cmd.replace('\\n', '\\\\\\n').replace('\n', '\\n').replace('!', '"\'!\'"')); |
||
265 | f.write("\t${Q}chmod a+x ./$$(basename $@ .tar)/.trg.sh\n"); |
||
266 | |||
267 | if 'hostcmd' in target: |
||
268 | cmd = g_templateHostCmd % (target['hostcmd'].replace('$', '\\$$').replace('"', '\\"')); |
||
269 | f.write("\t${Q}echo '******************************'\n"); |
||
270 | f.write("\t${Q}echo '%s'\n" % target['comment']); |
||
271 | f.write("\t${Q}echo '******************************'\n"); |
||
272 | f.write("\t${Q}(echo -e \"%s\") | tee ./$$(basename $@ .tar)/.hst.sh\n" % cmd.replace('\\n', '\\\\\\\\n').replace('\n', '\\n').replace('!', '"\'!\'"')); |
||
273 | f.write("\t${Q}chmod a+x ./$$(basename $@ .tar)/.hst.sh\n"); |
||
274 | |||
275 | # start command here ... |
||
276 | f.write("\t${Q}${SUDO} bash -c \""); |
||
277 | |||
278 | f.write("cd $$(basename $@ .tar); tar -xf ../$<; "); |
||
279 | if not dry_run: |
||
280 | f.write("[ -f .trg.sh ] && chroot . ./.trg.sh; rm -f ./.trg.sh; "); |
||
281 | f.write("[ -f .hst.sh ] && ./.hst.sh; rm -f ./.hst.sh; "); |
||
282 | if not 'temporary' in target or not target['temporary']: |
||
283 | f.write("tar -cf '../$@' .;"); |
||
284 | f.write("\"\n"); |
||
285 | # ... end command |
||
286 | |||
287 | |||
288 | if 'temporary' in target and target['temporary']: |
||
289 | f.write("\t${Q}cp $< $@\n"); |
||
290 | |||
291 | f.write("\t${Q}-${SUDO} rm -Rf ./$$(basename $@ .tar)\n"); |
||
292 | f.write("\n"); |
||
293 | |||
294 | # write footer |
||
295 | f.write("include %s/wharfie.mk\n" % installpath); |
||
296 | if installpath != '.': |
||
297 | f.write("-include wharfie.mk\n"); |
||
298 | f.write("\n"); |
||
299 | |||
300 | |||
301 | # |
||
302 | # Main |
||
303 | # |
||
304 | def main(): |
||
305 | parser = argparse.ArgumentParser() |
||
306 | parser.add_argument('--clean', action='store_true', help="Clear intermediate files" ) |
||
307 | parser.add_argument('--info', action='store_true', help="Print info about already generated image" ) |
||
308 | parser.add_argument('--gen-only', action='store_true', help="Generate makefile only, but don't build it" ) |
||
309 | parser.add_argument('--dry-run', action='store_true', help="Generate makefile with disabled run actions and don't build it" ) |
||
310 | parser.add_argument('wharfile', default='Wharfile', nargs='?', help="Filename of a 'Wharfile'. By default ./Wharfile is used." ) |
||
311 | args = parser.parse_args() |
||
312 | |||
313 | # generate makefile |
||
314 | if os.path.isfile(args.wharfile): |
||
315 | read_wharfile(args.wharfile); |
||
316 | else: |
||
317 | print("error: Wharfile '%s' not found." % args.wharfile) |
||
318 | exit(1) |
||
319 | |||
320 | if os.path.isfile(os.path.abspath(os.path.dirname(sys.argv[0])) + "/wharfie.mk"): |
||
321 | write_makefile('Makefile', args.dry_run, os.path.dirname(sys.argv[0])); |
||
322 | else: |
||
323 | write_makefile('Makefile', args.dry_run, os.path.abspath(os.path.dirname(sys.argv[0])) + "/../share/wharfie"); |
||
324 | 225 | ||
325 | # call make |
226 | # call make |
326 | if args.clean: |
227 | if args.clean: |
327 | os.system("make clean") |
228 | os.system("make clean") |
328 | elif args.info: |
229 | elif args.info: |