-
Notifications
You must be signed in to change notification settings - Fork 19
/
arsdkgen.py
executable file
·170 lines (150 loc) · 5.39 KB
/
arsdkgen.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
#!/usr/bin/env python3
import sys
import locale
_forced_locale = 'en_US.UTF-8'
try:
locale.setlocale(locale.LC_ALL, _forced_locale)
except locale.Error:
print('Unable to set locale to {}.'.format(_forced_locale),
'Continuing with default locale (this might cause issues)',
file=sys.stderr)
import os, stat, logging, tempfile, filecmp, shutil
import optparse
import arsdkparser
#===============================================================================
#===============================================================================
#===============================================================================
# Writer class to wrap a file and allow printf-like write method.
#===============================================================================
class Writer(object):
def __init__(self, filePath):
# unlink previous file
try:
os.unlink(filePath)
except OSError as e:
if e.errno == 2: # No such file or directory
pass
else:
raise e
self.filePath = filePath
self.fd = open(filePath, "w")
def write(self, fmt, *args):
if args:
self.fd.write(fmt % (args))
else:
self.fd.write(fmt % ())
def close(self):
# close file
self.fd.close()
# mark file as readonly
os.chmod(self.filePath, stat.S_IRUSR | stat.S_IRGRP | stat.S_IROTH)
#===============================================================================
#===============================================================================
def main():
(options, args) = parseArgs()
setupLog(options)
generator_filepath = args[0]
extra = ' '.join(args[1:]) if len(args) > 1 else None
# Setup full path of output directories
options.outdir = os.path.abspath(options.outdir)
logging.info("arsdkgen: cmd=%s generator=%s, outdir=%s extra=%s",
"list" if options.listFiles else "generate",
generator_filepath, options.outdir, extra)
if not options.listFiles:
os.makedirs(options.outdir, 0o755, exist_ok=True)
# Import package of ge generation
(generator_path, generator_filename) = os.path.split(generator_filepath)
sys.path.append(generator_path)
try:
generator = __import__(os.path.splitext(generator_filename)[0])
except ImportError:
logging.error("Unable to import generator %s", generator_filepath)
sys.exit(1)
ctx = arsdkparser.ArParserCtx()
path, filename = os.path.split(os.path.realpath(__file__))
path = os.path.join(path, "xml")
# first load generic.xml
arsdkparser.parse_xml(ctx, os.path.join(path, "generic.xml"))
for f in sorted(os.listdir(path)):
if not f.endswith(".xml") or f == "generic.xml":
continue
arsdkparser.parse_xml(ctx, os.path.join(path, f))
# Call generator
if options.listFiles:
generator.list_files(ctx, options.outdir, extra)
else:
# Generate in tmp folder.
tmp_dir = tempfile.mkdtemp()
generator.generate_files(ctx, tmp_dir, extra)
# Copy in outdir all files different in tmp_dir and in outdir.
for path, subdirs, files in os.walk(tmp_dir):
for name in files:
f_tmp = os.path.join(path, name)
f_cp = f_tmp.replace(tmp_dir, options.outdir)
if not os.path.isfile(f_cp) or \
filecmp.cmp(f_tmp, f_cp) == False:
if not os.path.exists(os.path.dirname(f_cp)):
os.makedirs(os.path.dirname(f_cp))
logging.info('Copy: ' + f_tmp + " => " + f_cp)
shutil.copy(f_tmp, f_cp)
# Remove tmp_dir
shutil.rmtree(tmp_dir)
#===============================================================================
# Setup option parser and parse command line.
#===============================================================================
def parseArgs():
# Setup parser
usage = "usage: %prog [options] <generator> [extra]"
parser = optparse.OptionParser(usage = usage)
# Main options
parser.add_option("-o", "--output",
dest = "outdir",
action = "store",
default = ".",
metavar = "DIR",
help = "Name of output directory [default: current directory]")
parser.add_option("-f", "--files",
dest = "listFiles",
action = "store_true",
default = False,
help = "List on stdout full path of files that will be generated and exit")
# Other options
parser.add_option("-q",
dest = "quiet",
action = "store_true",
default = False,
help = "be quiet")
parser.add_option("-v",
dest = "verbose",
action = "count",
default = 0,
help = "verbose output (more verbose if specified twice)")
# Parse arguments and check validity
(options, args) = parser.parse_args()
if len(args) < 1:
parser.error("Missing generator filepath")
return (options, args)
#===============================================================================
# Setup logging system.
#===============================================================================
def setupLog(options):
logging.basicConfig(
level = logging.WARNING,
format = "[%(levelname)s] %(message)s",
stream = sys.stderr)
logging.addLevelName(logging.CRITICAL, "C")
logging.addLevelName(logging.ERROR, "E")
logging.addLevelName(logging.WARNING, "W")
logging.addLevelName(logging.INFO, "I")
logging.addLevelName(logging.DEBUG, "D")
# Setup log level
if options.quiet == True:
logging.getLogger().setLevel(logging.CRITICAL)
elif options.verbose >= 2:
logging.getLogger().setLevel(logging.DEBUG)
elif options.verbose >= 1:
logging.getLogger().setLevel(logging.INFO)
#===============================================================================
#===============================================================================
if __name__ == "__main__":
main()