瀏覽代碼

Allow installing extra files to other locations

Thomas Kluyver 11 年之前
父節點
當前提交
05b56d48c5
共有 3 個文件被更改,包括 46 次插入15 次删除
  1. 11 5
      nsist/__init__.py
  2. 20 1
      nsist/configreader.py
  3. 15 9
      nsist/nsiswriter.py

+ 11 - 5
nsist/__init__.py

@@ -3,6 +3,7 @@
 import errno
 import logging
 import ntpath
+import operator
 import os
 import shutil
 from subprocess import call
@@ -149,7 +150,7 @@ from {module} import {func}
             sc['icon'] = os.path.basename(sc['icon'])
             files.add(sc['icon'])
     
-        self.install_files.extend(files)
+        self.install_files.extend([(f, '$INSTDIR') for f in files])
     
     def prepare_packages(self):
         logger.info("Copying packages into build directory...")
@@ -166,9 +167,12 @@ from {module} import {func}
         """Copy a list of files into the build directory, and add them to
         install_files or install_dirs as appropriate.
         """
-        for file in self.extra_files:
+        for file, destination in self.extra_files:
             file = file.rstrip('/\\')
             basename = os.path.basename(file)
+
+            if not destination:
+                destination = '$INSTDIR'
     
             if os.path.isdir(file):
                 target_name = pjoin(self.build_dir, basename)
@@ -177,10 +181,10 @@ from {module} import {func}
                 elif os.path.exists(target_name):
                     os.unlink(target_name)
                 shutil.copytree(file, target_name)
-                self.install_dirs.append(basename)
+                self.install_dirs.append((basename, destination))
             else:
                 shutil.copy2(file, self.build_dir)
-                self.install_files.append(basename)
+                self.install_files.append((basename, destination))
     
     def write_nsi(self):
         nsis_writer = NSISFileWriter(self.nsi_template, installerbuilder=self,
@@ -195,6 +199,8 @@ from {module} import {func}
             )
 
         logger.info('Writing NSI file to %s', self.nsi_file)
+        # Sort by destination directory, so we can group them effectively
+        self.install_files.sort(key=operator.itemgetter(1))
         nsis_writer.write(self.nsi_file)    
 
     def run_nsis(self):
@@ -276,7 +282,7 @@ def main(argv=None):
         icon = appcfg.get('icon', DEFAULT_ICON),
         shortcuts = shortcuts,
         packages = cfg.get('Include', 'packages', fallback='').splitlines(),
-        extra_files = cfg.get('Include', 'files', fallback='').splitlines(),
+        extra_files = configreader.read_extra_files(cfg),
         py_version = cfg.get('Python', 'version', fallback=DEFAULT_PY_VERSION),
         py_bitness = cfg.getint('Python', 'bitness', fallback=DEFAULT_BITNESS),
         build_dir = cfg.get('Build', 'directory', fallback=DEFAULT_BUILD_DIR),

+ 20 - 1
nsist/configreader.py

@@ -87,7 +87,9 @@ class InvalidConfig(ValueError):
     pass
 
 def read_and_validate(config_file):
-    config = configparser.ConfigParser()
+    # Interpolation interferes with Windows-style environment variables, so
+    # it's disabled for now.
+    config = configparser.ConfigParser(interpolation=None)
     config.read(config_file)
     for section in config.sections():
         if section in CONFIG_VALIDATORS:
@@ -103,6 +105,23 @@ def read_and_validate(config_file):
             raise InvalidConfig(err_msg)    
     return config
 
+def read_extra_files(cfg):
+    """Read the list of extra files from the config file.
+    
+    Returns a list of 2-tuples: (file, destination_directory), which can be
+    passed as the ``extra_files`` parameter to :class:`nsist.InstallerBuilder`.
+    """
+    lines = cfg.get('Include', 'files', fallback='').splitlines()
+    pairs = []
+    for line in lines:
+        if '>' in line:
+            file, dest = line.rsplit('>', 1)
+            pairs.append((file.strip(), dest.strip()))
+        else:
+            pairs.append((line, '$INSTDIR'))
+
+    return pairs
+
 def read_shortcuts_config(cfg):
     """Read and verify the shortcut definitions from the config file.
     

+ 15 - 9
nsist/nsiswriter.py

@@ -1,3 +1,6 @@
+import itertools
+import operator
+import ntpath
 import re
 import sys
 
@@ -52,7 +55,6 @@ class NSISFileWriter(object):
         """
         for name, value in self.definitions.items():
             f.write('!define {} "{}"\n'.format(name, value))
-    
 
     # Template fillers
     # ----------------
@@ -60,12 +62,16 @@ class NSISFileWriter(object):
     # These return an iterable of lines to fill after a given template field
 
     def files_install(self):
-        for file in self.installerbuilder.install_files:
-            yield 'File "{}"'.format(file)
+        for destination, group in itertools.groupby(
+                    self.installerbuilder.install_files, operator.itemgetter(1)):
+            yield 'SetOutPath "{}"'.format(destination)
+            for file, _ in group:
+                yield 'File "{}"'.format(file)
+        yield 'SetOutPath "$INSTDIR"'
 
     def dirs_install(self):
-        for dir in self.installerbuilder.install_dirs:
-            yield 'SetOutPath "$INSTDIR\{}"'.format(dir)
+        for dir, destination in self.installerbuilder.install_dirs:
+            yield 'SetOutPath "{}"'.format(ntpath.join(destination, dir))
             yield 'File /r "{}\*.*"'.format(dir)
         yield 'SetOutPath "$INSTDIR"'
     
@@ -90,12 +96,12 @@ class NSISFileWriter(object):
         yield 'SetOutPath "$INSTDIR"'
 
     def files_uninstall(self):
-        for file in self.installerbuilder.install_files:
-            yield 'Delete "$INSTDIR\{}"'.format(file)
+        for file, destination in self.installerbuilder.install_files:
+            yield 'Delete "{}"'.format(ntpath.join(destination, file))
 
     def dirs_uninstall(self):
-        for dir in self.installerbuilder.install_dirs:
-            yield 'RMDir /r "$INSTDIR\{}"'.format(dir)
+        for dir, destination in self.installerbuilder.install_dirs:
+            yield 'RMDir /r "{}"'.format(ntpath.join(destination, dir))
     
     def shortcuts_uninstall(self):
         shortcuts = self.installerbuilder.shortcuts