Created
December 18, 2014 22:27
-
-
Save takluyver/6f5701e2e732ceca8bb7 to your computer and use it in GitHub Desktop.
nsigen.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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') |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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