Diff of /trunk/wharfie/wharfie.py [r12] .. [r13]  Maximize  Restore

Switch to unified view

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: