Skip to content

Instantly share code, notes, and snippets.

@takluyver
Created December 18, 2014 22:27
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save takluyver/6f5701e2e732ceca8bb7 to your computer and use it in GitHub Desktop.
Save takluyver/6f5701e2e732ceca8bb7 to your computer and use it in GitHub Desktop.
nsigen.py
class Comment(object):
def __init__(self, content):
self.content = content
def generate(self, state=None):
yield "; " + self.content
def _should_quote(arg):
return (' ' in arg) or ('$' in arg)
def assemble_line(parts):
quoted_parts = [("%s" % p) if _should_quote(p) else p
for p in parts if p is not None]
return ' '.join(quoted_parts)
class Instruction(object):
def __init__(self, name, *parameters):
self.name = name
self.parameters = parameters
def generate(self, state=None):
yield assemble_line([self.name] + list(self.parameters))
def make_instruction_class(name):
def __init__(self, *parameters):
Instruction.__init__(self, name, *parameters)
return type(name, (Instruction,), {'__init__': __init__})
File = make_instruction_class('File')
class Scope(object):
def __init__(self, contents=None):
self.contents = contents or []
def generate_children(self, state=None):
for child in self.contents:
for line in child.generate(state):
yield ' ' + line
class Section(Scope):
def __init__(self, name=None, index_var=None, selected=True, contents=None):
super(Section, self).__init__(contents)
self.name = name
self.index_var = index_var
self.selected = selected
def generate(self, state=None):
parts = ['Section',
None if self.selected else '/o',
self.name, self.index_var]
yield assemble_line(parts)
for line in self.generate_children(state):
yield line
yield 'SectionEnd'
yield '' # Blank line after a section
class SectionGroup(Scope):
def __init__(self, name, index_var=None, expanded=False, contents=None):
super(SectionGroup, self).__init__(contents)
self.name = name
self.expanded = expanded
self.index_var = index_var
def generate(self, state=None):
parts = ['SectionGroup',
'/e' if self.expanded else None,
self.name, self.index_var]
yield assemble_line(parts)
for line in self.generate_children(state):
yield line
yield 'SectionGroupEnd'
class Function(Scope):
def __init__(self, name, contents=None):
super(Function, self).__init__(contents)
self.name = name
def generate(self, state=None):
yield assemble_line(['Function', self.name])
for line in self.generate_children(state):
yield
class Label(object):
def __init__(self, name):
self.name = name
def generate(self, scope):
yield self.name + ":"
class Conditional(object):
# e.g. IfSilent, IntCmp
def __init__(self, name, *parameters, ifbody=None, elsebody=None):
self.name = name
self.parameters = parameters
self.ifbody = ifbody or []
self.elsebody = elsebody or []
def generate(self, state):
if_counter = state.get('if_counter', 1)
state['if_counter'] = if_counter + 1
yield assemble_line([self.name] + self.parameters + ["0",
("else%d" if self.elsebody else "endif%d") % if_counter])
for child in self.ifbody:
for line in child.generate(state):
yield " " + line
if self.elsebody:
yield (" Goto endif%d" % if_counter)
yield ("else%d:" % if_counter)
for child in self.elsebody:
for line in child.generate(state):
yield " " + line
yield ("endif%d:" % if_counter)
class CompilerCommand(object):
def __init__(self, name, *parameters):
self.name = name
self.parameters = parameters
def generate(self, state=None):
yield "!" + assemble_line([self.name] + list(self.parameters))
class CompilerConditional(object):
# ifdef etc
def __init__(self, name, parameters, ifbody=None, elsebody=None):
self.name = name
self.parameters = parameters
self.ifbody = ifbody or []
self.elsebody = elsebody or []
def generate(self, state=None):
yield "!" + assemble_line([self.name] + self.parameters)
for child in self.ifbody:
for line in child.generate(state):
yield ' ' + line
if self.elsebody:
yield "!else"
for child in self.elsebody:
for line in child.generate(state):
yield ' ' + line
yield "!endif"
def make_compiler_command_class(name):
def __init__(self, *parameters):
CompilerCommand.__init__(self, name, *parameters)
return type(name, (CompilerCommand,), {'__init__': __init__})
define = make_compiler_command_class('define')
insertmacro = make_compiler_command_class('insertmacro')
class Macro(Scope):
def __init__(self, name, parameters):
super(Macro, self).__init__()
self.name = name
self.parameters = parameters
def generate(self, state=None):
yield "!" + assemble_line([self.name] + self.parameters)
for line in self.generate_children(state):
yield " " + line
yield "!macroend"
class Document(object):
def __init__(self, children=None):
self.children = children or []
def generate(self, state):
for child in self.children:
for line in child.generate(state):
yield line
def write(self, fileobj_or_path):
if isinstance(fileobj_or_path, str):
with open(fileobj_or_path, 'w') as f:
return self.write(f)
for line in self.generate(state={}):
fileobj_or_path.write(line + '\n')
from nsigen import *
Document([
Comment('Definitions will be added above'),
Instruction('SetCompressor', 'lzma'),
Instruction('RequestExecutionLevel', 'admin'),
Comment("Modern UI installer stuff"),
CompilerCommand("include", "MUI2.nsh"),
define("MUI_ABORTWARNING"),
define("MUI_ICON", "${NSISDIR}\Contrib\Graphics\Icons\modern-install.ico"),
Comment("UI pages"),
insertmacro("MUI_PAGE_WELCOME"),
insertmacro("MUI_PAGE_COMPONENTS"),
insertmacro("MUI_PAGE_DIRECTORY"),
insertmacro("MUI_PAGE_INSTFILES"),
insertmacro("MUI_PAGE_FINISH"),
insertmacro("MUI_LANGUAGE", "English"),
Comment("MUI end --------"),
Instruction("Name", "${PRODUCT_NAME} ${PRODUCT_VERSION}"),
Instruction("OutFile", "${INSTALLER_NAME}"),
Instruction("InstallDir", "$PROGRAMFILES${BITNESS}\${PRODUCT_NAME}"),
Instruction("ShowInstDetails", "show"),
Section("-SETTINGS", contents=[
Instruction("SetOutPath", "$INSTDIR"),
Instruction("SetOverwrite", "ifnewer"),
]),
Section("Python ${PY_VERSION}", index_var="sec_py", contents=[
File("python-${PY_VERSION}${ARCH_TAG}.msi"),
Instruction("DetailPrint", "Installing Python ${PY_MAJOR_VERSION}, ${BITNESS} bit"),
Instruction("ExecWait", 'msiexec /i "$INSTDIR\python-${PY_VERSION}${ARCH_TAG}.msi" \
/qb ALLUSERS=1 TARGETDIR="$COMMONFILES${BITNESS}\Python\${PY_MAJOR_VERSION}"'),
Instruction("Delete", "$INSTDIR\python-${PY_VERSION}${ARCH_TAG}.msi"),
]),
]).write("sample.nsi")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment