Skip only white spaced lines
[scm/meta/abs.git] / abs
1 #!/usr/bin/env python
2 # vim: ai ts=4 sts=4 et sw=4
3 #
4 # Copyright (c) 2014, 2015, 2016 Samsung Electronics.Co.Ltd.
5 #
6 # This program is free software; you can redistribute it and/or modify it
7 # under the terms of the GNU General Public License as published by the Free
8 # Software Foundation; version 2 of the License
9 #
10 # This program is distributed in the hope that it will be useful, but
11 # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12 # or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
13 # for more details.
14 #
15
16 import sys
17 import os
18 import subprocess
19 import re
20 import argparse
21 from argparse import ArgumentParser
22 import ConfigParser
23 import glob
24 import fnmatch
25 import shutil
26 import zipfile
27 import errno
28
29 g_home = os.path.dirname(os.path.realpath(__file__))
30 class LocalError(Exception):
31     """Local error exception."""
32
33     pass
34
35 class Executor(object):
36     """Subprocess wrapper"""
37
38     def __init__(self, checker=None):
39         self.stdout = subprocess.PIPE
40         self.stderr = subprocess.STDOUT
41         self.checker = checker
42
43     def run(self, cmdline_or_args, show=False, checker=False):
44         """Execute external command"""
45
46         out = ''
47         try:
48             process = subprocess.Popen(cmdline_or_args, \
49                                        stdout=self.stdout, \
50                                        stderr=self.stderr, \
51                                        shell=True)
52             while True:
53                 line = process.stdout.readline()
54                 if show:
55                     print line.rstrip()
56                 out = out + '\n' + line.rstrip()
57                 if not line:
58                     break
59         except:
60             raise LocalError('Running process failed')
61
62         return out
63
64 def list_files(path, ext=None):
65
66     f_list = []
67     for root, dirnames, filenames in os.walk(path):
68         if ext is None:
69             for filename in filenames:
70                 f_list.append(os.path.join(root, filename))
71         else:
72             for filename in fnmatch.filter(filenames, '*.'+ext):
73                 f_list.append(os.path.join(root, filename))
74     return f_list
75
76 class FakeSecHead(object):
77
78     def __init__(self, fp):
79
80         self.fp = fp
81         self.sechead = '[ascection]\n'
82
83     def readline(self):
84
85         if self.sechead:
86             try:
87                 return self.sechead
88             finally:
89                 self.sechead = None
90         else:
91             return self.fp.readline()
92
93 class ErrorParser(object):
94     """Inspect specific error string"""
95
96     parsers = []
97
98     def __init__(self):
99
100         ErrorParser = {'GNU_LINKER':['(.*?):?\(\.\w+\+.*\): (.*)', \
101                                      '(.*[/\\\])?ld(\.exe)?: (.*)'], \
102                        'GNU_GCC':['(.*?):(\d+):(\d+:)? [Ee]rror: ([`\'"](.*)[\'"] undeclared .*)', \
103                                   '(.*?):(\d+):(\d+:)? [Ee]rror: (conflicting types for .*[`\'"](.*)[\'"].*)', \
104                                   '(.*?):(\d+):(\d+:)? (parse error before.*[`\'"](.*)[\'"].*)', \
105                                   '(.*?):(\d+):(\d+:)?\s*(([Ee]rror)|(ERROR)): (.*)'], \
106 #                                  '(.*?):(\d+):(\d+:)? (.*)'], \
107                        'GNU_GMAKE':['(.*):(\d*): (\*\*\* .*)', \
108                                     '.*make.*: \*\*\* .*', \
109                                     '.*make.*: Target (.*) not remade because of errors.', \
110                                     '.*[Cc]ommand not found.*', \
111                                     'Error:\s*(.*)'], \
112                        'TIZEN_NATIVE':['.*ninja: build stopped.*', \
113                                        'edje_cc: Error..(.*):(\d).*', \
114                                        'edje_cc: Error.*']}
115
116         for parser in ErrorParser:
117             parser_env = os.getenv('SDK_ERROR_'+parser)
118             if parser_env:
119                 self.parsers.append(parser_env)
120             else:
121                 for msg in ErrorParser[parser]:
122                     self.parsers.append(msg)
123
124     def check(self, full_log):
125         """Check error string line by line"""
126
127         #snipset_text = full_log[:full_log.rfind('PLATFORM_VER\t')].split('\n')
128         for line in full_log.split('\n'):
129             errline = re.search('|'.join(self.parsers), line[:1024])
130             if errline:
131                 return errline.string #Errors
132         return None #No error
133
134 class _Rootstrap(object):
135     """Tizen SDK rootstrap info.
136        Used only in Sdk class"""
137
138     rootstrap_list = None
139     sdk_path = None
140
141     def __init__(self, sdk_path=None, config=None, rootstrap_search=None):
142
143         self.tizen = sdk_path
144         self.list_rootstrap(rootstrap_search)
145         self.config_file = config
146
147     def list_rootstrap(self, rootstrap_search=None):
148         """List all the rootstraps"""
149
150         rs_prefix = 'mobile|wearable'
151         if rootstrap_search is not None:
152             rs_prefix = rootstrap_search
153         print 'Set rs_prefix: %s' % rs_prefix
154
155         if self.rootstrap_list != None:
156             return self.rootstrap_list
157
158         cmdline = self.tizen + ' list rootstrap'
159         ret = Executor().run(cmdline, show=False)
160         for x in ret.splitlines():
161             if re.search('(%s)-(2.4|3.0|4.0|5.0)-(device|emulator|device64|emulator64).core.*' % rs_prefix, x):
162                 if self.rootstrap_list == None:
163                     self.rootstrap_list = []
164                 self.rootstrap_list.append(x.split(' ')[0])
165             else:
166                 print 'No search result for %s' % '(%s)-(2.4|3.0|4.0|5.0)-(device|emulator|device64|emulator64).core.*' % rs_prefix
167         return self.rootstrap_list
168
169     def check_rootstrap(self, rootstrap, show=True):
170         """Specific rootstrap is in the SDK
171            Otherwise use default"""
172
173         if rootstrap == None:
174             rootstrap = 'mobile-3.0-emulator.core' #default
175         if rootstrap in self.rootstrap_list:
176             return rootstrap
177         else:
178             if show == True:
179                 print '  ERROR: Rootstrap [%s] does not exist' % rootstrap
180                 print '  Update your rootstrap or use one of:\n    %s' \
181                        % '\n    '.join(self.list_rootstrap())
182             return None
183
184 class Sdk(object):
185     """Tizen SDK related job"""
186
187     rs = None #_Rootstrap class instance
188     rootstrap_list = None
189     sdk_to_search = ['tizen-studio/tools/ide/bin/tizen', \
190                      'tizen-sdk/tools/ide/bin/tizen', \
191                      'tizen-sdk-ux/tools/ide/bin/tizen', \
192                      'tizen-sdk-cli/tools/ide/bin/tizen']
193
194     def __init__(self, sdkpath=None, rootstrap_search=None):
195
196         self.error_parser = ErrorParser()
197         self.runtool = Executor(checker=self.error_parser)
198
199         self.home = os.getenv('HOME')
200         self.config_file = os.path.join(g_home, '.abs')
201
202         if sdkpath is None:
203             self.tizen = self.get_user_root()
204             if self.tizen is None or self.tizen == '':
205                 for i in self.sdk_to_search:
206                     if os.path.isfile(os.path.join(self.home, i)):
207                         self.tizen = os.path.join(self.home, i)
208                         break
209         else:
210             self.tizen = os.path.join(sdkpath, 'tools/ide/bin/tizen')
211             self.update_user_root(self.tizen)
212
213         if not os.path.isfile(self.tizen):
214             print 'Cannot locate cli tool'
215             raise LocalError('Fail to locate cli tool')
216
217         self.rs = _Rootstrap(sdk_path=self.tizen, config=self.config_file, rootstrap_search=rootstrap_search)
218
219     def get_user_root(self):
220
221         if os.path.isfile(self.config_file):
222             config = ConfigParser.RawConfigParser()
223             config.read(self.config_file)
224             return config.get('Global', 'tizen')
225         return None
226
227     def update_user_root(self, path):
228
229         if not os.path.isfile(self.config_file):
230             with open(self.config_file, 'w') as f:
231                 f.write('[Global]\n')
232                 f.write('tizen = %s\n' % path)
233             return
234
235         config = ConfigParser.RawConfigParser()
236         config.read(self.config_file)
237         config.set('Global', 'tizen', path)
238         with open(self.config_file, 'wb') as cf:
239             config.write(cf)
240
241     def list_rootstrap(self):
242         return self.rs.list_rootstrap()
243
244     def check_rootstrap(self, rootstrap):
245         return self.rs.check_rootstrap(rootstrap)
246
247     def _run(self, command, args, show=True, checker=False):
248         """Run a tizen command"""
249
250         cmd = [self.tizen, command] + args
251         print '\nRunning command:\n    %s' % ' '.join(cmd)
252         return self.runtool.run(' '.join(cmd), show=show, checker=checker)
253
254     def copytree2(self, src, dst, symlinks=False, ignore=None):
255         """Copy with Ignore & Overwrite"""
256         names = os.listdir(src)
257         if ignore is not None:
258             ignored_names = ignore(src, names)
259         else:
260             ignored_names = set()
261
262         try:
263             os.makedirs(dst)
264         except:
265             pass
266
267         errors = []
268         for name in names:
269             if name in ignored_names:
270                 continue
271             srcname = os.path.join(src, name)
272             dstname = os.path.join(dst, name)
273             try:
274                 if symlinks and os.path.islink(srcname):
275                     linkto = os.readlink(srcname)
276                     os.symlink(linkto, dstname)
277                 elif os.path.isdir(srcname):
278                     self.copytree2(srcname, dstname, symlinks, ignore)
279                 else:
280                     # Will raise a SpecialFileError for unsupported file types
281                     shutil.copy2(srcname, dstname)
282             # catch the Error from the recursive copytree so that we can
283             # continue with other files
284             except shutil.Error, err:
285                 errors.extend(err.args[0])
286             except EnvironmentError, why:
287                 errors.append((srcname, dstname, str(why)))
288         try:
289             shutil.copystat(src, dst)
290         except OSError, why:
291             if WindowsError is not None and isinstance(why, WindowsError):
292                 # Copying file access times may fail on Windows
293                 pass
294             else:
295                 errors.append((src, dst, str(why)))
296         #if errors:
297          #   raise shutil.Error, errors
298
299     def _copy_build_output(self, src, dst):
300         if not os.path.isdir(src) :
301             return
302         try:
303             self.copytree2(src, dst, ignore=shutil.ignore_patterns('*.edc', '*.po', 'objs', '*.info', '*.so', 'CMakeLists.txt', '*.h', '*.c'))
304         except OSError as exc:
305             # File already exist
306             if exc.errno == errno.EEXIST:
307                 shutil.copy(src, dst)
308             if exc.errno == errno.ENOENT:
309                 shutil.copy(src, dst)
310             else:
311                 raise
312
313     def _package_sharedlib(self, project_path, conf, app_name):
314         """If -r option used for packaging, make zip file from copied files"""
315         #project_path=project['path']
316         project_build_output_path=os.path.join(project_path, conf)
317         package_path=os.path.join(project_build_output_path, '.pkg')
318
319         if os.path.isdir(package_path):
320             shutil.rmtree(package_path)
321         os.makedirs(package_path)
322         os.makedirs(os.path.join(package_path, 'lib'))
323
324         #Copy project resource
325         self._copy_build_output(os.path.join(project_path, 'lib'), os.path.join(package_path, 'lib'))
326         self._copy_build_output(os.path.join(project_path, 'res'), os.path.join(package_path, 'res'))
327
328         #Copy built res resource
329         self._copy_build_output(os.path.join(project_build_output_path, 'res'), os.path.join(package_path, 'res'))
330
331         #Copy so library file
332         for filename in list_files(project_build_output_path, 'so'):
333             shutil.copy(filename, os.path.join(package_path, 'lib'))
334
335         # Copy so library file
336         zipname=app_name + '.zip'
337         rsrc_zip = os.path.join(project_build_output_path, zipname)
338         myZipFile = zipfile.ZipFile(rsrc_zip, 'w')
339         for filename in list_files(package_path):
340             try:
341                 myZipFile.write(filename, filename.replace(package_path, ''))
342             except Exception, e:
343                 print str(e)
344         myZipFile.close()
345         return rsrc_zip
346
347     def build_native(self, source, rootstrap=None, arch=None, conf='Debug', jobs=None):
348         """SDK CLI build command"""
349
350         _rootstrap = self.check_rootstrap(rootstrap)
351         if _rootstrap == None:
352             raise LocalError('Rootstrap %s not exist' % rootstrap)
353
354         if rootstrap is None and arch is None:
355             rootstrap = _rootstrap
356             self.arch = 'x86'
357         elif arch is None:
358             if 'emulator64' in rootstrap: self.arch = 'x86_64'
359             elif 'device64' in rootstrap: self.arch = 'aarch64'
360             elif 'emulator' in rootstrap: self.arch = 'x86'
361             elif 'device' in rootstrap: self.arch = 'arm'
362         elif rootstrap is None:
363             if arch not in ['x86', 'arm', 'aarch64', 'x86_64']:
364                 raise LocalError('Architecture and rootstrap mismatch')
365
366             rootstrap = _rootstrap
367             if arch == 'x86_64': rootstrap = rootstrap.replace('emulator', 'emulator64')
368             elif arch == 'aarch64': rootstrap = rootstrap.replace('emulator', 'device64')
369             elif arch == 'arm': rootstrap = rootstrap.replace('emulator', 'device')
370
371         for x in source.project_list:
372             b_args = ['-r', rootstrap, '-a', self.arch, '-C', conf, '-c', 'gcc']
373             if jobs is not None: b_args.extend(['-j', jobs])
374             b_args.extend(['--', x['path']])
375             out = self._run('build-native', b_args, checker=True)
376             logpath = os.path.join(source.output_dir, \
377                                   'build_%s_%s' % (rootstrap, os.path.basename(x['path'])))
378             if not os.path.isdir(source.output_dir):
379                 os.makedirs(source.output_dir)
380             with open(logpath, 'w') as lf:
381                 lf.write(out)
382             ret = self.error_parser.check(out)
383             if True:
384                 with open(logpath+'.log', 'w') as lf:
385                     lf.write(out)
386             if ret:
387                 raise LocalError(ret)
388
389     def package(self, source, cert=None, pkg_type=None, conf='Debug', manual_strip=False):
390         """SDK CLI package command
391             IF Debug + Manual Strip off then generate package-name-debug.tpk
392             IF Debug + Manual Strip on then generate package-name.tpk with custom strip
393             IF Release then generate package-name.tpk with strip option
394         """
395         if cert is None: cert = 'ABS'
396         if pkg_type is None: pkg_type = 'tpk'
397         if conf is None: conf = 'Debug'
398
399         final_app = ''
400         main_args = ['-t', pkg_type, '-s', cert]
401         out = '' #logfile
402
403         # remove tpk or zip file on project path
404         package_list = []
405         for i, x in enumerate(source.project_list):
406             package_list.extend(list_files(os.path.join(x['path'], conf), ext='tpk'))
407             package_list.extend(list_files(os.path.join(x['path'], conf), ext='zip'))
408
409         for k in package_list :
410             print ' package list ' + k;
411             os.remove(k)
412
413         # Manual strip
414         if manual_strip == True :
415             strip_cmd='';
416             if self.arch == None:
417                 raise LocalError('Architecture is None')
418
419             for i, x in enumerate(source.project_list):
420                 dir = os.path.join(x['path'], conf)
421                 files = [os.path.join(dir,f) for f in os.listdir(dir) if os.path.isfile(os.path.join(dir,f))]
422
423                 # dir must be "project/Debug directory"
424                 info_path = os.path.join(dir, "build.info")
425                 # Default Strip gcc version is 6.2
426                 gcc_version = "6.2"
427                 # Parsing GCC version from build.info inside Debug directory in Project to each project
428                 if os.path.exists(info_path) :
429                     with open(info_path) as fp :
430                         for line in fp :
431                             if line.startswith("toolchain=") :
432                                 line = line.strip()
433                                 gcc_version = re.findall("\d+\.\d+", line)[0]
434                 else :
435                     print "Cannot find Debug/build.info. The default gcc will strip tpk"
436
437                 print "gcc version:" + gcc_version
438
439                 if self.arch == 'x86' :
440                     if(gcc_version == "4.9"):
441                         strip_cmd = os.path.join(os.path.dirname(self.tizen), '../../i386-linux-gnueabi-gcc-' + gcc_version + '/bin/i386-linux-gnueabi-strip')
442                     else:
443                         strip_cmd = os.path.join(os.path.dirname(self.tizen), '../../i586-linux-gnueabi-gcc-' + gcc_version + '/bin/i586-linux-gnueabi-strip')
444                 elif self.arch == 'arm' :
445                     strip_cmd = os.path.join(os.path.dirname(self.tizen), '../../arm-linux-gnueabi-gcc-' + gcc_version + '/bin/arm-linux-gnueabi-strip')
446                 elif self.arch == 'x86_64' :
447                     strip_cmd = os.path.join(os.path.dirname(self.tizen), '../../x86_64-linux-gnu-gcc-' + gcc_version + '/bin/x86_64-linux-gnu-strip')
448                 elif self.arch == 'aarch64' :
449                     strip_cmd = os.path.join(os.path.dirname(self.tizen), '../../aarch64-linux-gnu-gcc-' + gcc_version + '/bin/aarch64-linux-gnu-strip')
450
451                 print strip_cmd
452
453                 for k in files:
454                     cmdline = strip_cmd + ' ' + k;
455                     #print 'my command line ' + cmdline;
456                     Executor().run(cmdline, show=False)
457
458         elif conf == 'Release':
459             main_args.extend(['--strip', 'on'])
460
461         for i, x in enumerate(source.project_list):
462             if x['type'] == 'app':
463                 out = '%s\n%s' % (out, \
464                       self._run('package', main_args + ['--',os.path.join(x['path'],conf)]))
465                 try:
466                     final_app = list_files(os.path.join(x['path'], conf), ext='tpk')[0]
467                 except:
468                     raise LocalError('TPK file not generated for %s.' % x['APPNAME'])
469                 x['out_package'] = final_app
470             elif x['type'] == 'sharedLib':
471                 self._package_sharedlib(x['path'], conf, x['APPNAME'])
472                 x['out_package'] = list_files(os.path.join(x['path'], conf), ext='zip')[0]
473             else:
474                 raise LocalError('Not supported project type %s' % x['type'])
475
476         if source.b_multi == True:
477             extra_args=[]
478             print 'THIS IS MULTI PROJECT'
479             for i, x in enumerate(source.project_list):
480                 if x['out_package'] != final_app and x['type'] == 'app':
481                     extra_args.extend(['-r', x['out_package']])
482                 elif x['type'] == 'sharedLib':
483                     extra_args.extend(['-r', x['out_package']])
484
485             extra_args.extend(['--', final_app])
486             out = self._run('package', main_args + extra_args)
487
488         #TODO: signature validation check failed : Invalid file reference. An unsigned file was found.
489         print 'Packaging final step again!'
490         out = self._run('package', main_args + ['--', final_app])
491
492         #Copy tpk to output directory
493         if conf == 'Debug' and manual_strip == False :
494             basename = os.path.splitext(final_app)[0]
495             newname = basename +'-debug.tpk'
496             os.rename(final_app, newname)
497             shutil.copy(newname, source.output_dir)
498         else :
499             shutil.copy(final_app, source.output_dir)
500
501     def clean(self, source):
502         """SDK CLI clean command"""
503
504         if os.path.isdir(source.multizip_path):
505             shutil.rmtree(source.multizip_path)
506
507         if os.path.isfile(os.path.join(source.multizip_path, '.zip')):
508             os.remove(os.path.join(source.multizip_path, '.zip'))
509
510         for x in source.project_list:
511             self._run('clean', ['--', x['path']], show=False)
512
513 class Source(object):
514     """Project source related job"""
515
516     workspace = '' #Project root directory
517     project_list = []
518     b_multi = False
519     multi_conf_file = 'WORKSPACE' #Assume multi-project if this file exist.
520     multizip_path = '' #For multi-project packaging -r option
521     property_dict = {}
522     output_dir = '_abs_out_'
523
524     def __init__(self, src=None):
525
526         if src == None:
527             self.workspace = os.getcwd()
528         else:
529             self.workspace = os.path.abspath(src)
530         self.output_dir = os.path.join(self.workspace, self.output_dir)
531
532         os.environ['workspace_loc']=str(os.path.realpath(self.workspace))
533
534         self.multizip_path = os.path.join(self.workspace, 'multizip')
535         self.pre_process()
536
537     def set_properties(self, path):
538         """Fetch all properties from project_def.prop"""
539
540         mydict = {}
541         cp = ConfigParser.SafeConfigParser()
542         cp.optionxform = str
543         cp.readfp(FakeSecHead(open(os.path.join(path, 'project_def.prop'))))
544         for x in cp.items('ascection'):
545             mydict[x[0]] = x[1]
546         mydict['path'] = path
547         return mydict
548
549     def set_user_options(self, c_opts=None, cpp_opts=None, link_opts=None):
550         if c_opts is not None:
551             os.environ['USER_C_OPTS'] = c_opts
552             print 'Set USER_C_OPTS=[%s]' % os.getenv('USER_C_OPTS')
553         if cpp_opts is not None:
554             os.environ['USER_CPP_OPTS'] = cpp_opts
555             print 'Set USER_CPP_OPTS=[%s]' % os.getenv('USER_CPP_OPTS')
556         if link_opts is not None:
557             os.environ['USER_LINK_OPTS'] = link_opts
558             print 'Set USER_LINK_OPTS=[%s]' % os.getenv('USER_LINK_OPTS')
559
560     def pre_process(self):
561
562         if os.path.isfile(os.path.join(self.workspace, self.multi_conf_file)):
563             self.b_multi = True
564             with open(os.path.join(self.workspace, self.multi_conf_file)) as f:
565                 for line in f:
566                     if not line.strip():
567                         continue
568                     file_path = os.path.join(self.workspace, line.rstrip())
569                     self.project_list.append(self.set_properties(file_path))
570         else:
571             self.b_multi = False
572             file_path = os.path.join(self.workspace)
573             self.project_list.append(self.set_properties(file_path))
574
575 def argument_parsing(argv):
576     """Any arguments passed from user"""
577
578     parser = argparse.ArgumentParser(description='ABS command line interface')
579
580     subparsers = parser.add_subparsers(dest='subcommands')
581
582     #### [subcommand - BUILD] ####
583     build = subparsers.add_parser('build')
584     build.add_argument('-w', '--workspace', action='store', dest='workspace', \
585                         help='source directory')
586     build.add_argument('-r', '--rootstrap', action='store', dest='rootstrap', \
587                         help='(ex, mobile-3.0-device.core) rootstrap name')
588     build.add_argument('-a', '--arch', action='store', dest='arch', \
589                         help='(x86|arm|x86_64|aarch64) Architecture to build')
590     build.add_argument('-t', '--type', action='store', dest='type', \
591                         help='(tpk|wgt) Packaging type')
592     build.add_argument('-s', '--cert', action='store', dest='cert', \
593                         help='(ex, ABS) Certificate profile name')
594     build.add_argument('-c', '--conf', action='store',default='Release', dest='conf', \
595                         help='(ex, Debug|Release) Build Configuration')
596     build.add_argument('-j', '--jobs', action='store', dest='jobs', \
597                         help='(number of jobs) The number of parallel builds')
598     build.add_argument('--sdkpath', action='store', dest='sdkpath', \
599                         help='Specify Tizen SDK installation root (one time init).' \
600                              ' ex) /home/yours/tizen-sdk/')
601     build.add_argument('--profile-to-search', action='store', dest='profiletosearch', \
602                         help='Rootstrap profile prefix.' \
603                              ' ex) (mobile|wearable|da-hfp)')
604     build.add_argument('--c-opts', action='store', dest='c_opts', \
605                         help='Extra compile options USER_C_OPTS')
606     build.add_argument('--cpp-opts', action='store', dest='cpp_opts', \
607                         help='Extra compile options USER_CPP_OPTS')
608     build.add_argument('--link-opts', action='store', dest='link_opts', \
609                         help='Extra linking options USER_LINK_OPTS')
610
611     return parser.parse_args(argv[1:])
612
613 def build_main(args):
614     """Command [build] entry point."""
615
616     try:
617         my_source = Source(src=args.workspace)
618
619         my_source.set_user_options(c_opts=args.c_opts, cpp_opts=args.cpp_opts, link_opts=args.link_opts)
620         print '-------------------'
621         print '(%s)' % args.profiletosearch
622         print '-------------------'
623         my_sdk = Sdk(sdkpath=args.sdkpath, rootstrap_search=args.profiletosearch)
624         my_sdk.clean(my_source)
625         my_sdk.build_native(my_source, rootstrap=args.rootstrap, arch=args.arch, jobs=args.jobs)
626         if args.conf == 'Debug' :
627             my_sdk.package(my_source, pkg_type=args.type, cert=args.cert)
628             my_sdk.package(my_source, pkg_type=args.type, cert=args.cert, manual_strip=True)
629         else :
630             my_sdk.package(my_source, pkg_type=args.type, cert=args.cert, manual_strip=True)
631
632     except Exception as err:
633         wrk = os.path.join(os.path.abspath(args.workspace), '_abs_out_')
634         if not os.path.isdir(wrk):
635             os.makedirs(wrk)
636         with open(os.path.join(wrk, 'build_EXCEPTION.log'), 'w') as ef:
637             ef.write('Exception %s' % str(err))
638         raise err
639
640 def main(argv):
641     """Script entry point."""
642
643     print 'ABS SCRIPT FROM GIT'
644
645     args = argument_parsing(argv)
646
647     if args.subcommands == 'build':
648         return build_main(args)
649     else:
650         print 'Unsupported command %s' % args.subcommands
651         raise LocalError('Command %s not supported' % args.subcommands)
652
653 if __name__ == '__main__':
654
655     try:
656         sys.exit(main(sys.argv))
657     except Exception, e:
658         print 'Exception %s' % str(e)
659         #FIXME: Remove hard-coded output directory.
660         if not os.path.isdir('_abs_out_'):
661             os.makedirs('_abs_out_')
662         with open(os.path.join('_abs_out_', 'build_EXCEPTION.log'), 'w') as ef:
663             ef.write('Exception %s' % repr(e))
664         sys.exit(1)