takluyver / pynsist

Build Windows installers for Python applications
https://pynsist.readthedocs.io/
Other
896 stars 119 forks source link

Adding files with the same name #156

Closed JoshMayberry closed 6 years ago

JoshMayberry commented 6 years ago

The Issue Pynsist places all non-directory files in extra_files in the root folder. This means that if two files have the same name, one will overwrite the other.

Take the following case:

extra_files = [("folder1/__init__.py", "docs\\folder1"), ("folder2/__init__.py", "docs\\folder2")]

This will become the following in the .nsi file:

  ; Install files
    SetOutPath "$INSTDIR\\docs\\folder1"
      File "__init__.py"
    SetOutPath "$INSTDIR\\docs\\folder2"
      File "__init__.py"

This will copy the same file to both folders, because the file sits in the root directory of the build directory.

Proposed Solution Perhaps, files for the Install files portion of the .nsi file should become the following:

  ; Install files
    SetOutPath "$INSTDIR\\docs\\folder1"
      File "docs\\folder1\\__init__.py"
    SetOutPath "$INSTDIR\\docs\\folder2"
      File "docs\\folder2\\__init__.py"

The files should be stored in the build directory in the same structure they will be in the install directory

JoshMayberry commented 6 years ago

Alternate Solution Allow the user to rename the files that go into the build directory. Perhaps something like this:

extra_files = [("folder1/__init__.py", "docs\\folder1", "folder1_init.py"), ("folder2/__init__.py", "docs\\folder2", "folder2_init.py")]

Which would copy the files in argument 0 and rename them in the build directory as what is in argument 2. This would then become the following in the .nsi file:

 ; Install files
    SetOutPath "$INSTDIR\\docs\\folder1"
      File "folder1_init.py"
    SetOutPath "$INSTDIR\\docs\\folder2"
      File "folder2_init.py"

I created a pull request with a working example that does this: https://github.com/takluyver/pynsist/pull/157

takluyver commented 6 years ago

Thanks! And sorry it's taken me a while to look at it.

I'm not keen on the solution that requires the user specify a name for the file in the build directory - it shouldn't be up to the user to do this, and it's awkward to have three names per file in the installer.cfg file.

The 'build directory like install' option looks promising, but I see a problem: there are multiple root directories that installed files can go into. E.g. if you have separate files to install at $INSTDIR\file.txt, $APPDATA\file.txt and C:\file.txt, how do you arrange those in the build directory?

One obvious way to tackle this from a computer perspective is to name each file in the build directory with a hash of its contents, like a6bea03f5212f99efc8fbf9462c2a382fd.dat. This effectively guarantees you a unique name for each different file you want to store. The downside is that it makes debugging harder, because the filenames are meaningless to humans.

The best option here might be for pynsist to keep track of the filenames it uses, and cal the next __init__.py files names like __init__.1.py, __init__.2.py etc. That way you still have a pretty good idea what each file is from the name.

JoshMayberry commented 6 years ago

I like your solution. Would it be possible to rename files like init.py.1, init.py.2 instead? I think the code would be easier to write, considering you might have files that end with .tar.gz.

takluyver commented 6 years ago

It's possible, but I think the .1.py is preferable, because lots of things use the extension to guess what kind of file it is. I think it's worth making the code a little bit more complicated to have the extensions at the end.

takluyver commented 6 years ago

e.g. Path.suffixes and Path.stem might be able to help with that.