@@ -5,6 +5,7 @@
|
|||||||
/deploy/
|
/deploy/
|
||||||
*.spec
|
*.spec
|
||||||
*.egg-info
|
*.egg-info
|
||||||
|
setup.iss
|
||||||
|
|
||||||
# Documentation
|
# Documentation
|
||||||
/docs/build/
|
/docs/build/
|
||||||
|
|||||||
@@ -52,63 +52,65 @@ in principle work fine on other operating systems as well as long as dependencie
|
|||||||
tests are run on the latest versions of Ubuntu Linux, Windows Server and macOS.
|
tests are run on the latest versions of Ubuntu Linux, Windows Server and macOS.
|
||||||
|
|
||||||
|
|
||||||
## Installing and Running
|
# Installing and Running
|
||||||
|
|
||||||
You can runt novelWriter either from a downloaded copy of the source code, or by running:
|
novelWriter is available on [pypi.org](https://pypi.org/project/novelWriter/), and can be installed with:
|
||||||
```bash
|
```bash
|
||||||
pip install novelwriter
|
pip install novelwriter
|
||||||
```
|
```
|
||||||
**Note:** On some systems you must use `pip3` instead for the Python 3 version.
|
|
||||||
|
|
||||||
You can update novelWriter to the latest version by running:
|
To upgrade an existing installation, use:
|
||||||
```bash
|
```bash
|
||||||
pip install --upgrade novelwriter
|
pip install --upgrade novelwriter
|
||||||
```
|
```
|
||||||
|
|
||||||
The application can then be started with one of the commands, depending on your Python configuration:
|
Dependencies are installed automatically, but can generally be installed with:
|
||||||
|
```bash
|
||||||
|
pip install -r requirements.txt
|
||||||
|
```
|
||||||
|
|
||||||
|
Below are some brief instructions on how to get started on different operating systems.
|
||||||
|
|
||||||
|
|
||||||
|
## Linux
|
||||||
|
|
||||||
|
Either download the source, or install with pip.
|
||||||
|
|
||||||
|
If you run from source, install the dependencies via pip, or directly from the OS repo.
|
||||||
|
There are very few dependencies, and they should be available in the standard repo.
|
||||||
|
The Python packages needed are `pyqt5`, `lxml` and `pyenchant`.
|
||||||
|
|
||||||
|
### Installing from Source
|
||||||
|
|
||||||
|
You can also install novelWriter from source with:
|
||||||
|
```bash
|
||||||
|
python3 setup.py sample
|
||||||
|
sudo python3 setup.py install
|
||||||
|
sudo python3 setup.py launcher
|
||||||
|
```
|
||||||
|
|
||||||
|
The last line will install the application icons and set up a launcher for novelWriter.
|
||||||
|
The method uses hardcoded paths, so it may or may not work for your Linux distro.
|
||||||
|
If you have any issues, please submit a ticket so the script can be tuned.
|
||||||
|
|
||||||
|
The script may prompt you to choose which executable to configure if it finds more than one.
|
||||||
|
|
||||||
|
### Running from Source
|
||||||
|
|
||||||
|
If you want to run directly from the source, the application can be started with:
|
||||||
```bash
|
```bash
|
||||||
./novelWriter.py
|
./novelWriter.py
|
||||||
python novelWriter.py
|
|
||||||
python3 novelWriter.py
|
|
||||||
```
|
```
|
||||||
|
|
||||||
It also takes a few parameters for debugging and such, which can be listed with the switch `--help`.
|
You can also create a launcher for running directly from source with:
|
||||||
The `--info`, `--debug` or `--verbose` flags are particularly useful for increasing logging output
|
|
||||||
for debugging.
|
|
||||||
|
|
||||||
You can also provide a path to a folder containing a novelWriter project as the last parameter.
|
|
||||||
|
|
||||||
|
|
||||||
### Launcher and Icons
|
|
||||||
|
|
||||||
In the root setup folder there are icons and scripts and a template for setting up a launcher on
|
|
||||||
Gnome desktops. You may need to modify those scripts slightly, but as they are, they work on Debian
|
|
||||||
and Ubuntu. For other operating systems, please consult your operating system documentation for how
|
|
||||||
to make those. Feel free to submit more if you are able to make them.
|
|
||||||
|
|
||||||
|
|
||||||
## Package Dependencies
|
|
||||||
|
|
||||||
It is recommended that novelWriter runs with Qt 5.10 or later, and requires Python 3.6 or later.
|
|
||||||
Minimum version of Qt is 5.2.
|
|
||||||
|
|
||||||
|
|
||||||
### Linux
|
|
||||||
|
|
||||||
Generally, dependencies can be installed via `pip` with:
|
|
||||||
```bash
|
```bash
|
||||||
pip3 install -r requirements.txt
|
sudo python3 setup.py launcher
|
||||||
```
|
```
|
||||||
|
|
||||||
You can also install the packages from the distro's own package manager.
|
For more install options, see [Build and Install novelWriter](setup/BUILD.md).
|
||||||
For the apt package manager on Debian/Ubuntu systems, the following Python3 packages are needed:
|
|
||||||
|
|
||||||
* `python3-pyqt5` for the GUI
|
|
||||||
* `python3-lxml` for writing project files
|
|
||||||
* `python3-enchant` for better spell checking (optional)
|
|
||||||
|
|
||||||
|
|
||||||
### macOS
|
## macOS
|
||||||
|
|
||||||
These instructions assume you're using brew, and have Python and pip set up.
|
These instructions assume you're using brew, and have Python and pip set up.
|
||||||
If not, see the [brew docs](https://docs.brew.sh/Homebrew-and-Python) for help.
|
If not, see the [brew docs](https://docs.brew.sh/Homebrew-and-Python) for help.
|
||||||
@@ -126,11 +128,16 @@ It comes with a lot of default dictionaries.
|
|||||||
brew install enchant
|
brew install enchant
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
### Windows
|
### Windows
|
||||||
|
|
||||||
On Windows, the `pip install` command is generally sufficient to install everything you need.
|
On Windows, you may first need to install Python.
|
||||||
That should also install the Qt libraries and the spell check dictionary dependencies.
|
See the [python.org](https://www.python.org/) website for download packages.
|
||||||
|
It is recommended that you install the latest version of Python 3.8.
|
||||||
|
|
||||||
|
To install dependencies, run:
|
||||||
|
```bash
|
||||||
|
pip install --user -r requirements.txt
|
||||||
|
```
|
||||||
|
|
||||||
**Note:** On Windows, make sure Python3 is in your PATH if you want to launch novelWriter from
|
**Note:** On Windows, make sure Python3 is in your PATH if you want to launch novelWriter from
|
||||||
command line. You can also right click the `novelWriter.py` file, create a shortcut, then right
|
command line. You can also right click the `novelWriter.py` file, create a shortcut, then right
|
||||||
@@ -142,8 +149,11 @@ It should look something like this:
|
|||||||
C:\...\AppData\Local\Programs\Python\Python38\python.exe novelWriter.py
|
C:\...\AppData\Local\Programs\Python\Python38\python.exe novelWriter.py
|
||||||
```
|
```
|
||||||
|
|
||||||
|
You can also run the `make.py` script to generate a single executable, or an installer.
|
||||||
|
See [Build and Install novelWriter](setup/BUILD.md) for more details.
|
||||||
|
|
||||||
### Package Versions
|
|
||||||
|
## Package Versions
|
||||||
|
|
||||||
Exporting to Markdown requires PyQt/Qt 5.14. There are no known minimum for `lxml`, but the code
|
Exporting to Markdown requires PyQt/Qt 5.14. There are no known minimum for `lxml`, but the code
|
||||||
was originally written with 4.2. The optional spell check library must be at least 3.0.0 to work
|
was originally written with 4.2. The optional spell check library must be at least 3.0.0 to work
|
||||||
@@ -155,8 +165,15 @@ checker, but more can be added to the `nw/assets/dict` folder. See the [README](
|
|||||||
file in that folder for how to generate more dictionaries. Note that the difflib-based option is
|
file in that folder for how to generate more dictionaries. Note that the difflib-based option is
|
||||||
both slow and limited.
|
both slow and limited.
|
||||||
|
|
||||||
|
## Debugging
|
||||||
|
|
||||||
## Key Features
|
If you need to debug novelWriter, you must run it from command line.
|
||||||
|
It takes a few parameters, which can be listed with the switch `--help`.
|
||||||
|
The `--info`, `--debug` or `--verbose` flags are particularly useful for increasing logging output
|
||||||
|
for debugging.
|
||||||
|
|
||||||
|
|
||||||
|
# Key Features
|
||||||
|
|
||||||
Some features of novelWriter are listed below. Consult the documentation for more information.
|
Some features of novelWriter are listed below. Consult the documentation for more information.
|
||||||
|
|
||||||
|
|||||||
@@ -12,7 +12,6 @@
|
|||||||
# add these directories to sys.path here. If the directory is relative to the
|
# add these directories to sys.path here. If the directory is relative to the
|
||||||
# documentation root, use os.path.abspath to make it absolute, like shown here.
|
# documentation root, use os.path.abspath to make it absolute, like shown here.
|
||||||
#
|
#
|
||||||
# import os
|
|
||||||
# import sys
|
# import sys
|
||||||
# sys.path.insert(0, os.path.abspath("."))
|
# sys.path.insert(0, os.path.abspath("."))
|
||||||
import os
|
import os
|
||||||
|
|||||||
-84
@@ -1,84 +0,0 @@
|
|||||||
#!/usr/bin/env python3
|
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
|
|
||||||
import os
|
|
||||||
import sys
|
|
||||||
import getopt
|
|
||||||
import subprocess
|
|
||||||
|
|
||||||
# Defaults
|
|
||||||
buildWindowed = True
|
|
||||||
|
|
||||||
# Parse Options
|
|
||||||
shortOpt = "hd"
|
|
||||||
longOpt = [
|
|
||||||
"help",
|
|
||||||
"debug",
|
|
||||||
]
|
|
||||||
helpMsg = (
|
|
||||||
"\n"
|
|
||||||
"novelWriter Install Script\n"
|
|
||||||
"\n"
|
|
||||||
"Usage:\n"
|
|
||||||
" -h, --help Print this message.\n"
|
|
||||||
" -d, --debug Build novelWriter for debugging. To debug novelwriter after build,\n"
|
|
||||||
" run it from command line with the debug options. Please check the\n"
|
|
||||||
" novelWriter --help output for details.\n"
|
|
||||||
)
|
|
||||||
|
|
||||||
try:
|
|
||||||
inOpts, inArgs = getopt.getopt(sys.argv[1:], shortOpt, longOpt)
|
|
||||||
except getopt.GetoptError:
|
|
||||||
print(helpMsg)
|
|
||||||
sys.exit(2)
|
|
||||||
|
|
||||||
for inOpt, inArg in inOpts:
|
|
||||||
if inOpt in ("-h", "--help"):
|
|
||||||
print(helpMsg)
|
|
||||||
sys.exit(0)
|
|
||||||
elif inOpt in ("-d", "--debug"):
|
|
||||||
buildWindowed = False
|
|
||||||
|
|
||||||
# Run pip
|
|
||||||
packList = ["pyinstaller"]
|
|
||||||
with open("requirements.txt", mode="r") as reqFile:
|
|
||||||
for reqPack in reqFile:
|
|
||||||
if len(reqPack.strip()) > 0:
|
|
||||||
packList.append(reqPack)
|
|
||||||
|
|
||||||
for packName in packList:
|
|
||||||
print("Installing package dependency: %s" % packName)
|
|
||||||
try:
|
|
||||||
subprocess.call([sys.executable, "-m", "pip", "install", packName])
|
|
||||||
except Exception as e:
|
|
||||||
print("Failed with error:")
|
|
||||||
print(str(e))
|
|
||||||
|
|
||||||
# Run pyinstaller
|
|
||||||
if sys.platform.startswith("win32"):
|
|
||||||
dotDot = ";"
|
|
||||||
else:
|
|
||||||
dotDot = ":"
|
|
||||||
|
|
||||||
instOpt = [
|
|
||||||
"--name=novelWriter",
|
|
||||||
"--clean",
|
|
||||||
"--onefile",
|
|
||||||
"--add-data=%s%s%s" % (os.path.join("nw", "assets"), dotDot, "assets"),
|
|
||||||
"--icon=%s" % os.path.join("nw", "assets", "icons", "novelwriter.ico"),
|
|
||||||
]
|
|
||||||
if buildWindowed:
|
|
||||||
instOpt.append("--windowed")
|
|
||||||
|
|
||||||
instOpt.append("novelWriter.py")
|
|
||||||
|
|
||||||
import PyInstaller.__main__ # noqa: E402
|
|
||||||
PyInstaller.__main__.run(instOpt)
|
|
||||||
|
|
||||||
print("")
|
|
||||||
print("##################")
|
|
||||||
print(" Build Finished")
|
|
||||||
print("##################")
|
|
||||||
print("")
|
|
||||||
print("If everything went well, the novelWriter executable should be in the folder named 'dist'")
|
|
||||||
print("")
|
|
||||||
@@ -0,0 +1,331 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
"""
|
||||||
|
This script will either build:
|
||||||
|
* A single file executable named dist/novelWriter.exe. This is a quite
|
||||||
|
slow option, and the file is fairly big. Option --onefile
|
||||||
|
* A single directory named dist/novelWriter with a novelWriter.exe, and
|
||||||
|
all dependecies included. This is the default.
|
||||||
|
* The latter can be combined with a build stage of a setup.exe file
|
||||||
|
named setup-novelwriter-<version>.exe. Option --setup.
|
||||||
|
|
||||||
|
In addition, providing the --pip flag will cause the script to try to
|
||||||
|
install all dependencies needed for runing the build, and for running
|
||||||
|
novelWriter itself.
|
||||||
|
"""
|
||||||
|
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
import shutil
|
||||||
|
import subprocess
|
||||||
|
|
||||||
|
OS_NONE = 0
|
||||||
|
OS_LINUX = 1
|
||||||
|
OS_WIN = 2
|
||||||
|
OS_DARWIN = 3
|
||||||
|
|
||||||
|
# =============================================================================================== #
|
||||||
|
# Package Installer
|
||||||
|
# =============================================================================================== #
|
||||||
|
|
||||||
|
def installPackages(hostOS):
|
||||||
|
"""Install package dependencies both for this script and for running
|
||||||
|
novelWriter itself.
|
||||||
|
"""
|
||||||
|
print("")
|
||||||
|
print("Installing Dependencies")
|
||||||
|
print("#######################")
|
||||||
|
print("")
|
||||||
|
|
||||||
|
installQueue = ["pip", "pyinstaller", "-r requirements.txt"]
|
||||||
|
if hostOS == OS_DARWIN:
|
||||||
|
installQueue.append("pyobjc")
|
||||||
|
|
||||||
|
pyCmd = [sys.executable, "-m"]
|
||||||
|
pipCmd = ["pip", "install", "--user", "--upgrade"]
|
||||||
|
for stepCmd in installQueue:
|
||||||
|
pkgCmd = stepCmd.split(" ")
|
||||||
|
try:
|
||||||
|
subprocess.call(pyCmd + pipCmd + pkgCmd)
|
||||||
|
except Exception as e:
|
||||||
|
print("Failed with error:")
|
||||||
|
print(str(e))
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
return
|
||||||
|
|
||||||
|
# =============================================================================================== #
|
||||||
|
# Run PyInstaller on Package
|
||||||
|
# =============================================================================================== #
|
||||||
|
|
||||||
|
def freezePackage(buildWindowed, oneFile, makeSetup, hostOS):
|
||||||
|
"""Run PyInstaller to freeze the packages. This assumes all
|
||||||
|
dependencies are already in place.
|
||||||
|
"""
|
||||||
|
import PyInstaller.__main__ # noqa: E402
|
||||||
|
|
||||||
|
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:
|
||||||
|
subprocess.call([sys.executable, "setup.py", "sample"])
|
||||||
|
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
|
||||||
|
|
||||||
|
# =============================================================================================== #
|
||||||
|
# Inno Setup Builder
|
||||||
|
# =============================================================================================== #
|
||||||
|
|
||||||
|
def innoSetup():
|
||||||
|
"""Run the Inno Setup tool to build a setup.exe file for Windows.
|
||||||
|
"""
|
||||||
|
print("")
|
||||||
|
print("Running Inno Setup")
|
||||||
|
print("##################")
|
||||||
|
print("")
|
||||||
|
|
||||||
|
# Read the iss template
|
||||||
|
issData = ""
|
||||||
|
with open(os.path.join("setup", "win_setup.iss"), mode="r") as inFile:
|
||||||
|
issData = inFile.read()
|
||||||
|
|
||||||
|
import nw # noqa: E402
|
||||||
|
issData = issData.replace(r"%%version%%", nw.__version__)
|
||||||
|
issData = issData.replace(r"%%dir%%", os.getcwd())
|
||||||
|
|
||||||
|
with open("setup.iss", mode="w+") as outFile:
|
||||||
|
outFile.write(issData)
|
||||||
|
|
||||||
|
try:
|
||||||
|
subprocess.call(["iscc", "setup.iss"])
|
||||||
|
except Exception as e:
|
||||||
|
print("Inno Setup failed with error:")
|
||||||
|
print(str(e))
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
return
|
||||||
|
|
||||||
|
# =============================================================================================== #
|
||||||
|
# Clean Build and Dist Folders
|
||||||
|
# =============================================================================================== #
|
||||||
|
|
||||||
|
def cleanInstall():
|
||||||
|
"""Recursively delete the 'build' and 'dist' folders.
|
||||||
|
"""
|
||||||
|
print("")
|
||||||
|
print("Cleaning up build environment ...")
|
||||||
|
|
||||||
|
buildDir = os.path.join(os.getcwd(), "build")
|
||||||
|
if os.path.isdir(buildDir):
|
||||||
|
try:
|
||||||
|
shutil.rmtree(buildDir)
|
||||||
|
print("Deleted folder 'build'")
|
||||||
|
except Exception as e:
|
||||||
|
print("Error: Cannot delete 'build' folder.")
|
||||||
|
print(str(e))
|
||||||
|
sys.exit(1)
|
||||||
|
else:
|
||||||
|
print("Folder 'build' not found")
|
||||||
|
|
||||||
|
distDir = os.path.join(os.getcwd(), "dist")
|
||||||
|
if os.path.isdir(distDir):
|
||||||
|
try:
|
||||||
|
shutil.rmtree(distDir)
|
||||||
|
print("Deleted folder 'dist'")
|
||||||
|
except Exception as e:
|
||||||
|
print("Error: Cannot delete 'dist' folder.")
|
||||||
|
print(str(e))
|
||||||
|
sys.exit(1)
|
||||||
|
else:
|
||||||
|
print("Folder 'dist' not found")
|
||||||
|
|
||||||
|
print("")
|
||||||
|
|
||||||
|
return
|
||||||
|
|
||||||
|
# =============================================================================================== #
|
||||||
|
# Process Build Steps
|
||||||
|
# =============================================================================================== #
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
"""Parse command line options and run the commands.
|
||||||
|
"""
|
||||||
|
# Detect OS
|
||||||
|
if sys.platform.startswith("linux"):
|
||||||
|
hostOS = OS_LINUX
|
||||||
|
elif sys.platform.startswith("darwin"):
|
||||||
|
hostOS = OS_DARWIN
|
||||||
|
elif sys.platform.startswith("win32"):
|
||||||
|
hostOS = OS_WIN
|
||||||
|
elif sys.platform.startswith("cygwin"):
|
||||||
|
hostOS = OS_WIN
|
||||||
|
else:
|
||||||
|
hostOS = OS_NONE
|
||||||
|
|
||||||
|
# Flags and Variables
|
||||||
|
buildWindowed = True
|
||||||
|
oneFile = False
|
||||||
|
makeSetup = False
|
||||||
|
doFreeze = False
|
||||||
|
|
||||||
|
helpMsg = (
|
||||||
|
"\n"
|
||||||
|
"novelWriter Make Tool\n"
|
||||||
|
"=====================\n"
|
||||||
|
"This tool provides build commands for distibuting novelWriter as a\n"
|
||||||
|
"package. The available options are as follows:\n"
|
||||||
|
"\n"
|
||||||
|
"help Print the help message.\n"
|
||||||
|
"freeze Freeze the package and produces a folder of all\n"
|
||||||
|
" dependencies using pyinstaller.\n"
|
||||||
|
"onefile Build a standalone executable with all dependencies\n"
|
||||||
|
" bundled. Implies 'freeze', cannot be used with 'setup'.\n"
|
||||||
|
"pip Run pip to install all package dependencies for\n"
|
||||||
|
" novelWriter and this build tool.\n"
|
||||||
|
"setup Build a setup.exe installer for Windows. This option\n"
|
||||||
|
" automaticall disables the 'onefile' option.\n"
|
||||||
|
"clean This will attempt to delete the 'build' and 'dist'\n"
|
||||||
|
" folders in the current folder.\n"
|
||||||
|
)
|
||||||
|
|
||||||
|
if "help" in sys.argv or len(sys.argv) <= 1:
|
||||||
|
print(helpMsg)
|
||||||
|
sys.exit(0)
|
||||||
|
|
||||||
|
if not os.path.isfile(os.path.join(os.getcwd(), "novelWriter.py")):
|
||||||
|
print("Error: This script must be run in the root folder of novelWriter.")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
if not os.path.isdir(os.path.join(os.getcwd(), "nw")):
|
||||||
|
print("Error: This script must be run in the root folder of novelWriter.")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
if "clean" in sys.argv:
|
||||||
|
sys.argv.remove("clean")
|
||||||
|
cleanInstall()
|
||||||
|
|
||||||
|
if "pip" in sys.argv:
|
||||||
|
sys.argv.remove("pip")
|
||||||
|
installPackages(hostOS)
|
||||||
|
|
||||||
|
if "freeze" in sys.argv:
|
||||||
|
sys.argv.remove("freeze")
|
||||||
|
doFreeze = True
|
||||||
|
|
||||||
|
if "onefile" in sys.argv:
|
||||||
|
sys.argv.remove("onefile")
|
||||||
|
doFreeze = True
|
||||||
|
oneFile = True
|
||||||
|
|
||||||
|
if "setup" in sys.argv:
|
||||||
|
sys.argv.remove("setup")
|
||||||
|
if hostOS == OS_WIN:
|
||||||
|
oneFile = False
|
||||||
|
makeSetup = True
|
||||||
|
else:
|
||||||
|
print("Error: Argument 'setup' for Inno Setup is Windows only.")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
if doFreeze:
|
||||||
|
freezePackage(buildWindowed, oneFile, makeSetup, hostOS)
|
||||||
|
|
||||||
|
if makeSetup:
|
||||||
|
innoSetup()
|
||||||
|
|
||||||
|
# END Main
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
[build-system]
|
||||||
|
requires = ["setuptools", "wheel"]
|
||||||
|
build-backend = "setuptools.build_meta"
|
||||||
@@ -1,6 +1,49 @@
|
|||||||
[metadata]
|
[metadata]
|
||||||
license_files = LICENSE.md
|
name = novelWriter
|
||||||
version = attr: nw.__version__
|
version = attr: nw.__version__
|
||||||
|
author = Veronica Berglyd Olsen
|
||||||
|
author_email = code@vkbo.net
|
||||||
|
description = A markdown-like document editor for writing novels
|
||||||
|
url = https://novelwriter.io
|
||||||
|
long_description = file: README.md
|
||||||
|
long_description_content_type = text/markdown
|
||||||
|
license_file = LICENSE.md
|
||||||
|
license = GNU General Public License v3
|
||||||
|
classifiers =
|
||||||
|
Programming Language :: Python :: 3 :: Only
|
||||||
|
Programming Language :: Python :: 3.6
|
||||||
|
Programming Language :: Python :: 3.7
|
||||||
|
Programming Language :: Python :: 3.8
|
||||||
|
Programming Language :: Python :: 3.9
|
||||||
|
Programming Language :: Python :: Implementation :: CPython
|
||||||
|
License :: OSI Approved :: GNU General Public License v3 (GPLv3)
|
||||||
|
Development Status :: 4 - Beta
|
||||||
|
Operating System :: OS Independent
|
||||||
|
Intended Audience :: End Users/Desktop
|
||||||
|
Natural Language :: English
|
||||||
|
Topic :: Text Editors
|
||||||
|
python_requires = >=3.6
|
||||||
|
install_requires =
|
||||||
|
pyqt5>=5.2.1
|
||||||
|
lxml>=4.2.0
|
||||||
|
pyenchant>=3.0.0
|
||||||
|
project_urls =
|
||||||
|
Bug Tracker = https://github.com/vkbo/novelWriter/issues
|
||||||
|
Documentation = https://github.com/vkbo/novelWriter/issues
|
||||||
|
Source Code = https://github.com/vkbo/novelWriter
|
||||||
|
|
||||||
|
[options]
|
||||||
|
include_package_data = True
|
||||||
|
packages = find:
|
||||||
|
|
||||||
|
[options.packages.find]
|
||||||
|
exclude = docs, tests, sample
|
||||||
|
|
||||||
|
[options.entry_points]
|
||||||
|
console_script =
|
||||||
|
novelWriter-cli = nw:main
|
||||||
|
gui_scripts =
|
||||||
|
novelWriter = nw:main
|
||||||
|
|
||||||
[bdist_wheel]
|
[bdist_wheel]
|
||||||
universal = 0
|
universal = 0
|
||||||
|
|||||||
@@ -1,30 +1,26 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
|
import shutil
|
||||||
import subprocess
|
import subprocess
|
||||||
import setuptools
|
import setuptools
|
||||||
|
|
||||||
##
|
# =============================================================================================== #
|
||||||
# Build the Package
|
# Qt Assistant Documentation Builder
|
||||||
##
|
# =============================================================================================== #
|
||||||
|
|
||||||
buildDocs = False
|
def buildQtDocs():
|
||||||
buildSample = False
|
"""This function will build the documentation as a Qt help file. The
|
||||||
|
file is then copied into the nw/assets/help directory and can be
|
||||||
|
included in builds.
|
||||||
|
|
||||||
if "qthelp" in sys.argv:
|
Depends on packages:
|
||||||
buildDocs = True
|
* pip install sphinx
|
||||||
sys.argv.remove("qthelp")
|
* pip install sphinx-rtd-theme
|
||||||
|
* pip install sphinxcontrib-qthelp
|
||||||
if "sample" in sys.argv:
|
|
||||||
buildSample = True
|
|
||||||
sys.argv.remove("sample")
|
|
||||||
|
|
||||||
##
|
|
||||||
# Qt Assistant Documentation
|
|
||||||
##
|
|
||||||
|
|
||||||
if buildDocs:
|
|
||||||
|
|
||||||
|
It also requires the qhelpgenerator to be available on the system.
|
||||||
|
"""
|
||||||
buildDir = os.path.join("docs", "build", "qthelp")
|
buildDir = os.path.join("docs", "build", "qthelp")
|
||||||
helpDir = os.path.join("nw", "assets", "help")
|
helpDir = os.path.join("nw", "assets", "help")
|
||||||
|
|
||||||
@@ -41,14 +37,14 @@ if buildDocs:
|
|||||||
try:
|
try:
|
||||||
subprocess.call(["make", "-C", "docs", "qthelp"])
|
subprocess.call(["make", "-C", "docs", "qthelp"])
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print("Failed with error:")
|
print("QtHelp Build Error:")
|
||||||
print(str(e))
|
print(str(e))
|
||||||
buildFail = True
|
buildFail = True
|
||||||
|
|
||||||
try:
|
try:
|
||||||
subprocess.call(["qhelpgenerator", os.path.join(buildDir, inFile)])
|
subprocess.call(["qhelpgenerator", os.path.join(buildDir, inFile)])
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print("Failed with error:")
|
print("QtHelp Build Error:")
|
||||||
print(str(e))
|
print(str(e))
|
||||||
buildFail = True
|
buildFail = True
|
||||||
|
|
||||||
@@ -56,7 +52,7 @@ if buildDocs:
|
|||||||
try:
|
try:
|
||||||
os.mkdir(helpDir)
|
os.mkdir(helpDir)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print("Failed with error:")
|
print("QtHelp Build Error:")
|
||||||
print(str(e))
|
print(str(e))
|
||||||
buildFail = True
|
buildFail = True
|
||||||
|
|
||||||
@@ -68,7 +64,7 @@ if buildDocs:
|
|||||||
os.rename(os.path.join(buildDir, outFile), os.path.join(helpDir, outFile))
|
os.rename(os.path.join(buildDir, outFile), os.path.join(helpDir, outFile))
|
||||||
os.rename(os.path.join(buildDir, datFile), os.path.join(helpDir, datFile))
|
os.rename(os.path.join(buildDir, datFile), os.path.join(helpDir, datFile))
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print("Failed with error:")
|
print("QtHelp Build Error:")
|
||||||
print(str(e))
|
print(str(e))
|
||||||
buildFail = True
|
buildFail = True
|
||||||
|
|
||||||
@@ -80,11 +76,20 @@ if buildDocs:
|
|||||||
print("Documentation build: OK")
|
print("Documentation build: OK")
|
||||||
print("")
|
print("")
|
||||||
|
|
||||||
##
|
return
|
||||||
# Sample Project ZIP file
|
|
||||||
##
|
|
||||||
|
|
||||||
if buildSample:
|
# =============================================================================================== #
|
||||||
|
# Sample Project ZIP File Builder
|
||||||
|
# =============================================================================================== #
|
||||||
|
|
||||||
|
def buildSampleZip():
|
||||||
|
"""Bundle the sample project into a single zip file to be saved into
|
||||||
|
the nw/assets folder for further bundling into builds.
|
||||||
|
"""
|
||||||
|
print("")
|
||||||
|
print("Building Sample ZIP File")
|
||||||
|
print("========================")
|
||||||
|
print("")
|
||||||
|
|
||||||
srcSample = "sample"
|
srcSample = "sample"
|
||||||
dstSample = os.path.join("nw", "assets", "sample.zip")
|
dstSample = os.path.join("nw", "assets", "sample.zip")
|
||||||
@@ -96,8 +101,10 @@ if buildSample:
|
|||||||
from zipfile import ZipFile
|
from zipfile import ZipFile
|
||||||
|
|
||||||
with ZipFile(dstSample, "w") as zipObj:
|
with ZipFile(dstSample, "w") as zipObj:
|
||||||
|
print("Compressing: nwProject.nwx")
|
||||||
zipObj.write(os.path.join(srcSample, "nwProject.nwx"), "nwProject.nwx")
|
zipObj.write(os.path.join(srcSample, "nwProject.nwx"), "nwProject.nwx")
|
||||||
for docFile in os.listdir(os.path.join(srcSample, "content")):
|
for docFile in os.listdir(os.path.join(srcSample, "content")):
|
||||||
|
print("Compressing: content/%s" % docFile)
|
||||||
srcDoc = os.path.join(srcSample, "content", docFile)
|
srcDoc = os.path.join(srcSample, "content", docFile)
|
||||||
zipObj.write(srcDoc, "content/"+docFile)
|
zipObj.write(srcDoc, "content/"+docFile)
|
||||||
|
|
||||||
@@ -105,58 +112,197 @@ if buildSample:
|
|||||||
print("Error: Could not find sample project source directory.")
|
print("Error: Could not find sample project source directory.")
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
if len(sys.argv) == 1:
|
print("")
|
||||||
# Nothing more to do
|
print("Built file: %s" % dstSample)
|
||||||
sys.exit(0)
|
print("")
|
||||||
|
|
||||||
##
|
return
|
||||||
# Build the Package
|
|
||||||
##
|
|
||||||
|
|
||||||
# Read content from files
|
# =============================================================================================== #
|
||||||
with open("README.md", "r") as inFile:
|
# Create Launcher
|
||||||
longDescription = inFile.read()
|
# =============================================================================================== #
|
||||||
|
|
||||||
setuptools.setup(
|
def makeLauncherLinux():
|
||||||
name = "novelWriter",
|
"""Will attempt to install icons and make a launcher.
|
||||||
# version = __version__, # Set in setup.cfg
|
"""
|
||||||
author = "Veronica Berglyd Olsen",
|
print("")
|
||||||
author_email = "code@vkbo.net",
|
print("Creating Launcher")
|
||||||
description = "A markdown-like document editor for writing novels",
|
print("=================")
|
||||||
long_description = longDescription,
|
print("")
|
||||||
long_description_content_type = "text/markdown",
|
|
||||||
license = "GNU General Public License v3",
|
exOpts = []
|
||||||
url = "https://novelwriter.io",
|
|
||||||
entry_points = {
|
testExec = shutil.which("novelWriter")
|
||||||
"console_scripts" : ["novelWriter-cli=nw:main"],
|
if testExec is not None:
|
||||||
"gui_scripts" : ["novelWriter=nw:main"],
|
exOpts.append(testExec)
|
||||||
},
|
|
||||||
packages = setuptools.find_packages(exclude=["docs", "tests", "sample"]),
|
testExec = shutil.which("novelwriter")
|
||||||
include_package_data = True,
|
if testExec is not None:
|
||||||
package_data = {"": ["*.conf"]},
|
exOpts.append(testExec)
|
||||||
project_urls = {
|
|
||||||
"Bug Tracker": "https://github.com/vkbo/novelWriter/issues",
|
testExec = os.path.join(os.getcwd(), "novelWriter.py")
|
||||||
"Documentation": "https://github.com/vkbo/novelWriter/issues",
|
if os.path.isfile(testExec):
|
||||||
"Source Code": "https://github.com/vkbo/novelWriter",
|
exOpts.append(testExec)
|
||||||
},
|
|
||||||
classifiers = [
|
useExec = ""
|
||||||
"Programming Language :: Python :: 3 :: Only",
|
nOpts = len(exOpts)
|
||||||
"Programming Language :: Python :: 3.6",
|
if nOpts == 0:
|
||||||
"Programming Language :: Python :: 3.7",
|
print("Error: No executables for novelWriter found.")
|
||||||
"Programming Language :: Python :: 3.8",
|
sys.exit(1)
|
||||||
"Programming Language :: Python :: 3.9",
|
elif nOpts == 1:
|
||||||
"Programming Language :: Python :: Implementation :: CPython",
|
useExec = exOpts[0]
|
||||||
"License :: OSI Approved :: GNU General Public License v3 (GPLv3)",
|
else:
|
||||||
"Development Status :: 4 - Beta",
|
print("Found multiple novelWriter executables:")
|
||||||
"Operating System :: OS Independent",
|
print("")
|
||||||
"Intended Audience :: End Users/Desktop",
|
for iExec, anExec in enumerate(exOpts):
|
||||||
"Natural Language :: English",
|
print(" [%d] %s" % (iExec, anExec))
|
||||||
"Topic :: Text Editors",
|
print("")
|
||||||
],
|
intVal = int(input("Please select which novelWriter executable to use: "))
|
||||||
python_requires = ">=3.6",
|
print("")
|
||||||
install_requires = [
|
|
||||||
"pyqt5>=5.2.1",
|
if intVal >= 0 and intVal < nOpts:
|
||||||
"lxml>=4.2.0",
|
useExec = exOpts[intVal]
|
||||||
"pyenchant>=3.0.0",
|
else:
|
||||||
],
|
print("Error: Invalid selection.")
|
||||||
)
|
sys.exit(1)
|
||||||
|
|
||||||
|
print("Using executable: %s " % useExec)
|
||||||
|
|
||||||
|
# Read the Template
|
||||||
|
desktopData = ""
|
||||||
|
with open(os.path.join("setup", "novelwriter.desktop"), mode="r") as inFile:
|
||||||
|
desktopData = inFile.read()
|
||||||
|
|
||||||
|
desktopData = desktopData.replace(r"%%exec%%", useExec)
|
||||||
|
|
||||||
|
desktopFile = "/usr/share/applications/novelwriter.desktop"
|
||||||
|
try:
|
||||||
|
with open(desktopFile, mode="w+") as outFile:
|
||||||
|
outFile.write(desktopData)
|
||||||
|
print("Wrote file: %s" % desktopFile)
|
||||||
|
except Exception as e:
|
||||||
|
print("Error: Could not write novelwriter.desktop file.")
|
||||||
|
print(str(e))
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
print("")
|
||||||
|
|
||||||
|
# Copy Icons
|
||||||
|
|
||||||
|
iconDirs = [
|
||||||
|
"/usr/share/icons/hicolor/24x24/apps",
|
||||||
|
"/usr/share/icons/hicolor/48x48/apps",
|
||||||
|
"/usr/share/icons/hicolor/96x96/apps",
|
||||||
|
"/usr/share/icons/hicolor/256x256/apps",
|
||||||
|
"/usr/share/icons/hicolor/512x512/apps",
|
||||||
|
"/usr/share/icons/hicolor/scalable/apps",
|
||||||
|
"/usr/share/icons/hicolor/scalable/mimetypes",
|
||||||
|
]
|
||||||
|
for iconDir in iconDirs:
|
||||||
|
if not os.path.isdir:
|
||||||
|
try:
|
||||||
|
os.mkdir(iconDir)
|
||||||
|
print("Created folder: %s" % iconDir)
|
||||||
|
except Exception as e:
|
||||||
|
print("Error: Could not make folder: %s" % iconDir)
|
||||||
|
print(str(e))
|
||||||
|
|
||||||
|
copyList = [(
|
||||||
|
"setup/icons/24x24/novelwriter.png",
|
||||||
|
"/usr/share/icons/hicolor/24x24/apps/novelwriter.png"
|
||||||
|
), (
|
||||||
|
"setup/icons/48x48/novelwriter.png",
|
||||||
|
"/usr/share/icons/hicolor/48x48/apps/novelwriter.png"
|
||||||
|
), (
|
||||||
|
"setup/icons/96x96/novelwriter.png",
|
||||||
|
"/usr/share/icons/hicolor/96x96/apps/novelwriter.png"
|
||||||
|
), (
|
||||||
|
"setup/icons/256x256/novelwriter.png",
|
||||||
|
"/usr/share/icons/hicolor/256x256/apps/novelwriter.png"
|
||||||
|
), (
|
||||||
|
"setup/icons/512x512/novelwriter.png",
|
||||||
|
"/usr/share/icons/hicolor/512x512/apps/novelwriter.png"
|
||||||
|
), (
|
||||||
|
"setup/icons/novelwriter.svg",
|
||||||
|
"/usr/share/icons/hicolor/scalable/apps/novelwriter.svg"
|
||||||
|
), (
|
||||||
|
"setup/icons/x-novelwriter-project.svg",
|
||||||
|
"/usr/share/icons/hicolor/scalable/mimetypes/application-x-novelwriter-project.svg"
|
||||||
|
), (
|
||||||
|
"setup/mime/x-novelwriter-project.xml",
|
||||||
|
"/usr/share/mime/packages/x-novelwriter-project.xml"
|
||||||
|
)]
|
||||||
|
for srcFile, dstFile in copyList:
|
||||||
|
try:
|
||||||
|
shutil.copyfile(srcFile, dstFile)
|
||||||
|
print("Copied file to: %s" % dstFile)
|
||||||
|
except Exception as e:
|
||||||
|
print("Error: Could not copy file: %s" % srcFile)
|
||||||
|
print(str(e))
|
||||||
|
|
||||||
|
print("")
|
||||||
|
|
||||||
|
# Update System
|
||||||
|
try:
|
||||||
|
subprocess.call(["update-mime-database", "/usr/share/mime/"])
|
||||||
|
print("Updated mime database.")
|
||||||
|
except Exception as e:
|
||||||
|
print("Error: Filed to update mime database.")
|
||||||
|
print(str(e))
|
||||||
|
|
||||||
|
try:
|
||||||
|
subprocess.call(["update-icon-caches", "/usr/share/icons/*"])
|
||||||
|
print("Updated icon cache.")
|
||||||
|
except Exception as e:
|
||||||
|
print("Error: Filed to update icon cache.")
|
||||||
|
print(str(e))
|
||||||
|
|
||||||
|
print("")
|
||||||
|
print("Done!")
|
||||||
|
print("")
|
||||||
|
|
||||||
|
return
|
||||||
|
|
||||||
|
# =============================================================================================== #
|
||||||
|
# Process Jobs
|
||||||
|
# =============================================================================================== #
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
|
||||||
|
helpMsg = (
|
||||||
|
"\n"
|
||||||
|
"novelWriter Setup Tool\n"
|
||||||
|
"======================\n"
|
||||||
|
"This tool provides some additional setup commands for novelWriter.\n"
|
||||||
|
"\n"
|
||||||
|
"help Print the help message.\n"
|
||||||
|
"gthelp Build the help documentation for use with the QtAssistant.\n"
|
||||||
|
"sample Build the sample project as a zip file.\n"
|
||||||
|
"launcher Install launcher icons for freedesktop systems.\n"
|
||||||
|
)
|
||||||
|
|
||||||
|
if "help" in sys.argv:
|
||||||
|
sys.argv.remove("help")
|
||||||
|
print(helpMsg)
|
||||||
|
sys.exit(0)
|
||||||
|
|
||||||
|
if "qthelp" in sys.argv:
|
||||||
|
sys.argv.remove("qthelp")
|
||||||
|
buildQtDocs()
|
||||||
|
|
||||||
|
if "sample" in sys.argv:
|
||||||
|
sys.argv.remove("sample")
|
||||||
|
buildSampleZip()
|
||||||
|
|
||||||
|
if "launcher" in sys.argv:
|
||||||
|
sys.argv.remove("launcher")
|
||||||
|
makeLauncherLinux()
|
||||||
|
|
||||||
|
if len(sys.argv) <= 1:
|
||||||
|
# Nothing more to do
|
||||||
|
sys.exit(0)
|
||||||
|
|
||||||
|
# Run the standard setup
|
||||||
|
setuptools.setup()
|
||||||
|
|
||||||
|
# END Main
|
||||||
|
|||||||
@@ -0,0 +1,47 @@
|
|||||||
|
# Build and Install novelWriter
|
||||||
|
|
||||||
|
The root folder of the repository contains two scripts for setup and install:
|
||||||
|
|
||||||
|
|
||||||
|
## Script `setup.py`
|
||||||
|
|
||||||
|
The `setup.py` is a standard Python setup script with a couple of additional options:
|
||||||
|
|
||||||
|
* `qthelp`: Will attempt to build a single file QtAssistand documentation file.
|
||||||
|
This requires the Qt tools to be installed on the local system, as well as the sphinx build tools
|
||||||
|
for the documentation.
|
||||||
|
* `sample`: Will create a `sample.zip` file in the `nw/assets` folder.
|
||||||
|
This is the file the New Project Wizard uses to generate an example project.
|
||||||
|
If novelWriter is run from source, this file is not needed.
|
||||||
|
* `launcher`: Will try to copy the novelWriter icons and create a novelWriter.desktop file to launch
|
||||||
|
the application. This should work on standard Linux desktops.
|
||||||
|
|
||||||
|
To install novelWriter as a local Python package, run:
|
||||||
|
```bash
|
||||||
|
sudo python setup.py install
|
||||||
|
```
|
||||||
|
|
||||||
|
## Script `make.py`
|
||||||
|
|
||||||
|
The `make.py` script provides a number of convenient options for building packages if novelWriter.
|
||||||
|
|
||||||
|
Usage:
|
||||||
|
```bash
|
||||||
|
python make.py [command]
|
||||||
|
```
|
||||||
|
|
||||||
|
It currently accept the following commands:
|
||||||
|
|
||||||
|
* `help`: Print the help message.
|
||||||
|
* `freeze`: Freeze the package and produces a folder of all dependencies using pyinstaller.
|
||||||
|
* `onefile`: Build a standalone executable with all dependencies bundled.
|
||||||
|
Implies `freeze`, cannot be used with `setup`.
|
||||||
|
* `pip`: Run pip to install all package dependencies for novelWriter and this build tool.
|
||||||
|
* `setup`: Build a setup.exe installer for Windows.
|
||||||
|
This option automaticall disables the `onefile` option.
|
||||||
|
* `clean`: This will attempt to delete the `build` and `dist` folders in the current folder.
|
||||||
|
|
||||||
|
For instance, to create a Windows installer, run:
|
||||||
|
```bash
|
||||||
|
python make.py freeze setup
|
||||||
|
```
|
||||||
@@ -1,42 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
|
|
||||||
cd ..
|
|
||||||
|
|
||||||
EXEC=$(pwd)/novelWriter.py
|
|
||||||
EXEC=$(echo $EXEC | sed 's_/_\\/_g')
|
|
||||||
|
|
||||||
sed "s/%%exec%%/$EXEC/g" setup/novelwriter.desktop > /usr/share/applications/novelwriter.desktop
|
|
||||||
|
|
||||||
if [ ! -d /usr/share/icons/hicolor/24x24/apps ]; then
|
|
||||||
mkdir -pv /usr/share/icons/hicolor/24x24/apps
|
|
||||||
fi
|
|
||||||
if [ ! -d /usr/share/icons/hicolor/48x48/apps ]; then
|
|
||||||
mkdir -pv /usr/share/icons/hicolor/48x48/apps
|
|
||||||
fi
|
|
||||||
if [ ! -d /usr/share/icons/hicolor/96x96/apps ]; then
|
|
||||||
mkdir -pv /usr/share/icons/hicolor/96x96/apps
|
|
||||||
fi
|
|
||||||
if [ ! -d /usr/share/icons/hicolor/256x256/apps ]; then
|
|
||||||
mkdir -pv /usr/share/icons/hicolor/256x256/apps
|
|
||||||
fi
|
|
||||||
if [ ! -d /usr/share/icons/hicolor/512x512/apps ]; then
|
|
||||||
mkdir -pv /usr/share/icons/hicolor/512x512/apps
|
|
||||||
fi
|
|
||||||
if [ ! -d /usr/share/icons/hicolor/scalable/apps ]; then
|
|
||||||
mkdir -pv /usr/share/icons/hicolor/scalable/apps
|
|
||||||
fi
|
|
||||||
if [ ! -d /usr/share/icons/hicolor/scalable/mimetypes ]; then
|
|
||||||
mkdir -pv /usr/share/icons/hicolor/scalable/mimetypes
|
|
||||||
fi
|
|
||||||
|
|
||||||
cp -v setup/icons/24x24/novelwriter.png /usr/share/icons/hicolor/24x24/apps/
|
|
||||||
cp -v setup/icons/48x48/novelwriter.png /usr/share/icons/hicolor/48x48/apps/
|
|
||||||
cp -v setup/icons/96x96/novelwriter.png /usr/share/icons/hicolor/96x96/apps/
|
|
||||||
cp -v setup/icons/256x256/novelwriter.png /usr/share/icons/hicolor/256x256/apps/
|
|
||||||
cp -v setup/icons/512x512/novelwriter.png /usr/share/icons/hicolor/512x512/apps/
|
|
||||||
cp -v setup/icons/novelwriter.svg /usr/share/icons/hicolor/scalable/apps/
|
|
||||||
cp -v setup/icons/x-novelwriter-project.svg /usr/share/icons/hicolor/scalable/mimetypes/application-x-novelwriter-project.svg
|
|
||||||
cp -v setup/mime/x-novelwriter-project.xml /usr/share/mime/packages/
|
|
||||||
|
|
||||||
update-mime-database /usr/share/mime/
|
|
||||||
update-icon-caches /usr/share/icons/*
|
|
||||||
@@ -0,0 +1,52 @@
|
|||||||
|
; 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}_win_amd64_setup
|
||||||
|
Compression=lzma
|
||||||
|
SolidCompression=yes
|
||||||
|
WizardStyle=modern
|
||||||
|
ArchitecturesInstallIn64BitMode=x64
|
||||||
|
|
||||||
|
[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
|
||||||
|
Name: "{userappdata}\Microsoft\Internet Explorer\Quick Launch\{#nwAppName}"; Filename: "{app}\{#nwAppExeName}"; Tasks: quicklaunchicon
|
||||||
|
|
||||||
|
[Run]
|
||||||
|
Filename: "{app}\{#nwAppExeName}"; Description: "{cm:LaunchProgram,{#StringChange(nwAppName, '&', '&&')}}"; Flags: nowait postinstall skipifsilent
|
||||||
Reference in New Issue
Block a user