Merge pull request #480 from vkbo/setup

Setup and Install
This commit is contained in:
Veronica K. Berglyd Olsen
2020-10-17 17:28:47 +02:00
committed by GitHub
11 changed files with 763 additions and 250 deletions
+1
View File
@@ -5,6 +5,7 @@
/deploy/
*.spec
*.egg-info
setup.iss
# Documentation
/docs/build/
+61 -44
View File
@@ -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.
## 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
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
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
./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`.
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:
You can also create a launcher for running directly from source with:
```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 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)
For more install options, see [Build and Install novelWriter](setup/BUILD.md).
### macOS
## macOS
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.
@@ -126,11 +128,16 @@ It comes with a lot of default dictionaries.
brew install enchant
```
### Windows
On Windows, the `pip install` command is generally sufficient to install everything you need.
That should also install the Qt libraries and the spell check dictionary dependencies.
On Windows, you may first need to install Python.
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
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
```
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
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
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.
-1
View File
@@ -12,7 +12,6 @@
# 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.
#
# import os
# import sys
# sys.path.insert(0, os.path.abspath("."))
import os
-84
View File
@@ -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("")
Executable
+331
View File
@@ -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
+3
View File
@@ -0,0 +1,3 @@
[build-system]
requires = ["setuptools", "wheel"]
build-backend = "setuptools.build_meta"
+44 -1
View File
@@ -1,6 +1,49 @@
[metadata]
license_files = LICENSE.md
name = novelWriter
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]
universal = 0
+224 -78
View File
@@ -1,30 +1,26 @@
#!/usr/bin/env python3
import os
import sys
import shutil
import subprocess
import setuptools
##
# Build the Package
##
# =============================================================================================== #
# Qt Assistant Documentation Builder
# =============================================================================================== #
buildDocs = False
buildSample = False
def buildQtDocs():
"""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:
buildDocs = True
sys.argv.remove("qthelp")
if "sample" in sys.argv:
buildSample = True
sys.argv.remove("sample")
##
# Qt Assistant Documentation
##
if buildDocs:
Depends on packages:
* pip install sphinx
* pip install sphinx-rtd-theme
* pip install sphinxcontrib-qthelp
It also requires the qhelpgenerator to be available on the system.
"""
buildDir = os.path.join("docs", "build", "qthelp")
helpDir = os.path.join("nw", "assets", "help")
@@ -41,14 +37,14 @@ if buildDocs:
try:
subprocess.call(["make", "-C", "docs", "qthelp"])
except Exception as e:
print("Failed with error:")
print("QtHelp Build Error:")
print(str(e))
buildFail = True
try:
subprocess.call(["qhelpgenerator", os.path.join(buildDir, inFile)])
except Exception as e:
print("Failed with error:")
print("QtHelp Build Error:")
print(str(e))
buildFail = True
@@ -56,7 +52,7 @@ if buildDocs:
try:
os.mkdir(helpDir)
except Exception as e:
print("Failed with error:")
print("QtHelp Build Error:")
print(str(e))
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, datFile), os.path.join(helpDir, datFile))
except Exception as e:
print("Failed with error:")
print("QtHelp Build Error:")
print(str(e))
buildFail = True
@@ -80,11 +76,20 @@ if buildDocs:
print("Documentation build: OK")
print("")
##
# Sample Project ZIP file
##
return
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"
dstSample = os.path.join("nw", "assets", "sample.zip")
@@ -96,8 +101,10 @@ if buildSample:
from zipfile import ZipFile
with ZipFile(dstSample, "w") as zipObj:
print("Compressing: nwProject.nwx")
zipObj.write(os.path.join(srcSample, "nwProject.nwx"), "nwProject.nwx")
for docFile in os.listdir(os.path.join(srcSample, "content")):
print("Compressing: content/%s" % docFile)
srcDoc = os.path.join(srcSample, "content", docFile)
zipObj.write(srcDoc, "content/"+docFile)
@@ -105,58 +112,197 @@ if buildSample:
print("Error: Could not find sample project source directory.")
sys.exit(1)
if len(sys.argv) == 1:
# Nothing more to do
sys.exit(0)
print("")
print("Built file: %s" % dstSample)
print("")
##
# Build the Package
##
return
# Read content from files
with open("README.md", "r") as inFile:
longDescription = inFile.read()
# =============================================================================================== #
# Create Launcher
# =============================================================================================== #
setuptools.setup(
name = "novelWriter",
# version = __version__, # Set in setup.cfg
author = "Veronica Berglyd Olsen",
author_email = "code@vkbo.net",
description = "A markdown-like document editor for writing novels",
long_description = longDescription,
long_description_content_type = "text/markdown",
license = "GNU General Public License v3",
url = "https://novelwriter.io",
entry_points = {
"console_scripts" : ["novelWriter-cli=nw:main"],
"gui_scripts" : ["novelWriter=nw:main"],
},
packages = setuptools.find_packages(exclude=["docs", "tests", "sample"]),
include_package_data = True,
package_data = {"": ["*.conf"]},
project_urls = {
"Bug Tracker": "https://github.com/vkbo/novelWriter/issues",
"Documentation": "https://github.com/vkbo/novelWriter/issues",
"Source Code": "https://github.com/vkbo/novelWriter",
},
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",
],
)
def makeLauncherLinux():
"""Will attempt to install icons and make a launcher.
"""
print("")
print("Creating Launcher")
print("=================")
print("")
exOpts = []
testExec = shutil.which("novelWriter")
if testExec is not None:
exOpts.append(testExec)
testExec = shutil.which("novelwriter")
if testExec is not None:
exOpts.append(testExec)
testExec = os.path.join(os.getcwd(), "novelWriter.py")
if os.path.isfile(testExec):
exOpts.append(testExec)
useExec = ""
nOpts = len(exOpts)
if nOpts == 0:
print("Error: No executables for novelWriter found.")
sys.exit(1)
elif nOpts == 1:
useExec = exOpts[0]
else:
print("Found multiple novelWriter executables:")
print("")
for iExec, anExec in enumerate(exOpts):
print(" [%d] %s" % (iExec, anExec))
print("")
intVal = int(input("Please select which novelWriter executable to use: "))
print("")
if intVal >= 0 and intVal < nOpts:
useExec = exOpts[intVal]
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
+47
View File
@@ -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
```
-42
View File
@@ -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/*
+52
View File
@@ -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