From 08b98739f76e796574e5d812f75ed9d95f84e212 Mon Sep 17 00:00:00 2001 From: "Veronica K. B. Olsen" <1619840+vkbo@users.noreply.github.com> Date: Wed, 3 Feb 2021 21:37:35 +0100 Subject: [PATCH 1/7] Fix typo --- README.md | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) diff --git a/README.md b/README.md index e0e3ad27..e6e563ef 100644 --- a/README.md +++ b/README.md @@ -40,7 +40,6 @@ Contributions to this project are welcome. However, please read the [Contributing Guide](https://github.com/vkbo/novelWriter/blob/main/CONTRIBUTING.md) before submitting larger additions ot changes to this project. - # Key Features Some features of novelWriter are listed below. Consult the @@ -82,7 +81,6 @@ with limitations to formatting. The HTML format is well suited for file conversion tools and import into other text editors. - ### Colour Themes The editor has syntax highlighting for the features it supports, and includes a set of different @@ -107,7 +105,6 @@ project tree. These are mostly to help the user track what they contain, but the impact on the format of the exported document. See the [documentation](https://novelwriter.readthedocs.io) for further details. - ### Project Notes Supporting note files can be added for the story plot, characters, locations, story timeline, etc. @@ -122,13 +119,11 @@ connects to the plot, and which characters, etc. occur in them. In addition, the are clickable in the document view pane, and control-clickable in the editor. They make it possible to quickly navigate between the documents while editing. - # Installing and Running For install instructions, please check the [documentation](https://novelwriter.readthedocs.io/) in the [Getting Started](https://novelwriter.readthedocs.io/en/latest/int_started.html) section. - ## TLDR Instructions If you want to run novelWriter directly from the source code, you must run the `novelWriter.py` @@ -138,7 +133,6 @@ file from command line. For installations on Linux, macOS or Windows, see below. below on some systems. You may also want to add the `--user` flag for `pip` to install in your user space only. - ### Install from PyPi novelWriter is available on [pypi.org](https://pypi.org/project/novelWriter/), and can be installed @@ -158,7 +152,6 @@ novelWriter Make sure the install location for pip is in your PATH variable. This is not always the case by default. - ### Setup on Linux If you're installing from source, the following commands will set up novelWriter on Linux: @@ -171,7 +164,6 @@ python setup.py xdg-install This should make novelWriter available as a regular application on your system, with a launceher icon, and file association with novelWriter project files. - ### Setup on macOS If you're installing from source, the following commands will set up novelWriter on macOS: @@ -188,7 +180,6 @@ line with: novelWriter ``` - ### Setup on Windows For Windows, first ensure that you have Python installed. If not, get it from @@ -199,8 +190,7 @@ Then, download the `novelWriter-x.y.z-minimal.zip` file, where `x.y.z` is the ve the [releases](https://github.com/vkbo/novelWriter/releases) page. You can extract it to wherever you want to keep novelWriter on your PC, and run the `setup_windows.bat` file in it (double-clicking it should work). This will install the necessary dependencies from -[pypi,org](https://pypi.org/) and create desktop and start menu icons. - +[pypi.org](https://pypi.org/) and create desktop and start menu icons. ## Debugging @@ -208,7 +198,6 @@ If you need to debug novelWriter, you must run it from command line. It takes a which can be listed with the switch `--help`. The `--info`, `--debug` or `--verbose` flags are particularly useful for increasing logging output for debugging. - # Licenses This is Open Source software, and novelWriter is licensed under GPLv3. See the @@ -235,7 +224,6 @@ Bundled assets have the following licenses: the main repo is available at [sdras/night-owl-vscode-theme](https://github.com/sdras/night-owl-vscode-theme). - # Screenshot **novelWriter with default system theme:** From 637c05466af238a4f60a254edeb3f170d1771e03 Mon Sep 17 00:00:00 2001 From: "Veronica K. B. Olsen" <1619840+vkbo@users.noreply.github.com> Date: Wed, 3 Feb 2021 21:45:22 +0100 Subject: [PATCH 2/7] Compress minimal zip file --- setup.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/setup.py b/setup.py index 99066647..9eb750c3 100755 --- a/setup.py +++ b/setup.py @@ -238,7 +238,7 @@ def makeMinimalPackage(): """Pack the core source file in a single zip file. """ from nw import __version__ - from zipfile import ZipFile + from zipfile import ZipFile, ZIP_DEFLATED # Make sample.zip first try: @@ -270,7 +270,7 @@ def makeMinimalPackage(): "setup_windows.bat", ] - with ZipFile(outFile, "w") as zipObj: + with ZipFile(outFile, "w", compression=ZIP_DEFLATED, compresslevel=9) as zipObj: for nRoot, _, nFiles in os.walk("nw"): if nRoot.endswith("__pycache__"): print("Skipping: %s" % nRoot) From ab0626720a1cf76b63a1f490ff962415bd0306fb Mon Sep 17 00:00:00 2001 From: "Veronica K. B. Olsen" <1619840+vkbo@users.noreply.github.com> Date: Thu, 4 Feb 2021 23:16:14 +0100 Subject: [PATCH 3/7] Add setup files to the minimal zip packager in setup.py --- setup.py | 5 +++++ setup/README.md | 13 +++++++++---- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/setup.py b/setup.py index 9eb750c3..2d00ea6d 100755 --- a/setup.py +++ b/setup.py @@ -271,6 +271,11 @@ def makeMinimalPackage(): ] with ZipFile(outFile, "w", compression=ZIP_DEFLATED, compresslevel=9) as zipObj: + for nRoot, _, nFiles in os.walk("setup"): + print("Compressing: %s [%d files]" % (nRoot, len(nFiles))) + for aFile in nFiles: + zipObj.write(os.path.join(nRoot, aFile)) + for nRoot, _, nFiles in os.walk("nw"): if nRoot.endswith("__pycache__"): print("Skipping: %s" % nRoot) diff --git a/setup/README.md b/setup/README.md index 45aaf397..e49a670e 100644 --- a/setup/README.md +++ b/setup/README.md @@ -10,7 +10,7 @@ options: ### General -`help` – Print the help message +`help` – Print the help message. `pip` – Install all package dependencies for novelWriter using pip. @@ -26,14 +26,17 @@ creating sample projects in the in-app New Project Wizard. ### Python Packaging +`minimal-zip` – Creates a minimal zip file of the core application without all +the other source files. + `pack-pyz` – Creates a pyz package in a folder with all dependencies using the -zipapp tool. This option is intended for Windows deployment. +zipapp tool. On Windows, python embeddable is added to the folder. `freeze` – Freeze the package and produces a folder with all dependencies using the pyinstaller tool. This option is not designed for a specific OS. `onefile` – Build a standalone executable with all dependencies bundled using -the pyinstaller tool. Implies `freeze`, cannot be used with `setup-exe` +the pyinstaller tool. Implies `freeze`, cannot be used with `setup-exe`. ### General Installers @@ -44,7 +47,9 @@ install. `xdg-install` – Install launcher and icons for freedesktop systems. Run as root or with sudo for system-wide install, or as user for single user install. -### Windows Installers +`win-install` – Install desktop and start menu icons for Windows systems. + +### "Windows Installers `setup-exe` – Build a Windows installer from a pyinstaller freeze package using Inno Setup. This option automatically disables `onefile`. From 020f1226475d64da7d7c08ded8e498e368f050f5 Mon Sep 17 00:00:00 2001 From: "Veronica K. B. Olsen" <1619840+vkbo@users.noreply.github.com> Date: Thu, 4 Feb 2021 23:16:31 +0100 Subject: [PATCH 4/7] Add size 192 scaled icons --- setup/icons/scaled/icon-novelwriter-192.png | Bin 0 -> 13138 bytes setup/icons/scaled/mime-novelwriter-192.png | Bin 0 -> 10633 bytes 2 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 setup/icons/scaled/icon-novelwriter-192.png create mode 100644 setup/icons/scaled/mime-novelwriter-192.png diff --git a/setup/icons/scaled/icon-novelwriter-192.png b/setup/icons/scaled/icon-novelwriter-192.png new file mode 100644 index 0000000000000000000000000000000000000000..c416142693a228fea532248d7e5369007f395c1b GIT binary patch literal 13138 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%0DnAZ?OF(9IK|w4*cUB15-0H6hY<8o*h? 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 Date: Fri, 5 Feb 2021 16:52:23 +0100 Subject: [PATCH 5/7] Add flag to tailor minimal zip package to different OSes --- novelWriter.py | 11 ++++---- novelWriter.pyw | 15 ----------- setup.py | 71 ++++++++++++++++++++++++++++++++++--------------- 3 files changed, 55 insertions(+), 42 deletions(-) delete mode 100644 novelWriter.pyw diff --git a/novelWriter.py b/novelWriter.py index 58af6c06..4f609f24 100755 --- a/novelWriter.py +++ b/novelWriter.py @@ -1,11 +1,10 @@ #!/usr/bin/env python3 # -*- coding: utf-8 -*- """ -novelWriter – Terminal Start Script -=================================== -The main start script for the terminal +novelWriter – Start Script +========================== """ - +import os import sys try: @@ -13,9 +12,11 @@ try: import PyQt5.QtGui # noqa: F401 import PyQt5.QtCore # noqa: F401 except Exception: - print("ERROR: Failed to load dependency python3-pyqt5") + print("ERROR: Failed to load dependency PyQt5") sys.exit(1) +os.curdir = os.path.abspath(os.path.dirname(__file__)) + if __name__ == "__main__": import nw nw.main(sys.argv[1:]) diff --git a/novelWriter.pyw b/novelWriter.pyw deleted file mode 100644 index 6a39bd3c..00000000 --- a/novelWriter.pyw +++ /dev/null @@ -1,15 +0,0 @@ -#!/usr/bin/env python3 -# -*- coding: utf-8 -*- -""" -novelWriter – Windows Start Script -================================== -The main start script for Windows GUI -""" - -import os - -os.curdir = os.path.abspath(os.path.dirname(__file__)) - -if __name__ == "__main__": - import nw - nw.main() diff --git a/setup.py b/setup.py index 2d00ea6d..411eab50 100755 --- a/setup.py +++ b/setup.py @@ -234,7 +234,7 @@ def buildSampleZip(): # Make Minimal Package (minimal-zip) ## -def makeMinimalPackage(): +def makeMinimalPackage(targetOS): """Pack the core source file in a single zip file. """ from nw import __version__ @@ -256,41 +256,53 @@ def makeMinimalPackage(): if not os.path.isdir("dist"): os.mkdir("dist") - outFile = os.path.join("dist", "novelWriter-%s-minimal.zip" % __version__) + if targetOS == OS_LINUX: + targName = "-linux" + elif targetOS == OS_DARWIN: + targName = "-darwin" + elif targetOS == OS_WIN: + targName = "-win" + else: + targName = "" + + outFile = os.path.join("dist", f"novelWriter-{__version__}-minimal{targName}.zip") if os.path.isfile(outFile): os.unlink(outFile) - rootFiles = [ - "LICENSE.md", - "README.md", - "CHANGELOG.md", - "novelWriter.pyw", - "requirements.txt", - "setup.py", - "setup_windows.bat", - ] + rootFiles = ["LICENSE.md", "README.md", "CHANGELOG.md", "requirements.txt", "setup.py"] with ZipFile(outFile, "w", compression=ZIP_DEFLATED, compresslevel=9) as zipObj: - for nRoot, _, nFiles in os.walk("setup"): - print("Compressing: %s [%d files]" % (nRoot, len(nFiles))) - for aFile in nFiles: - zipObj.write(os.path.join(nRoot, aFile)) + + if targetOS != OS_WIN: + for nRoot, _, nFiles in os.walk("setup"): + print("Adding Folder: %s [%d files]" % (nRoot, len(nFiles))) + for aFile in nFiles: + zipObj.write(os.path.join(nRoot, aFile)) for nRoot, _, nFiles in os.walk("nw"): if nRoot.endswith("__pycache__"): - print("Skipping: %s" % nRoot) + print("Skipping Folder: %s" % nRoot) continue - print("Compressing: %s [%d files]" % (nRoot, len(nFiles))) + print("Adding Folder: %s [%d files]" % (nRoot, len(nFiles))) for aFile in nFiles: if aFile.endswith(".pyc"): - print("Skipping: %s" % aFile) + print("Skipping File: %s" % aFile) continue zipObj.write(os.path.join(nRoot, aFile)) + if targetOS == OS_WIN: + zipObj.write("novelWriter.py", "novelWriter.pyw") + print("Adding File: novelWriter.pyw") + zipObj.write("setup_windows.bat") + print("Adding File: setup_windows.bat") + else: + zipObj.write("novelWriter.py") + print("Adding File: novelWriter.py") + for aFile in rootFiles: assert os.path.isfile(aFile) - print("Compressing: %s" % aFile) + print("Adding File: %s" % aFile) zipObj.write(aFile) print("") @@ -913,7 +925,6 @@ def innoSetup(setupType): if __name__ == "__main__": """Parse command line options and run the commands. """ - # Detect OS if sys.platform.startswith("linux"): hostOS = OS_LINUX @@ -926,6 +937,19 @@ if __name__ == "__main__": else: hostOS = OS_NONE + # Set Target OS + if "--linux" in sys.argv: + sys.argv.remove("--linux") + targetOS = OS_LINUX + elif "--darwin" in sys.argv: + sys.argv.remove("--darwin") + targetOS = OS_DARWIN + elif "--win" in sys.argv: + sys.argv.remove("--win") + targetOS = OS_WIN + else: + targetOS = hostOS + helpMsg = ( "\n" "novelWriter Setup Tool\n" @@ -934,6 +958,9 @@ if __name__ == "__main__": "This tool provides setup and build commands for installing or distibuting novelWriter\n" "as a package on Linux, Mac and Windows. The available options are as follows:\n" "\n" + "Some of the commands can be targeted towards a different OS than the host OS. To target\n" + "the command, add one of '--linux', '--darwin' or '--win'.\n" + "\n" "General:\n" "\n" " help Print the help message.\n" @@ -950,7 +977,7 @@ if __name__ == "__main__": "Python Packaging:\n" "\n" " minimal-zip Creates a minimal zip file of the core application without all the\n" - " other source files.\n" + " other source files. Accepts a target OS flag.\n" " pack-pyz Creates a pyz package in a folder with all dependencies using the\n" " zipapp tool. On Windows, python embeddable is added to the folder.\n" " freeze Freeze the package and produces a folder with all dependencies using\n" @@ -1015,7 +1042,7 @@ if __name__ == "__main__": if "minimal-zip" in sys.argv: sys.argv.remove("minimal-zip") - makeMinimalPackage() + makeMinimalPackage(targetOS) if "pack-pyz" in sys.argv: sys.argv.remove("pack-pyz") From be080b14630065dc043df361aad959b6e9862dfb Mon Sep 17 00:00:00 2001 From: "Veronica K. B. Olsen" <1619840+vkbo@users.noreply.github.com> Date: Fri, 5 Feb 2021 17:27:56 +0100 Subject: [PATCH 6/7] Remove the pyinstaller setup functions --- setup.py | 191 ++++------------------------------------ setup/README.md | 19 ++-- setup/win_setup_exe.iss | 59 ------------- 3 files changed, 21 insertions(+), 248 deletions(-) delete mode 100644 setup/win_setup_exe.iss diff --git a/setup.py b/setup.py index 411eab50..a6032470 100755 --- a/setup.py +++ b/setup.py @@ -489,127 +489,6 @@ def makeSimplePackage(embedPython): return -## -# Run PyInstaller on Package (freeze, onefile) -## - -def freezePackage(buildWindowed, oneFile, makeSetup, hostOS): - """Run PyInstaller to freeze the packages. This assumes all - dependencies are already in place. - """ - try: - import PyInstaller.__main__ # noqa: E402 - except ImportError: - print( - "ERROR: Package 'pyinstaller' is missing on this system.\n" - " Please run 'pip install --user pyinstaller'." - ) - sys.exit(1) - - print("") - print("Running PyInstaller") - print("===================") - print("") - - if hostOS == OS_WIN: - dotDot = ";" - else: - dotDot = ":" - - sys.modules["FixTk"] = None - instOpt = [ - "--name=novelWriter", - "--clean", - "--add-data=%s%s%s" % (os.path.join("nw", "assets"), dotDot, "assets"), - "--icon=%s" % os.path.join("nw", "assets", "icons", "novelwriter.ico"), - "--exclude-module=PyQt5.QtQml", - "--exclude-module=PyQt5.QtBluetooth", - "--exclude-module=PyQt5.QtDBus", - "--exclude-module=PyQt5.QtMultimedia", - "--exclude-module=PyQt5.QtMultimediaWidgets", - "--exclude-module=PyQt5.QtNetwork", - "--exclude-module=PyQt5.QtNetworkAuth", - "--exclude-module=PyQt5.QtNfc", - "--exclude-module=PyQt5.QtQuick", - "--exclude-module=PyQt5.QtQuickWidgets", - "--exclude-module=PyQt5.QtRemoteObjects", - "--exclude-module=PyQt5.QtSensors", - "--exclude-module=PyQt5.QtSerialPort", - "--exclude-module=PyQt5.QtSql", - "--exclude-module=FixTk", - "--exclude-module=tcl", - "--exclude-module=tk", - "--exclude-module=_tkinter", - "--exclude-module=tkinter", - "--exclude-module=Tkinter", - ] - - if buildWindowed: - instOpt.append("--windowed") - - if oneFile and not makeSetup: - instOpt.append("--onefile") - else: - instOpt.append("--onedir") - - instOpt.append("novelWriter.py") - - # Make sample.zip first - try: - buildSampleZip() - except Exception as e: - print("Failed with error:") - print(str(e)) - sys.exit(1) - - PyInstaller.__main__.run(instOpt) - - if not oneFile: - # These files are not needed, and take up a fair bit of space. - delFiles = [] - if hostOS == OS_WIN: - delFiles = [ - "Qt5DBus.dll", - "Qt5Network.dll", - "Qt5Qml.dll", - "Qt5QmlModels.dll", - "Qt5Quick.dll", - "Qt5Quick3D.dll", - "Qt5Quick3DAssetImport.dll", - "Qt5Quick3DRender.dll", - "Qt5Quick3DRuntimeRender.dll", - "Qt5Quick3DUtils.dll", - "Qt5Sql.dll" - ] - elif hostOS == OS_LINUX: - delFiles = [ - "libQt5DBus.so.5", - "libQt5Network.so.5", - "libQt5Qml.so.5", - "libQt5QmlModels.so.5", - "libQt5Quick.so.5", - "libQt5Quick3D.so.5", - "libQt5Quick3DAssetImport.so.5", - "libQt5Quick3DRender.so.5", - "libQt5Quick3DRuntimeRender.so.5", - "libQt5Quick3DUtils.so.5", - "libQt5Sql.so.5" - ] - distDir = os.path.join(os.getcwd(), "dist", "novelWriter") - for delFile in delFiles: - delPath = os.path.join(distDir, delFile) - if os.path.isfile(delPath): - print("Deleting file: %s" % delPath) - os.unlink(delPath) - - print("") - print("Build Finished") - print("") - print("The novelWriter executable should be in the folder named 'dist'") - print("") - - return - # =============================================================================================== # # General Installers # =============================================================================================== # @@ -888,9 +767,8 @@ def winInstall(): # Inno Setup Builder (setup-exe, setup-pyz) ## -def innoSetup(setupType): - """Run the Inno Setup tool to build a setup.exe file for Windows based on either a pyinstaller - freeze package (exe) or a zipapp package (pyz). +def innoSetup(): + """Run the Inno Setup tool to build a setup.exe file for Windows based on the pyz package. """ print("") print("Running Inno Setup") @@ -899,7 +777,7 @@ def innoSetup(setupType): # Read the iss template issData = "" - with open(os.path.join("setup", "win_setup_%s.iss" % setupType), mode="r") as inFile: + with open(os.path.join("setup", "win_setup_pyz.iss"), mode="r") as inFile: issData = inFile.read() import nw # noqa: E402 @@ -938,14 +816,14 @@ if __name__ == "__main__": hostOS = OS_NONE # Set Target OS - if "--linux" in sys.argv: - sys.argv.remove("--linux") + if "--target-linux" in sys.argv: + sys.argv.remove("--target-linux") targetOS = OS_LINUX - elif "--darwin" in sys.argv: - sys.argv.remove("--darwin") + elif "--target-darwin" in sys.argv: + sys.argv.remove("--target-darwin") targetOS = OS_DARWIN - elif "--win" in sys.argv: - sys.argv.remove("--win") + elif "--target-win" in sys.argv: + sys.argv.remove("--target-win") targetOS = OS_WIN else: targetOS = hostOS @@ -959,7 +837,7 @@ if __name__ == "__main__": "as a package on Linux, Mac and Windows. The available options are as follows:\n" "\n" "Some of the commands can be targeted towards a different OS than the host OS. To target\n" - "the command, add one of '--linux', '--darwin' or '--win'.\n" + "the command, add one of '--target-linux', '--target-darwin' or '--target-win'.\n" "\n" "General:\n" "\n" @@ -980,12 +858,9 @@ if __name__ == "__main__": " other source files. Accepts a target OS flag.\n" " pack-pyz Creates a pyz package in a folder with all dependencies using the\n" " zipapp tool. On Windows, python embeddable is added to the folder.\n" - " freeze Freeze the package and produces a folder with all dependencies using\n" - " the pyinstaller tool. This option is not designed for a specific OS.\n" - " onefile Build a standalone executable with all dependencies bundled using the\n" - " pyinstaller tool. Implies 'freeze', cannot be used with 'setup-exe'.\n" + " setup-pyz Build a Windows installer from a zipapp package using Inno Setup.\n" "\n" - "General Installers:\n" + "System Install:\n" "\n" " install Installs novelWriter to the system's Python install location. Run as \n" " root or with sudo for system-wide install, or as user for single user \n" @@ -993,20 +868,10 @@ if __name__ == "__main__": " xdg-install Install launcher and icons for freedesktop systems. Run as root or \n" " with sudo for system-wide install, or as user for single user install.\n" " win-install Install desktop and start menu icons for Windows systems.\n" - "\n" - "Windows Installers:\n" - "\n" - " setup-exe Build a Windows installer from a pyinstaller freeze package using Inno\n" - " Setup. This option automatically disables 'onefile'.\n" - " setup-pyz Build a Windows installer from a zipapp package using Inno Setup.\n" ) # Flags and Variables - buildWindowed = True - oneFile = False - makeSetupExe = False makeSetupPyz = False - doFreeze = False simplePack = False embedPython = False @@ -1050,15 +915,6 @@ if __name__ == "__main__": if hostOS == OS_WIN: embedPython = True - if "freeze" in sys.argv: - sys.argv.remove("freeze") - doFreeze = True - - if "onefile" in sys.argv: - sys.argv.remove("onefile") - doFreeze = True - oneFile = True - # General Installers # ================== @@ -1083,23 +939,12 @@ if __name__ == "__main__": print("ERROR: Command 'win-install' can only be used on Windows") sys.exit(1) - # Windows Setup Installers - # ======================== - - if "setup-exe" in sys.argv: - sys.argv.remove("setup-exe") - if hostOS == OS_WIN: - oneFile = False - makeSetupExe = True - makeSetupPyz = False - else: - print("Error: Command 'setup-exe' for Inno Setup is Windows only.") - sys.exit(1) + # Windows Setup Installer + # ======================= if "setup-pyz" in sys.argv: sys.argv.remove("setup-pyz") if hostOS == OS_WIN: - makeSetupExe = False makeSetupPyz = True else: print("Error: Command 'setup-pyz' for Inno Setup is Windows only.") @@ -1113,14 +958,8 @@ if __name__ == "__main__": if simplePack: makeSimplePackage(embedPython) - if doFreeze: - freezePackage(buildWindowed, oneFile, makeSetupExe, hostOS) - - if makeSetupExe: - innoSetup("exe") - if makeSetupPyz: - innoSetup("pyz") + innoSetup() if len(sys.argv) <= 1: # Nothing more to do diff --git a/setup/README.md b/setup/README.md index e49a670e..66bfb548 100644 --- a/setup/README.md +++ b/setup/README.md @@ -8,6 +8,10 @@ The root folder of the repository contains two scripts for setup and install: The `setup.py` is a standard Python setup script with a couple of additional options: +Some of the commands can be targeted towards a different OS than the host OS. +To target the command, add one of `--target-linux`, `--target-darwin` or +`--target-win`. + ### General `help` – Print the help message. @@ -32,13 +36,9 @@ the other source files. `pack-pyz` – Creates a pyz package in a folder with all dependencies using the zipapp tool. On Windows, python embeddable is added to the folder. -`freeze` – Freeze the package and produces a folder with all dependencies using -the pyinstaller tool. This option is not designed for a specific OS. +`setup-pyz` – Build a Windows installer from a zipapp package using Inno Setup. -`onefile` – Build a standalone executable with all dependencies bundled using -the pyinstaller tool. Implies `freeze`, cannot be used with `setup-exe`. - -### General Installers +### System Install `install` – Installs novelWriter to the system's Python install location. Run as root or with sudo for system-wide install, or as user for single user @@ -48,10 +48,3 @@ install. or with sudo for system-wide install, or as user for single user install. `win-install` – Install desktop and start menu icons for Windows systems. - -### "Windows Installers - -`setup-exe` – Build a Windows installer from a pyinstaller freeze package using -Inno Setup. This option automatically disables `onefile`. - -`setup-pyz` – Build a Windows installer from a zipapp package using Inno Setup. diff --git a/setup/win_setup_exe.iss b/setup/win_setup_exe.iss deleted file mode 100644 index bed7c5ed..00000000 --- a/setup/win_setup_exe.iss +++ /dev/null @@ -1,59 +0,0 @@ -; Script generated by the Inno Setup Script Wizard. -; SEE THE DOCUMENTATION FOR DETAILS ON CREATING INNO SETUP SCRIPT FILES! - -#define nwAppDir "%%dir%%\dist" -#define nwAppName "novelWriter" -#define nwAppVersion "%%version%%" -#define nwAppPublisher "novelWriter" -#define nwAppURL "http://novelWriter.io" -#define nwAppExeName "novelWriter.exe" - -[Setup] -; NOTE: The value of AppId uniquely identifies this application. Do not use the same AppId value in installers for other applications. -; (To generate a new GUID, click Tools | Generate GUID inside the IDE.) -AppId={{459A75D0-951F-4932-9809-6002EC8E733E} -AppName={#nwAppName} -AppVersion={#nwAppVersion} -AppVerName={#nwAppName} {#nwAppVersion} -AppPublisher={#nwAppPublisher} -AppPublisherURL={#nwAppURL} -AppSupportURL={#nwAppURL} -AppUpdatesURL={#nwAppURL} -DefaultDirName={autopf}\{#nwAppName} -DisableProgramGroupPage=yes -; The [Icons] "quicklaunchicon" entry uses {userappdata} but its [Tasks] entry has a proper IsAdminInstallMode Check. -UsedUserAreasWarning=no -; Uncomment the following line to run in non administrative install mode (install for current user only.) -;PrivilegesRequired=lowest -PrivilegesRequiredOverridesAllowed=dialog -OutputDir={#nwAppDir} -OutputBaseFilename=novelwriter-{#nwAppVersion}-win10-amd64-setup -Compression=lzma -SolidCompression=yes -WizardStyle=modern -ArchitecturesInstallIn64BitMode=x64 -ChangesAssociations=yes - -[Languages] -Name: "english"; MessagesFile: "compiler:Default.isl" - -[Tasks] -Name: "desktopicon"; Description: "{cm:CreateDesktopIcon}"; GroupDescription: "{cm:AdditionalIcons}"; Flags: unchecked -Name: "quicklaunchicon"; Description: "{cm:CreateQuickLaunchIcon}"; GroupDescription: "{cm:AdditionalIcons}"; Flags: unchecked; OnlyBelowVersion: 6.1; Check: not IsAdminInstallMode - -[Files] -Source: "{#nwAppDir}\novelWriter\*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs createallsubdirs - -[Icons] -Name: "{autoprograms}\{#nwAppName}"; Filename: "{app}\{#nwAppExeName}" -Name: "{autodesktop}\{#nwAppName}"; Filename: "{app}\{#nwAppExeName}"; Tasks: desktopicon - -[Run] -Filename: "{app}\{#nwAppExeName}"; Description: "{cm:LaunchProgram,{#StringChange(nwAppName, '&', '&&')}}"; Flags: nowait postinstall skipifsilent - -[Registry] -Root: HKA; Subkey: "Software\Classes\.nwx\OpenWithProgids"; ValueType: string; ValueName: "novelWriterProject.nwx"; ValueData: ""; Flags: uninsdeletevalue -Root: HKA; Subkey: "Software\Classes\novelWriterProject.nwx"; ValueType: string; ValueName: ""; ValueData: "novelWriter Project File"; Flags: uninsdeletekey -Root: HKA; Subkey: "Software\Classes\novelWriterProject.nwx\DefaultIcon"; ValueType: string; ValueName: ""; ValueData: "{app}\assets\icons\x-novelwriter-project.ico" -Root: HKA; Subkey: "Software\Classes\novelWriterProject.nwx\shell\open\command"; ValueType: string; ValueName: ""; ValueData: """{app}\{#nwAppExeName}"" ""%1""" -Root: HKA; Subkey: "Software\Classes\Applications\{#nwAppExeName}\SupportedTypes"; ValueType: string; ValueName: ".nwx"; ValueData: "" From ab21a9238d1ba8a6eba29f7a41cd1be0d326d32e Mon Sep 17 00:00:00 2001 From: "Veronica K. B. Olsen" <1619840+vkbo@users.noreply.github.com> Date: Fri, 5 Feb 2021 17:28:16 +0100 Subject: [PATCH 7/7] Update Windows Setup documentation --- docs/source/setup_windows.rst | 47 +++++++++++++++++++++++------------ 1 file changed, 31 insertions(+), 16 deletions(-) diff --git a/docs/source/setup_windows.rst b/docs/source/setup_windows.rst index 4a2f35a9..b34046d8 100644 --- a/docs/source/setup_windows.rst +++ b/docs/source/setup_windows.rst @@ -7,10 +7,11 @@ Setup on Windows This is a brief guide to how you can get novelWriter running on a Windows computer. Unlike other operating systems, Windows does not come prepared with an environment to run Python -applications, so you must first install Python. After that, running novelWriter is straightfoeward. +applications, so you must first install Python. After that, running novelWriter is straightforward. -If you have any problems, you can always open a question on the project's discussions_ page. This -requires a GitHub account. +.. tip:: + If you have any problems, you can always open a question on the project's discussions_ page. + This requires a GitHub account. .. _discussions: https://github.com/vkbo/novelWriter/discussions @@ -20,11 +21,15 @@ requires a GitHub account. Using the Installer =================== -The installer for Windows is no longer provided. You can still create it yourself if you want to. -It can be generated with the provided ``setup.py`` script. use the script's ``help`` command to get -further instructions. +The installer for Windows is no longer provided. See the `installer issue`_ for more info on why. +You can still create the installer yourself if you want to. It can be generated with the provided +``setup.py`` script. use the script's ``help`` command to get further instructions. -Please use the "Running from Source" option below instead. +Please use the "Running from Source" option below instead. It has been improved and a script has +been added that does nearly the same thing. + + +.. _installer issue: https://github.com/vkbo/novelWriter/issues/640 .. _a_setup_win_source: @@ -33,12 +38,18 @@ Running from Source =================== To run novelWriter from source, download the latest source zip file from the release page on -GitHub_ or the `main website`_. The file named ``novelWriter-x.y.z-minimal.zip``, where ``x.y.z`` -is the version number, is ideal for this. You can also download the full source. +GitHub_, or from the `main website`_. You can download the "Minimal Windows" zip file. It is a +minimal version of the source that contains only the files needed for running on Windows. You can +also download the full source if you wish. In order to make novelWriter run on your system, you must first have Python installed (Step 1). -Thereafter, a script will do the rest of the job (Step 2). or you can do it yourself manually if -you wish to. +Thereafter, a script will do the rest of the job (Step 2). Alternatively, you can run this step +manually from the command prompt if you wish to. + +.. tip:: + If your system already has all the dependencies installed, you can run novelWriter directly from + the extracted folder by double-clicking the ``novelWriter.pyw`` file. However, running the + script also adds start icons. .. _GitHub: https://github.com/vkbo/novelWriter/releases .. _main website: https://novelwriter.io @@ -66,13 +77,17 @@ Step 2: Dependencies and Icons **Alternative A: By Script** Open the folder where you extracted the novelWriter source, and double-click the file named -``setup_windows`` or ``setup_windows.bat``. This should open a command line window and run the -setup script to install dependencies, and add desktop and start menu icons. It will also check that -it can find Python from Step 1. +``setup_windows.bat``. This should open a command line window and run the setup script to install +dependencies, and add desktop and start menu icons. + +The script will also check that it can find Python on your system and alert you if it cannot run +it. If you are sure you have installed it, but the script cannot find it, you probably didn't +install it with the "Add Python to PATH" option mentioned in Step 1. .. note:: - If you upgrade Python to a newer version and the path to ``pythonw.exe`` changes, you may need - to run this script again. + If you upgrade Python to a newer version and the path to ``pythonw.exe`` has therefore changed, + you may need to run this script again. You can also run it to upgrade dependencies to the latest + version. **Alternative B: Manual Installation**