Imported Upstream version 1.2.0
[platform/upstream/iotivity.git] / build_common / tools / UnpackAll.py
1 # -*- coding: utf-8 -*-
2
3 ############################################################################
4 # GPL License                                                              #
5 #                                                                          #
6 # This file is a SCons (http://www.scons.org/) builder                     #
7 # Copyright (c) 2012-14, Philipp Kraus, <philipp.kraus@flashpixx.de>       #
8 # Copyright 2014 Intel Mobile Communications GmbH All Rights Reserved.     #
9 # This program is free software: you can redistribute it and/or modify     #
10 # it under the terms of the GNU General Public License as                  #
11 # published by the Free Software Foundation, either version 3 of the       #
12 # License, or (at your option) any later version.                          #
13 #                                                                          #
14 # This program is distributed in the hope that it will be useful,          #
15 # but WITHOUT ANY WARRANTY; without even the implied warranty of           #
16 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the            #
17 # GNU General Public License for more details.                             #
18 #                                                                          #
19 # You should have received a copy of the GNU General Public License        #
20 # along with this program. If not, see <http://www.gnu.org/licenses/>.     #
21 ############################################################################
22
23 # This builder originated from work by Philipp Kraus and flashpixx project
24 # (see https://github.com/flashpixx). Based on the Unpack.py, it only
25 # contains changes to allow a complete unpacking of the archive.
26 # It is assumed that the target represents a file in the archive after it
27 # is unpacked.
28
29 # The Unpack Builder can be used for unpacking archives (eg Zip, TGZ, BZ, ... ).
30 # The emitter of the Builder reads the archive data and creates a returning
31 # file list the builder extract the archive. The environment variable
32 # stores a dictionary "UNPACK" for set different extractions (subdict "EXTRACTOR"):
33 # {
34 #   PRIORITY         => a value for setting the extractor order (lower numbers = extractor is used earlier)
35 #   SUFFIX           => defines a list with file suffixes, which should be handled with this extractor
36 #   EXTRACTSUFFIX    => suffix of the extract command
37 #   EXTRACTFLAGS     => a string parameter for the RUN command for extracting the data
38 #   EXTRACTCMD       => full extract command of the builder
39 #   RUN              => the main program which will be started (if the parameter is empty, the extractor will be ignored)
40 #   LISTCMD          => the listing command for the emitter
41 #   LISTFLAGS        => the string options for the RUN command for showing a list of files
42 #   LISTSUFFIX       => suffix of the list command
43 #   LISTEXTRACTOR    => a optional Python function, that is called on each output line of the
44 #                       LISTCMD for extracting file & dir names, the function need two parameters (first line number,
45 #                       second line content) and must return a string with the file / dir path (other value types
46 #                       will be ignored)
47 # }
48 # Other options in the UNPACK dictionary are:
49 #   STOPONEMPTYFILE  => bool variable for stoping if the file has empty size (default True)
50 #   VIWEXTRACTOUTPUT => shows the output messages of the extraction command (default False)
51 #   EXTRACTDIR       => path in that the data will be extracted (default #)
52 #
53 # The file which is handled by the first suffix match of the extractor, the extractor list can be append for other files.
54 # The order of the extractor dictionary creates the listing & extractor command eg file extension .tar.gz should be
55 # before .gz, because the tar.gz is extract in one shoot.
56 #
57 # Under *nix system these tools are supported: tar, bzip2, gzip, unzip
58 # Under Windows only 7-Zip (http://www.7-zip.org/) is supported
59
60
61 import subprocess, os
62 import SCons.Errors, SCons.Warnings, SCons.Util
63
64 # enables Scons warning for this builder
65 class UnpackWarning(SCons.Warnings.Warning) :
66     pass
67
68 SCons.Warnings.enableWarningClass(UnpackWarning)
69
70 # extractor function for Tar output
71 # @param env environment object
72 # @param count number of returning lines
73 # @param no number of the output line
74 # @param i line content
75 def __fileextractor_nix_tar( env, count, no, i ) :
76     return i.split()[-1]
77
78 # extractor function for GZip output,
79 # ignore the first line
80 # @param env environment object
81 # @param count number of returning lines
82 # @param no number of the output line
83 # @param i line content
84 def __fileextractor_nix_gzip( env, count, no, i ) :
85     if no == 0 :
86         return None
87     return i.split()[-1]
88
89 # extractor function for Unzip output,
90 # ignore the first & last two lines
91 # @param env environment object
92 # @param count number of returning lines
93 # @param no number of the output line
94 # @param i line content
95 def __fileextractor_nix_unzip( env, count, no, i ) :
96     if no < 3 or no >= count - 2 :
97         return None
98     return i.split()[-1]
99
100 # extractor function for 7-Zip
101 # @param env environment object
102 # @param count number of returning lines
103 # @param no number of the output line
104 # @param i line content
105 def __fileextractor_win_7zip( env, count, no, i ) :
106     item = i.split()
107     if no > 8 and no < count - 2 :
108         return item[-1]
109     return None
110
111
112
113 # returns the extractor item for handling the source file
114 # @param source input source file
115 # @param env environment object
116 # @return extractor entry or None on non existing
117 def __getExtractor( source, env ) :
118     # we check each unpacker and get the correct list command first, run the command and
119     # replace the target filelist with the list values, we sorte the extractors by their priority
120     for unpackername, extractor in sorted(env["UNPACK"]["EXTRACTOR"].iteritems(), key = lambda (k,v) : (v["PRIORITY"],k)):
121
122         if not SCons.Util.is_String(extractor["RUN"]) :
123             raise SCons.Errors.StopError("list command of the unpack builder for [%s] archives is not a string" % (unpackername))
124         if not len(extractor["RUN"]) :
125             raise SCons.Errors.StopError("run command of the unpack builder for [%s] archives is not set - can not extract files" % (unpackername))
126
127
128         if not SCons.Util.is_String(extractor["LISTFLAGS"]) :
129             raise SCons.Errors.StopError("list flags of the unpack builder for [%s] archives is not a string" % (unpackername))
130         if not SCons.Util.is_String(extractor["LISTCMD"]) :
131             raise SCons.Errors.StopError("list command of the unpack builder for [%s] archives is not a string" % (unpackername))
132
133         if not SCons.Util.is_String(extractor["EXTRACTFLAGS"]) :
134             raise SCons.Errors.StopError("extract flags of the unpack builder for [%s] archives is not a string" % (unpackername))
135         if not SCons.Util.is_String(extractor["EXTRACTCMD"]) :
136             raise SCons.Errors.StopError("extract command of the unpack builder for [%s] archives is not a string" % (unpackername))
137
138
139         # check the source file suffix and if the first is found, run the list command
140         if not SCons.Util.is_List(extractor["SUFFIX"]) :
141             raise SCons.Errors.StopError("suffix list of the unpack builder for [%s] archives is not a list" % (unpackername))
142
143         for suffix in extractor["SUFFIX"] :
144             if str(source[0]).lower()[-len(suffix):] == suffix.lower() :
145                 return extractor
146
147     return None
148
149
150 # creates the extracter output message
151 # @param s original message
152 # @param target target name
153 # @param source source name
154 # @param env environment object
155 def __message( s, target, source, env ) :
156     print "extract [%s] ..." % (source[0])
157
158
159 # action function for extracting of the data
160 # @param target target packed file
161 # @param source extracted files
162 # @param env environment object
163 def __action( target, source, env ) :
164     cwd = os.path.realpath('.')
165     extractor = __getExtractor([File(source)], env)
166     if not extractor :
167         print '''******************************* Error *****************************************
168 *
169 * Doesn't support auto extracting [%s], please extract it to [%s].
170 *                                                                             *
171 *******************************************************************************
172 ''' % (source, cwd)
173         raise SCons.Errors.StopError( "can not find any extractor value for the source file [%s]" % (source) )
174
175     extractor_cmd = extractor["EXTRACTCMD"]
176
177     # if the extract command is empty, we create an error
178     if len(extractor_cmd) == 0 :
179         raise SCons.Errors.StopError( "the extractor command for the source file [%s] is empty" % (source) )
180
181     # build it now (we need the shell, because some programs need it)
182     handle = None
183
184     cmd = env.subst(extractor_cmd, source=source, target=target)
185
186     if env["UNPACK"]["VIWEXTRACTOUTPUT"] :
187         handle  = subprocess.Popen( cmd, shell=True )
188     else :
189         devnull = open(os.devnull, "wb")
190         handle  = subprocess.Popen(cmd, shell=True, stdout=devnull, cwd = cwd)
191
192     if handle.wait() <> 0 :
193         print '''******************************* Error *****************************************
194 *
195 * Fail to unpack [%s]. It should be due to it isn't downloaded completely.
196 * Please download it manually or delete it and let the script auto download it*
197 * again.                                                                      *
198 *                                                                             *
199 *******************************************************************************
200 ''' % (source)
201         raise SCons.Errors.BuildError( "error running extractor [%s] on the source [%s]" % (cmd, source) )
202
203 # emitter function for getting the files
204 # within the archive
205 # @param target target packed file
206 # @param source extracted files
207 # @param env environment object
208 def __emitter( target, source, env ) :
209     return target, source
210
211 def __unpack_all(env, target, source) :
212         if os.path.exists(target):
213                 return
214
215         print "Unpacking %s ..." % source
216         __action(target, source, env)
217
218 # generate function, that adds the builder to the environment
219 # @param env environment object
220 def generate( env ) :
221     # setup environment variable
222     toolset = {
223         "STOPONEMPTYFILE"  : True,
224         "VIWEXTRACTOUTPUT" : False,
225         "EXTRACTDIR"       : os.curdir,
226         "EXTRACTOR" : {
227             "TARGZ" : {
228                 "PRIORITY"       : 0,
229                 "SUFFIX"         : [".tar.gz", ".tgz", ".tar.gzip"],
230                 "EXTRACTSUFFIX"  : "",
231                 "EXTRACTFLAGS"   : "",
232                 "EXTRACTCMD"     : "${UNPACK['EXTRACTOR']['TARGZ']['RUN']} ${UNPACK['EXTRACTOR']['TARGZ']['EXTRACTFLAGS']} $SOURCE ${UNPACK['EXTRACTOR']['TARGZ']['EXTRACTSUFFIX']}",
233                 "RUN"            : "",
234                 "LISTCMD"        : "${UNPACK['EXTRACTOR']['TARGZ']['RUN']} ${UNPACK['EXTRACTOR']['TARGZ']['LISTFLAGS']} $SOURCE ${UNPACK['EXTRACTOR']['TARGZ']['LISTSUFFIX']}",
235                 "LISTSUFFIX"     : "",
236                 "LISTFLAGS"      : "",
237                 "LISTEXTRACTOR"  : None
238             },
239
240             "TARBZ" : {
241                 "PRIORITY"       : 0,
242                 "SUFFIX"         : [".tar.bz", ".tbz", ".tar.bz2", ".tar.bzip2", ".tar.bzip"],
243                 "EXTRACTSUFFIX"  : "",
244                 "EXTRACTFLAGS"   : "",
245                 "EXTRACTCMD"     : "${UNPACK['EXTRACTOR']['TARBZ']['RUN']} ${UNPACK['EXTRACTOR']['TARBZ']['EXTRACTFLAGS']} $SOURCE ${UNPACK['EXTRACTOR']['TARBZ']['EXTRACTSUFFIX']}",
246                 "RUN"            : "",
247                 "LISTCMD"        : "${UNPACK['EXTRACTOR']['TARBZ']['RUN']} ${UNPACK['EXTRACTOR']['TARBZ']['LISTFLAGS']} $SOURCE ${UNPACK['EXTRACTOR']['TARBZ']['LISTSUFFIX']}",
248                 "LISTSUFFIX"     : "",
249                 "LISTFLAGS"      : "",
250                 "LISTEXTRACTOR"  : None
251             },
252
253             "BZIP" : {
254                 "PRIORITY"       : 1,
255                 "SUFFIX"         : [".bz", "bzip", ".bz2", ".bzip2"],
256                 "EXTRACTSUFFIX"  : "",
257                 "EXTRACTFLAGS"   : "",
258                 "EXTRACTCMD"     : "${UNPACK['EXTRACTOR']['BZIP']['RUN']} ${UNPACK['EXTRACTOR']['BZIP']['EXTRACTFLAGS']} $SOURCE ${UNPACK['EXTRACTOR']['BZIP']['EXTRACTSUFFIX']}",
259                 "RUN"            : "",
260                 "LISTCMD"        : "${UNPACK['EXTRACTOR']['BZIP']['RUN']} ${UNPACK['EXTRACTOR']['BZIP']['LISTFLAGS']} $SOURCE ${UNPACK['EXTRACTOR']['BZIP']['LISTSUFFIX']}",
261                 "LISTSUFFIX"     : "",
262                 "LISTFLAGS"      : "",
263                 "LISTEXTRACTOR"  : None
264             },
265
266             "GZIP" : {
267                 "PRIORITY"       : 1,
268                 "SUFFIX"         : [".gz", ".gzip"],
269                 "EXTRACTSUFFIX"  : "",
270                 "EXTRACTFLAGS"   : "",
271                 "EXTRACTCMD"     : "${UNPACK['EXTRACTOR']['GZIP']['RUN']} ${UNPACK['EXTRACTOR']['GZIP']['EXTRACTFLAGS']} $SOURCE ${UNPACK['EXTRACTOR']['GZIP']['EXTRACTSUFFIX']}",
272                 "RUN"            : "",
273                 "LISTCMD"        : "${UNPACK['EXTRACTOR']['GZIP']['RUN']} ${UNPACK['EXTRACTOR']['GZIP']['LISTFLAGS']} $SOURCE ${UNPACK['EXTRACTOR']['GZIP']['LISTSUFFIX']}",
274                 "LISTSUFFIX"     : "",
275                 "LISTFLAGS"      : "",
276                 "LISTEXTRACTOR"  : None
277             },
278
279             "TAR" : {
280                 "PRIORITY"       : 1,
281                 "SUFFIX"         : [".tar"],
282                 "EXTRACTSUFFIX"  : "",
283                 "EXTRACTFLAGS"   : "",
284                 "EXTRACTCMD"     : "${UNPACK['EXTRACTOR']['TAR']['RUN']} ${UNPACK['EXTRACTOR']['TAR']['EXTRACTFLAGS']} $SOURCE ${UNPACK['EXTRACTOR']['TAR']['EXTRACTSUFFIX']}",
285                 "RUN"            : "",
286                 "LISTCMD"        : "${UNPACK['EXTRACTOR']['TAR']['RUN']} ${UNPACK['EXTRACTOR']['TAR']['LISTFLAGS']} $SOURCE ${UNPACK['EXTRACTOR']['TAR']['LISTSUFFIX']}",
287                 "LISTSUFFIX"     : "",
288                 "LISTFLAGS"      : "",
289                 "LISTEXTRACTOR"  : None
290             },
291
292             "ZIP" : {
293                 "PRIORITY"       : 1,
294                 "SUFFIX"         : [".zip"],
295                 "EXTRACTSUFFIX"  : "",
296                 "EXTRACTFLAGS"   : "",
297                 "EXTRACTCMD"     : "${UNPACK['EXTRACTOR']['ZIP']['RUN']} ${UNPACK['EXTRACTOR']['ZIP']['EXTRACTFLAGS']} $SOURCE ${UNPACK['EXTRACTOR']['ZIP']['EXTRACTSUFFIX']}",
298                 "RUN"            : "",
299                 "LISTCMD"        : "${UNPACK['EXTRACTOR']['ZIP']['RUN']} ${UNPACK['EXTRACTOR']['ZIP']['LISTFLAGS']} $SOURCE ${UNPACK['EXTRACTOR']['ZIP']['LISTSUFFIX']}",
300                 "LISTSUFFIX"     : "",
301                 "LISTFLAGS"      : "",
302                 "LISTEXTRACTOR"  : None
303             }
304         }
305     }
306
307     # read tools for Windows system
308     if env["PLATFORM"] <> "darwin" and "win" in env["PLATFORM"] :
309
310         if env.WhereIs('7z', env.get('PATH')):
311             toolset["EXTRACTOR"]["TARGZ"]["RUN"]           = "7z"
312             toolset["EXTRACTOR"]["TARGZ"]["LISTEXTRACTOR"] = __fileextractor_win_7zip
313             toolset["EXTRACTOR"]["TARGZ"]["LISTFLAGS"]     = "x"
314             toolset["EXTRACTOR"]["TARGZ"]["LISTSUFFIX"]    = "-so -y | ${UNPACK['EXTRACTOR']['TARGZ']['RUN']} l -sii -ttar -y -so"
315             toolset["EXTRACTOR"]["TARGZ"]["EXTRACTFLAGS"]  = "x"
316             toolset["EXTRACTOR"]["TARGZ"]["EXTRACTSUFFIX"] = "-so -y | ${UNPACK['EXTRACTOR']['TARGZ']['RUN']} x -sii -ttar -y -o${UNPACK['EXTRACTDIR']}"
317
318             toolset["EXTRACTOR"]["TARBZ"]["RUN"]           = "7z"
319             toolset["EXTRACTOR"]["TARBZ"]["LISTEXTRACTOR"] = __fileextractor_win_7zip
320             toolset["EXTRACTOR"]["TARBZ"]["LISTFLAGS"]     = "x"
321             toolset["EXTRACTOR"]["TARBZ"]["LISTSUFFIX"]    = "-so -y | ${UNPACK['EXTRACTOR']['TARGZ']['RUN']} l -sii -ttar -y -so"
322             toolset["EXTRACTOR"]["TARBZ"]["EXTRACTFLAGS"]  = "x"
323             toolset["EXTRACTOR"]["TARBZ"]["EXTRACTSUFFIX"] = "-so -y | ${UNPACK['EXTRACTOR']['TARGZ']['RUN']} x -sii -ttar -y -o${UNPACK['EXTRACTDIR']}"
324
325             toolset["EXTRACTOR"]["BZIP"]["RUN"]            = "7z"
326             toolset["EXTRACTOR"]["BZIP"]["LISTEXTRACTOR"]  = __fileextractor_win_7zip
327             toolset["EXTRACTOR"]["BZIP"]["LISTFLAGS"]      = "l"
328             toolset["EXTRACTOR"]["BZIP"]["LISTSUFFIX"]     = "-y -so"
329             toolset["EXTRACTOR"]["BZIP"]["EXTRACTFLAGS"]   = "x"
330             toolset["EXTRACTOR"]["BZIP"]["EXTRACTSUFFIX"]  = "-y -o${UNPACK['EXTRACTDIR']}"
331
332             toolset["EXTRACTOR"]["GZIP"]["RUN"]            = "7z"
333             toolset["EXTRACTOR"]["GZIP"]["LISTEXTRACTOR"]  = __fileextractor_win_7zip
334             toolset["EXTRACTOR"]["GZIP"]["LISTFLAGS"]      = "l"
335             toolset["EXTRACTOR"]["GZIP"]["LISTSUFFIX"]     = "-y -so"
336             toolset["EXTRACTOR"]["GZIP"]["EXTRACTFLAGS"]   = "x"
337             toolset["EXTRACTOR"]["GZIP"]["EXTRACTSUFFIX"]  = "-y -o${UNPACK['EXTRACTDIR']}"
338
339             toolset["EXTRACTOR"]["ZIP"]["RUN"]             = "7z"
340             toolset["EXTRACTOR"]["ZIP"]["LISTEXTRACTOR"]   = __fileextractor_win_7zip
341             toolset["EXTRACTOR"]["ZIP"]["LISTFLAGS"]       = "l"
342             toolset["EXTRACTOR"]["ZIP"]["LISTSUFFIX"]      = "-y -so"
343             toolset["EXTRACTOR"]["ZIP"]["EXTRACTFLAGS"]    = "x"
344             toolset["EXTRACTOR"]["ZIP"]["EXTRACTSUFFIX"]   = "-y -o${UNPACK['EXTRACTDIR']}"
345
346             toolset["EXTRACTOR"]["TAR"]["RUN"]             = "7z"
347             toolset["EXTRACTOR"]["TAR"]["LISTEXTRACTOR"]   = __fileextractor_win_7zip
348             toolset["EXTRACTOR"]["TAR"]["LISTFLAGS"]       = "l"
349             toolset["EXTRACTOR"]["TAR"]["LISTSUFFIX"]      = "-y -ttar -so"
350             toolset["EXTRACTOR"]["TAR"]["EXTRACTFLAGS"]    = "x"
351             toolset["EXTRACTOR"]["TAR"]["EXTRACTSUFFIX"]   = "-y -ttar -o${UNPACK['EXTRACTDIR']}"
352         else:
353             print '''*********************** Error ************************
354 *                                                    *
355 * Please make sure that 7-zip is in your System PATH *
356 *                                                    *
357 ******************************************************
358 '''
359
360         # here can add some other Windows tools, that can handle the archive files
361         # but I don't know which ones can handle all file types
362
363
364
365     # read the tools on *nix systems and sets the default parameters
366     elif env["PLATFORM"] in ["darwin", "linux", "posix", "msys"] :
367
368         if env.WhereIs("unzip") :
369             toolset["EXTRACTOR"]["ZIP"]["RUN"]             = "unzip"
370             toolset["EXTRACTOR"]["ZIP"]["LISTEXTRACTOR"]   = __fileextractor_nix_unzip
371             toolset["EXTRACTOR"]["ZIP"]["LISTFLAGS"]       = "-l"
372             toolset["EXTRACTOR"]["ZIP"]["EXTRACTFLAGS"]    = "-oqq"
373             toolset["EXTRACTOR"]["ZIP"]["EXTRACTSUFFIX"]   = "-d ${UNPACK['EXTRACTDIR']}"
374
375         if env.WhereIs("tar") :
376             toolset["EXTRACTOR"]["TAR"]["RUN"]             = "tar"
377             toolset["EXTRACTOR"]["TAR"]["LISTEXTRACTOR"]   = __fileextractor_nix_tar
378             toolset["EXTRACTOR"]["TAR"]["LISTFLAGS"]       = "tvf"
379             toolset["EXTRACTOR"]["TAR"]["EXTRACTFLAGS"]    = "xf"
380             toolset["EXTRACTOR"]["TAR"]["EXTRACTSUFFIX"]   = "-C ${UNPACK['EXTRACTDIR']}"
381
382             toolset["EXTRACTOR"]["TARGZ"]["RUN"]           = "tar"
383             toolset["EXTRACTOR"]["TARGZ"]["LISTEXTRACTOR"] = __fileextractor_nix_tar
384             toolset["EXTRACTOR"]["TARGZ"]["EXTRACTFLAGS"]  = "xfz"
385             toolset["EXTRACTOR"]["TARGZ"]["LISTFLAGS"]     = "tvfz"
386             toolset["EXTRACTOR"]["TARGZ"]["EXTRACTSUFFIX"] = "-C ${UNPACK['EXTRACTDIR']}"
387
388             toolset["EXTRACTOR"]["TARBZ"]["RUN"]           = "tar"
389             toolset["EXTRACTOR"]["TARBZ"]["LISTEXTRACTOR"] = __fileextractor_nix_tar
390             toolset["EXTRACTOR"]["TARBZ"]["EXTRACTFLAGS"]  = "xfj"
391             toolset["EXTRACTOR"]["TARBZ"]["LISTFLAGS"]     = "tvfj"
392             toolset["EXTRACTOR"]["TARBZ"]["EXTRACTSUFFIX"] = "-C ${UNPACK['EXTRACTDIR']}"
393
394         if env.WhereIs("bzip2") :
395             toolset["EXTRACTOR"]["BZIP"]["RUN"]            = "bzip2"
396             toolset["EXTRACTOR"]["BZIP"]["EXTRACTFLAGS"]   = "-df"
397
398         if env.WhereIs("gzip") :
399             toolset["EXTRACTOR"]["GZIP"]["RUN"]            = "gzip"
400             toolset["EXTRACTOR"]["GZIP"]["LISTEXTRACTOR"]  = __fileextractor_nix_gzip
401             toolset["EXTRACTOR"]["GZIP"]["LISTFLAGS"]      = "-l"
402             toolset["EXTRACTOR"]["GZIP"]["EXTRACTFLAGS"]   = "-df"
403
404     else :
405         raise SCons.Errors.StopError("Unpack tool detection on this platform [%s] unkown" % (env["PLATFORM"]))
406
407     # the target_factory must be a "Entry", because the target list can be files and dirs, so we can not specified the targetfactory explicite
408     env.Replace(UNPACK = toolset)
409     env.AddMethod(__unpack_all, 'UnpackAll')
410
411 #    env["BUILDERS"]["UnpackAll"] = SCons.Builder.Builder( action = __action,  emitter = __emitter,  target_factory = SCons.Node.FS.Entry,  source_factory = SCons.Node.FS.File,  single_source = True,  PRINT_CMD_LINE_FUNC = __message )
412
413
414 # existing function of the builder
415 # @param env environment object
416 # @return true
417 def exists(env) :
418     return 1
419
420 Import('env')
421 generate(env)