/[ascend]/trunk/scons/nsis.py
ViewVC logotype

Annotation of /trunk/scons/nsis.py

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2609 - (hide annotations) (download) (as text)
Thu Apr 26 17:45:25 2012 UTC (11 years, 5 months ago) by jpye
File MIME type: text/x-python
File size: 5952 byte(s)
slightly improved approach for WOW32.
1 jpye 1408 # NSIS Support for SCons
2     # Written by Mike Elkins, January 2004
3     # Provided 'as-is', it works for me!
4    
5 jpye 2609
6 jpye 1408 """
7     This tool provides SCons support for the Nullsoft Scriptable Install System
8     a windows installer builder available at http://nsis.sourceforge.net/home
9    
10    
11     To use it you must copy this file into the scons/SCons/Tools directory or use
12     the tooldir arg in the Tool function and put a line like 'env.Tool("NSIS")'
13     into your file. Then you can do 'env.Installer("foobar")' which will read foobar.nsi and
14     create dependencies on all the files you put into your installer, so that if
15     anything changes your installer will be rebuilt. It also makes the target
16     equal to the filename you specified in foobar.nsi. Wildcards are handled correctly.
17    
18     In addition, if you set NSISDEFINES to a dictionary, those variables will be passed
19     to NSIS.
20     """
21    
22 jpye 2609
23    
24 jpye 1408 import SCons.Builder
25     import SCons.Util
26     import SCons.Scanner
27 jpye 2609 import os.path
28     import glob
29 jpye 1408
30     def nsis_parse( sources, keyword, multiple ):
31     """
32     A function that knows how to read a .nsi file and figure
33     out what files are referenced, or find the 'OutFile' line.
34    
35    
36     sources is a list of nsi files.
37     keyword is the command ('File' or 'OutFile') to look for
38     multiple is true if you want all the args as a list, false if you
39     just want the first one.
40     """
41     stuff = []
42     for s in sources:
43     c = s.get_contents()
44     for l in c.split('\n'):
45     semi = l.find(';')
46     if (semi != -1):
47     l = l[:semi]
48     hash = l.find('#')
49     if (hash != -1):
50     l = l[:hash]
51     # Look for the keyword
52     l = l.strip()
53     spl = l.split(None,1)
54     if len(spl) > 1:
55     if spl[0].capitalize() == keyword.capitalize():
56     arg = spl[1]
57     if arg.startswith('"') and arg.endswith('"'):
58     arg = arg[1:-1]
59     if multiple:
60     stuff += [ arg ]
61     else:
62     return arg
63     return stuff
64    
65    
66     def nsis_path( filename, nsisdefines, rootdir ):
67     """
68     Do environment replacement, and prepend with the SCons root dir if
69     necessary
70     """
71     # We can't do variables defined by NSIS itself (like $INSTDIR),
72     # only user supplied ones (like ${FOO})
73     varPos = filename.find('${')
74     while varPos != -1:
75     endpos = filename.find('}',varPos)
76     assert endpos != -1
77     if not nsisdefines.has_key(filename[varPos+2:endpos]):
78     raise KeyError ("Could not find %s in NSISDEFINES" % filename[varPos+2:endpos])
79     val = nsisdefines[filename[varPos+2:endpos]]
80     if type(val) == list:
81     if varPos != 0 or endpos+1 != len(filename):
82     raise Exception("Can't use lists on variables that aren't complete filenames")
83     return val
84     filename = filename[0:varPos] + val + filename[endpos+1:]
85     varPos = filename.find('${')
86     return filename
87    
88    
89     def nsis_scanner( node, env, path ):
90     """
91     The scanner that looks through the source .nsi files and finds all lines
92     that are the 'File' command, fixes the directories etc, and returns them.
93     """
94     nodes = node.rfile()
95     if not node.exists():
96     return []
97     nodes = []
98     source_dir = node.get_dir()
99     for include in nsis_parse([node],'file',1):
100     exp = nsis_path(include,env['NSISDEFINES'],source_dir)
101     if type(exp) != list:
102     exp = [exp]
103     for p in exp:
104     for filename in glob.glob( os.path.abspath(
105     os.path.join(str(source_dir),p))):
106     # Why absolute path? Cause it breaks mysteriously without it :(
107     nodes.append(filename)
108     return nodes
109    
110    
111     def nsis_emitter( source, target, env ):
112     """
113     The emitter changes the target name to match what the command actually will
114     output, which is the argument to the OutFile command.
115     """
116     nsp = nsis_parse(source,'outfile',0)
117     if not nsp:
118     return (target,source)
119     x = (
120     nsis_path(nsp,env['NSISDEFINES'],''),
121     source)
122     return x
123    
124     def quoteIfSpaced(text):
125     if ' ' in text:
126     return '"'+text+'"'
127     else:
128     return text
129    
130     def toString(item,env):
131     if type(item) == list:
132     ret = ''
133     for i in item:
134     if ret:
135     ret += ' '
136     val = toString(i,env)
137     if ' ' in val:
138     val = "'"+val+"'"
139     ret += val
140     return ret
141     else:
142     # For convienence, handle #s here
143     if str(item).startswith('#'):
144     item = env.File(item).get_abspath()
145     return str(item)
146    
147     def runNSIS(source,target,env,for_signature):
148     ret = env['NSIS']+" "
149     if env.has_key('NSISFLAGS'):
150     for flag in env['NSISFLAGS']:
151     ret += flag
152     ret += ' '
153     if env.has_key('NSISDEFINES'):
154     for d in env['NSISDEFINES']:
155     ret += '/D'+d
156     if env['NSISDEFINES'][d]:
157     ret +='='+quoteIfSpaced(toString(env['NSISDEFINES'][d],env))
158     ret += ' '
159     for s in source:
160     ret += quoteIfSpaced(str(s))
161     return ret
162    
163     def generate(env):
164     """
165     This function adds NSIS support to your environment.
166     """
167     env['BUILDERS']['Installer'] = SCons.Builder.Builder(generator=runNSIS,
168     src_suffix='.nsi',
169     emitter=nsis_emitter)
170     env.Append(SCANNERS = SCons.Scanner.Scanner( function = nsis_scanner,
171     skeys = ['.nsi']))
172     if not env.has_key('NSISDEFINES'):
173     env['NSISDEFINES'] = {}
174     env['NSIS'] = find_nsis(env)
175    
176     def find_nsis(env):
177     """
178     Try and figure out if NSIS is installed on this machine, and if so,
179     where.
180     """
181     if SCons.Util.can_read_reg:
182     # If we can read the registry, get the NSIS command from it
183     try:
184 jpye 2609 # 131609 is KEY_READ | KEY_WOW64_32KEY since NSIS is 32-bit
185     k = SCons.Util.RegOpenKeyEx(SCons.Util.hkey_mod.HKEY_LOCAL_MACHINE,'SOFTWARE\\NSIS',0,131609)
186     val, tok = SCons.Util.RegQueryValueEx(k,None)
187     ret = val + os.path.sep + 'makensis.exe'
188     if os.path.exists(ret):
189     return '"' + ret + '"'
190     else:
191     return None
192 jpye 1408 except:
193     pass # Couldn't find the key, just act like we can't read the registry
194     # Hope it's on the path
195     return env.WhereIs('makensis.exe')
196    
197     def exists(env):
198     """
199     Is NSIS findable on this machine?
200     """
201     if find_nsis(env) != None:
202     return 1
203 johnpye 913 return 0

john.pye@anu.edu.au
ViewVC Help
Powered by ViewVC 1.1.22