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