diff --git a/README.md b/README.md index be86e0f4..f8d19eb6 100644 --- a/README.md +++ b/README.md @@ -65,30 +65,42 @@ You can update novelWriter to the latest version by running: pip install --upgrade novelwriter ``` -The application can then be started with one of the commands, depending on your Python configuration: -```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. +## Installing from Source (Linux) + +You can then install novelWriter from the source directly 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. + +It may prompt you to choose which executable to configure. +You can also use this to configure it to run from source. + +## Running from Source (Linux) + +If you want to run directly from the source, the application can be started with: +```bash +./novelWriter.py +``` + +You can also create a launcher for the source with: +```bash +sudo python3 setup.py launcher +``` + For more install options, see [Build and Install novelWriter](setup/BUILD.md). -### 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. @@ -99,7 +111,7 @@ Minimum version of Qt is 5.2. Generally, dependencies can be installed via `pip` with: ```bash -pip3 install -r requirements.txt +pip install -r requirements.txt ``` You can also install the packages from the distro's own package manager. @@ -144,6 +156,9 @@ 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 an installer. +See [Build and Install novelWriter](setup/BUILD.md) for more details. + ### Package Versions diff --git a/setup.py b/setup.py index 403a71f2..4683e3f2 100755 --- a/setup.py +++ b/setup.py @@ -1,12 +1,13 @@ #!/usr/bin/env python3 import os import sys +import shutil import subprocess import setuptools -# =========================================================================== # +# =============================================================================================== # # Qt Assistant Documentation Builder -# =========================================================================== # +# =============================================================================================== # def buildQtDocs(): """This function will build the documentation as a Qt help file. The @@ -77,9 +78,9 @@ def buildQtDocs(): return -# =========================================================================== # +# =============================================================================================== # # Sample Project ZIP File Builder -# =========================================================================== # +# =============================================================================================== # def buildSampleZip(): """Bundle the sample project into a single zip file to be saved into @@ -117,13 +118,173 @@ def buildSampleZip(): return -# =========================================================================== # +# =============================================================================================== # +# Create Launcher +# =============================================================================================== # + +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__": - # Process non-standard jobs + 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") @@ -133,7 +294,11 @@ if __name__ == "__main__": sys.argv.remove("sample") buildSampleZip() - if len(sys.argv) == 1: + if "launcher" in sys.argv: + sys.argv.remove("launcher") + makeLauncherLinux() + + if len(sys.argv) <= 1: # Nothing more to do sys.exit(0) diff --git a/setup/BUILD.md b/setup/BUILD.md index d97e702a..81479cf7 100644 --- a/setup/BUILD.md +++ b/setup/BUILD.md @@ -2,6 +2,7 @@ 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: @@ -10,8 +11,10 @@ The `setup.py` is a standard Python setup script with a couple of additional opt 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. + 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 diff --git a/setup/installDebianUbuntu.sh b/setup/installDebianUbuntu.sh deleted file mode 100755 index c47f4d26..00000000 --- a/setup/installDebianUbuntu.sh +++ /dev/null @@ -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/*