Add PPA support (#880)

* Clean up a few things in various setup function
* Add Launchpad-related setting to Debian build function
* Add signature feature to package builder and fix error in debian/copyright
* Update documentation
* Update README
This commit is contained in:
Veronica Berglyd Olsen
2021-09-08 20:38:35 +02:00
committed by GitHub
parent a9cd0b29d4
commit 50d0c1eb29
9 changed files with 428 additions and 226 deletions
+33 -67
View File
@@ -32,6 +32,28 @@ The application is written in Python 3 (3.6+) using Qt5 and PyQt5 (5.3+). It is
but should in principle work fine on other operating systems as well as long as dependencies are but should in principle work fine on other operating systems as well as long as dependencies are
met. It is regularly tested on Debian and Ubuntu Linux, Windows, and macOS. met. It is regularly tested on Debian and Ubuntu Linux, Windows, and macOS.
## Installation
### Ubuntu and Debian
The Releases page has a `.deb` package (from version 1.5rc1 and on) that should install on both
Debian and Ubuntu.
You can also use the novelWriter [PPA](https://launchpad.net/~vkbo/+archive/ubuntu/novelwriter).
For more details, check the [Linux](https://novelwriter.readthedocs.io/en/latest/setup_linux.html)
setup chapter in the documentation.
### Other Operating Systems
For a regular installation, it is recommended that you download one of the minimal zip files from
the [Releases](https://github.com/vkbo/novelWriter/releases) page or the
[novelwriter.io](https://novelwriter.io/) website.
The [documentation](https://novelwriter.readthedocs.io/) has detailed install instructions for
[Linux](https://novelwriter.readthedocs.io/en/latest/setup_linux.html),
[Windows](https://novelwriter.readthedocs.io/en/latest/setup_windows.html), and
[macOS](https://novelwriter.readthedocs.io/en/latest/setup_mac.html).
They are pretty straightforward.
## Project Contributions ## Project Contributions
Please don't make feature pull requests without first having discussed them with the maintainer. Please don't make feature pull requests without first having discussed them with the maintainer.
@@ -48,8 +70,8 @@ New translations are always welcome. Please read the additional
## Key Features ## Key Features
Some key features of novelWriter are listed below. Consult the Some key features of novelWriter are listed below. The
[documentation](https://novelwriter.readthedocs.io) for more information. [documentation](https://novelwriter.readthedocs.io) has a lot more information.
### Formatting Codes ### Formatting Codes
@@ -64,19 +86,17 @@ set of formatting that is useful for the specific task of writing novels.
| `~~` | Wrapped | Strikethrough text. | | `~~` | Wrapped | Strikethrough text. |
| `%` | Prefix | A comment; does not count towards the word count.<sup>1</sup> | | `%` | Prefix | A comment; does not count towards the word count.<sup>1</sup> |
| `@` | Prefix | The following text is parsed as a keyword/value command for meta data. | | `@` | Prefix | The following text is parsed as a keyword/value command for meta data. |
| `>` | Prefix | The paragraph is indented one tab width from the left.<sup>2</sup> | | `>` | Prefix | The paragraph is indented one tab width from the left. |
| `<` | Suffix | The paragraph is indented one tab width from the right.<sup>2</sup> | | `<` | Suffix | The paragraph is indented one tab width from the right. |
| `>>` | Prefix | The paragraph is right-aligned.<sup>2</sup> | | `>>` | Prefix | The paragraph is right-aligned. |
| `<<` | Suffix | The paragraph is left-aligned.<sup>2</sup> | | `<<` | Suffix | The paragraph is left-aligned. |
| `>>`, `<<` | Wrapped | The paragraph is centred.<sup>2</sup> | | `>>`, `<<` | Wrapped | The paragraph is centred. |
<sup>1</sup> If the first word of the comment is `synopsis:`, the comment is indexed and treated as the <sup>1</sup> If the first word of the comment is `synopsis:`, the comment is indexed and treated as the
synopsis for the section of text where it occurs. These synopsis comments can be used to build an synopsis for the section of text where it occurs. These synopsis comments can be used to build an
outline and exported to external documents. outline and exported to external documents.
<sup>2</sup> The indent and alignment codes are available from version 1.4. In addition:
In additions:
* A variety of thin and non-breaking spaces are supported. Some of them depend on the system * A variety of thin and non-breaking spaces are supported. Some of them depend on the system
running at least Qt 5.9. Earlier versions of Qt will unfortunately strip them out when saving. running at least Qt 5.9. Earlier versions of Qt will unfortunately strip them out when saving.
@@ -129,72 +149,18 @@ scene connects to the plot, and which characters, etc. occur in them. In additio
themselves are clickable in the document view pane, and control-clickable in the editor. They make themselves are clickable in the document view pane, and control-clickable in the editor. They make
it possible to quickly navigate between the documents while writing. it possible to quickly navigate between the documents while writing.
## Standard Installation ## Installing or Running from Source
For a regular installation, it is recommended that you download one of the minimal zip files from
the [Releases](https://github.com/vkbo/novelWriter/releases) page or the
[novelwriter.io](https://novelwriter.io/) website.
The [documentation](https://novelwriter.readthedocs.io/) has detailed install instructions for
[Linux](https://novelwriter.readthedocs.io/en/latest/setup_linux.html),
[Windows](https://novelwriter.readthedocs.io/en/latest/setup_windows.html), and
[macOS](https://novelwriter.readthedocs.io/en/latest/setup_mac.html).
They are pretty straightforward.
## Running from Source
If you want to run novelWriter directly from the source code, you must run the `novelWriter.py` If you want to run novelWriter directly from the source code, you must run the `novelWriter.py`
file from command line. file from command line.
**Note:** You may need to replace `python` with `python3` and `pip` with `pip3` in the instructions
below on some systems. You may also want to add the `--user` flag for `pip` to install in your user
space only.
### Dependencies
Dependencies can generally be installed from PyPi with: Dependencies can generally be installed from PyPi with:
```bash ```bash
pip install -r requirements.txt pip install -r requirements.txt
``` ```
### Additional Steps for Linux For more details on running or installing from source, see
[Other Setup Methods](https://novelwriter.readthedocs.io/en/latest/setup_other.html).
On Linux, you can most likely find the dependencies in your distribution's repository. On Ubuntu
and Debian, run:
```bash
sudo apt install python3-pyqt5 python3-lxml python3-enchant
```
If you want to set up a launcher and icons on Linux, you can run:
```bash
python setup.py xdg-install
```
### Additional Steps for macOS
First, make sure you have properly set up Python3 with Homebrew. If not, check their
[documentation](https://docs.brew.sh/Homebrew-and-Python).
In addition, the following steps are necessary to install all dependencies:
```bash
brew install enchant
pip3 install --user -r requirements.txt
pip3 install --user pyobjc
```
### Additional Steps for Windows
Windows does not by default come with Python installed. If you haven't installed it already, get it
from [python.org/downloads](https://www.python.org/downloads/). Remember to select "Add Python to
PATH" during the installation.
The script `windows_install.bat` in the `setup` folder can be used to create desktop and start menu
icons for novelWriter. The script will also install dependencies for you from PyPi.
### Internationalisation
If you install from source, you must build the translation files yourself if you want to switch to
a different GUI language than British English. This requires that you have the Qt translation
framework installed. Check the specific instruction in the README in the `i18n` source folder for
how to build the translation files.
## Debugging ## Debugging
+4 -8
View File
@@ -4,7 +4,7 @@ novelWriter |release|
.. only:: html .. only:: html
.. image:: https://github.com/vkbo/novelWriter/workflows/python%203.8/badge.svg?branch=main .. image:: https://github.com/vkbo/novelWriter/actions/workflows/test_linux.yml/badge.svg?branch=main
:target: https://github.com/vkbo/novelWriter/actions :target: https://github.com/vkbo/novelWriter/actions
:alt: Python Tests :alt: Python Tests
@@ -12,10 +12,6 @@ novelWriter |release|
:target: https://codecov.io/gh/vkbo/novelWriter :target: https://codecov.io/gh/vkbo/novelWriter
:alt: Code Coverage :alt: Code Coverage
.. image:: https://readthedocs.org/projects/novelwriter/badge/?version=latest
:target: https://novelwriter.readthedocs.io/en/latest/?badge=latest
:alt: Documentation
.. image:: https://img.shields.io/github/v/release/vkbo/novelwriter .. image:: https://img.shields.io/github/v/release/vkbo/novelwriter
:target: https://github.com/vkbo/novelWriter/releases :target: https://github.com/vkbo/novelWriter/releases
:alt: GitHub Release :alt: GitHub Release
@@ -47,8 +43,8 @@ too. novelWriter can be run directly from the Python source, installed from the
You can also download a minimal archive package of novelWriter tailored for your operating system. You can also download a minimal archive package of novelWriter tailored for your operating system.
This package can be extracted anywhere on your computer, and a setup script can be run to create This package can be extracted anywhere on your computer, and a setup script can be run to create
the necessary icons and file associations. See :ref:`a_started`, or one or the setup instructions the necessary icons and file associations. See the setup instructions for your operating system for
for your operating system for further details. further details.
.. note:: .. note::
Version 1.5 introduces a few changes that will require you to make a few minor modifications to Version 1.5 introduces a few changes that will require you to make a few minor modifications to
@@ -71,10 +67,10 @@ for your operating system for further details.
:caption: Introduction :caption: Introduction
int_introduction int_introduction
int_started
setup_linux setup_linux
setup_mac setup_mac
setup_windows setup_windows
setup_other
.. toctree:: .. toctree::
+81 -60
View File
@@ -6,19 +6,77 @@ Setup on Linux
.. _GitHub: https://github.com/vkbo/novelWriter/releases .. _GitHub: https://github.com/vkbo/novelWriter/releases
.. _main website: https://novelwriter.io .. _main website: https://novelwriter.io
.. _PPA: https://launchpad.net/~vkbo/+archive/ubuntu/novelwriter
.. _Pre-Release PPA: https://launchpad.net/~vkbo/+archive/ubuntu/novelwriter-pre
This is a brief guide to how you can get novelWriter running on a Linux computer. There are This is a brief guide to how you can get novelWriter running on a Linux computer.
currently no install package of novelWriter for Linux, so it is recommended that you download
either the full source or minimal package and extract it to a practical location on your system and There are currently install packages available for Ubuntu and Debian. For other distros it is
run the ``setup.py`` script. recommended that you download either the full source or minimal package and extract it to a
practical location on your system and run the ``setup.py`` script.
Running from Source Debian or Ubuntu
=================== ================
To run novelWriter from source, download the latest source package from the release page on A general Debian package can be downloaded from the `main website`_. This package should work on
GitHub_ or the `main website`_, or if you have git running on your computer, you can also clone the both Debian and Ubuntu.
repository.
If you prefer, you can also add the novelWriter repository on Launchpad to your package manager.
Ubuntu
------
You can add the Ubuntu PPA_ and install novelWriter with the following commands.
.. code-block:: console
sudo add-apt-repository ppa:vkbo/novelwriter
sudo apt update
sudo apt install novelwriter
Debian
------
Since this is a pure Python package, the Launchpad PPA can in principle also be used on Debian.
However, the above command will fail to add the signing key.
Instead, run the following commands to add the repository and key:
.. code-block:: console
sudo mkdir -p /usr/local/share/keyrings/
sudo gpg --no-default-keyring --keyring /usr/local/share/novelwriter-keyring.gpg --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys F19F1FCE50043114
echo "deb [signed-by=/usr/local/share/keyrings/novelwriter-keyring.gpg] http://ppa.launchpad.net/vkbo/novelwriter/ubuntu focal main" | sudo tee /etc/apt/sources.list.d/novelwriter.list
Then run the update and install command:
.. code-block:: console
sudo apt update
sudo apt install novelwriter
Pre-Releases
------------
There is also a `Pre-Release PPA`_ available beta releases and release candidates.
.. code-block:: console
sudo add-apt-repository ppa:vkbo/novelwriter-pre
sudo apt update
sudo apt install novelwriter
Minimal Zip File
================
A minimal zip file is provided for Linux. You can download the latest zip file from the release
page on GitHub_, or from the `main website`_. This zip file contains only the main files needed to
run novelWriter. You can extract the file to wherever you want, and run the steps below.
Step 1: Installing Dependencies Step 1: Installing Dependencies
@@ -39,72 +97,35 @@ can install them with:
pip3 install --user -r requirements.txt pip3 install --user -r requirements.txt
Step 2: Install Package (Optional) Step 2: Create Launcher Icons
----------------------------------
You can install novelWriter to the default location for Python packages using ``setuptools``. This
step is optional as you can also just put the novelWriter program folder wherever you like
yourself. For instance in ``/opt/novelWriter``, and then run Step 3 to set up icons and launcher.
To install novelWriter to the default location requires that you have ``setuptools`` installed on
your system. If you don't have it installed, it can usually be installed from your distro's
repository. For Debian and Ubuntu this is achieved with:
.. code-block:: console
sudo apt install python3-setuptools
The package is also available from PyPi:
.. code-block:: console
pip3 install --user setuptools
With ``setuptools`` in place, novelWriter can be installed to the user space with:
.. code-block:: console
./setup.py install --user
This should install novelWriter as ``~/.local/bin/novelWriter``. If you instead want to install for
all users, i.e. as ``/usr/local/bin/novelWriter``, run:
.. code-block:: console
sudo ./setup.py install
This is equivalent to what the ``pip`` installer does. It puts novelWriter in the location on your
system where Python packages are usually kept. This is not really the best suited location for a
GUI application like novelWriter, so you may instead copy the entire source to a suiteable location
yourself.
Step 3: Create Launcher Icons
----------------------------- -----------------------------
Regardless of where you extract or install the source files, you can set up a standard icon and a A standard desktop launcher can be installed via the main setup script. It will create the needed
launcher. To set up this desktop launcher, the needed icons, and the project file association, desktop file and add it to the Applications menu. The necessary icons will also be installed, and a
run the following from inside the novelWriter folder at the installed or final location: file association with ``.nwx`` files added.
To set this up, run the following from inside the novelWriter folder at the final location:
.. code-block:: console .. code-block:: console
./setup.py xdg-install python3 setup.py xdg-install
By default, this command installs the launcher and icons for the current user only. To install for This will only install the launcher and icons for the current user. To set up novelWriter for all
all users, run the script with the ``sudo`` command. users, run:
.. tip:: .. code-block:: console
All options of the setup script can be listed with: ``./setup.py help``.
sudo python3 setup.py xdg-install
Uninstalling Icons Uninstalling Icons
================== ------------------
The steps taken by the ``xdg-install`` step can be reversed by running: The steps taken by the ``xdg-install`` step can be reversed by running:
.. code-block:: console .. code-block:: console
./setup.py xdg-uninstall python3 setup.py xdg-uninstall
This will remove the desktop launcher and icons from the system. As above, whether this is done on This will remove the desktop launcher and icons from the system. As above, whether this is done on
the current user, or system wide, depends on whether this command is called with ``sudo`` or not. the current user, or system wide, depends on whether this command is called with ``sudo`` or not.
@@ -1,25 +1,16 @@
.. _a_started: .. _a_other:
*************** *******************
Getting Started Other Setup Methods
*************** *******************
.. _main website: https://novelwriter.io .. _main website: https://novelwriter.io
.. _GitHub: https://github.com/vkbo/novelWriter/releases .. _GitHub: https://github.com/vkbo/novelWriter/releases
.. _PyPi: https://pypi.org/project/novelWriter/ .. _PyPi: https://pypi.org/project/novelWriter/
.. _Sphinx Docs: https://www.sphinx-doc.org/
This section contains brief guides to how you can get novelWriter running on your computer. These This section describes various other setup methods, and instructions for building needed files
are the methods currently supported by the developer. Packages may also be available in other when running novelWriter from the source code directly.
package managers, but those are not managed by the developer. No installers are provided at this
time, but it is fairly straightforward to set up novelWriter with the provided install scripts.
As novelWriter matures, more options for how to install it and get it running will be added. For
non-Windows users the install process is at the present time best suited for people used to working
with the command line. But even if you're not, the install process is fairly straightforward.
The next pages have specific install instructions for the various operating systems novelWriter can
run on. The instructions below are supplementary information, instructions for alterbative methods,
and additional build options.
.. note:: .. note::
The text below assumes the command ``python`` corresponds to a Python 3 executable. Python 2 is The text below assumes the command ``python`` corresponds to a Python 3 executable. Python 2 is
@@ -28,7 +19,7 @@ and additional build options.
without the ``python`` command. Likewise, ``pip`` may need to be replaced with ``pip3``. without the ``python`` command. Likewise, ``pip`` may need to be replaced with ``pip3``.
.. _a_started_depend: .. _a_other_depend:
Dependencies Dependencies
============ ============
@@ -41,7 +32,7 @@ The following Python packages are needed to run novelWriter:
* ``PyQt5`` needed for connecting with the Qt5 libraries. * ``PyQt5`` needed for connecting with the Qt5 libraries.
* ``lxml`` needed for full XML support. * ``lxml`` needed for full XML support.
* ``PyEnchant`` needed for efficient spell checking (optional). * ``PyEnchant`` needed for spell checking (optional).
PyQt/Qt should be at least 5.3, but ideally 5.10 or higher for nearly all features to work. For PyQt/Qt should be at least 5.3, but ideally 5.10 or higher for nearly all features to work. For
instance, searching using regular expressions with full Unicode support requires 5.13. There is no instance, searching using regular expressions with full Unicode support requires 5.13. There is no
@@ -59,23 +50,17 @@ source, dependencies can still be installed from PyPi with:
pip install -r requirements.txt pip install -r requirements.txt
.. _a_started_install: .. _a_other_pip:
Installing from Source or PyPi Installing from PyPi
============================== ====================
You can download the latest version of novelWriter from the source repository on GitHub_. You can novelWriter is available on the Python Package Index, or PyPi_.
also install novelWriter from PyPi_.
If you're running novelWriter from source, the main setup script has a number of options that may
be useful to you. You can list them by running:
.. code-block:: console
python setup.py --help
To install from PyPi you must first have the ``python`` and ``pip`` commands available on your To install from PyPi you must first have the ``python`` and ``pip`` commands available on your
system. If you don't, see specific instructions for your operating system in this documentation. system. If you don't, see specific instructions for your operating system in this documentation on
how to get the Python environment set up.
To install novelWriter from PyPi, use the following command: To install novelWriter from PyPi, use the following command:
.. code-block:: console .. code-block:: console
@@ -98,7 +83,42 @@ Make sure the install location for pip is in your PATH variable. This is not alw
default. default.
.. _a_started_i18n: .. _a_other_source:
Installing from Source
======================
You can download the latest version of novelWriter from the source repository on GitHub_ and run
the setup manually. It is equivalent to what the ``pip install`` command does, and it installs
novelWriter to the default location for Python packages.
This step requires that you have ``setuptools`` installed on your system. If you don't have it
installed, it can usually be installed from your distro's repository. For Debian and Ubuntu this is
achieved with:
.. code-block:: console
sudo apt install python3-setuptools
The package is also available from PyPi:
.. code-block:: console
pip install --user setuptools
With ``setuptools`` in place, novelWriter can be installed to the user space with:
.. code-block:: console
python setup.py install --user
.. tip::
The main setup script has a number of options that may be useful to you. You can list them by
running ``python setup.py --help``.
.. _a_other_i18n:
Building the Translation Files Building the Translation Files
============================== ==============================
@@ -112,7 +132,7 @@ You can build the ``.qm`` files with:
.. code-block:: console .. code-block:: console
python3 setup.py qtlrelease python setup.py qtlrelease
This requires that the Qt Linguist tool is installed on your system. On Ubuntu and Debian, the This requires that the Qt Linguist tool is installed on your system. On Ubuntu and Debian, the
needed package is called `qttools5-dev-tools`. needed package is called `qttools5-dev-tools`.
@@ -123,14 +143,13 @@ needed package is called `qttools5-dev-tools`.
the ``i18n`` folder of the source code. the ``i18n`` folder of the source code.
.. _a_started_docs: .. _a_other_docs:
Building the Documentation Building the Documentation
========================== ==========================
If you installed novelWriter from a package, the documentation should be pre-built and included. If A local copy of this documentation can be generated as HTML. This requires the following Python
you're running novelWriter from the source code, a local copy of this documentation can be packages on Debian and Ubuntu.
generated. It requires the following Python packages on Debian and Ubuntu.
* ``python3-sphinx`` * ``python3-sphinx``
* ``python3-sphinx-rtd-theme`` * ``python3-sphinx-rtd-theme``
@@ -150,15 +169,13 @@ The documentation can then be built from the ``docs`` folder in the source code
If successful, the documentation should be available in the ``docs/build/html`` folder and you can If successful, the documentation should be available in the ``docs/build/html`` folder and you can
open the ``index.html`` file in your browser. open the ``index.html`` file in your browser.
You can also build the PDF documentation locally using the setup script: You can also build a PDF manual from the documentation using the setup script:
.. code-block:: console .. code-block:: console
python setup.py pdfdocs python setup.py manual
This will build the documentation as a PDF using LaTeX. The file will then be copied into the This will build the documentation as a PDF using LaTeX. The file will then be copied into the
assets folder and made available in the :guilabel:`Help` menu in novelWriter. The Sphinx build assets folder and made available in the :guilabel:`Help` menu in novelWriter. The Sphinx build
system has a few extra dependencies when building the PDF. Please check the `Sphinx Docs`_ if you system has a few extra dependencies when building the PDF. Please check the `Sphinx Docs`_ for more
have any issues. details.
.. _Sphinx Docs: https://www.sphinx-doc.org/
+201 -42
View File
@@ -66,8 +66,7 @@ def extractVersion():
print("Could not read file: %s" % initFile) print("Could not read file: %s" % initFile)
print(str(e)) print(str(e))
print("novelWriter version is: %s (%s) at %s" % (numVers, hexVers, relDate)) print("novelWriter version: %s (%s) at %s" % (numVers, hexVers, relDate))
print("")
return numVers, hexVers, relDate return numVers, hexVers, relDate
@@ -80,28 +79,43 @@ def compactVersion(numVers):
return numVers return numVers
def sysCall(callArgs): def sysCall(callArgs, cwd=None):
"""Wrapper function for system calls. """Wrapper function for system calls.
""" """
sysP = subprocess.Popen(callArgs, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True) sysP = subprocess.Popen(
callArgs, stdout=subprocess.PIPE, stderr=subprocess.PIPE,
shell=True, cwd=cwd
)
stdOut, stdErr = sysP.communicate() stdOut, stdErr = sysP.communicate()
return stdOut.decode("utf-8"), stdErr.decode("utf-8"), sysP.returncode return stdOut.decode("utf-8"), stdErr.decode("utf-8"), sysP.returncode
def readFile(fileName): def readFile(fileName):
"""Read an entire file return as a string. """Read an entire file and return as a string.
""" """
with open(fileName, mode="r") as inFile: with open(fileName, mode="r") as inFile:
return inFile.read() return inFile.read()
def writeFile(fileName, writeText): def writeFile(fileName, writeText):
"""Write string to file """Write string to file.
""" """
with open(fileName, mode="w+") as outFile: with open(fileName, mode="w+") as outFile:
outFile.write(writeText) outFile.write(writeText)
def toUpload(srcPath, dstName=None):
"""Copy a file produced by one of the build functions to the uplaod
directory. The file can optionally be given a new name."""
uplDir = "dist_upload"
if not os.path.isdir(uplDir):
os.mkdir(uplDir)
if dstName is None:
dstName = os.path.basename(srcPath)
shutil.copyfile(srcPath, os.path.join(uplDir, dstName))
return
# =============================================================================================== # # =============================================================================================== #
# General # General
# =============================================================================================== # # =============================================================================================== #
@@ -140,10 +154,10 @@ def installPackages(hostOS):
## ##
# Clean Build and Dist Folders (clean) # Clean Build and Dist Folders (build-clean)
## ##
def cleanInstall(): def cleanBuildDirs():
"""Recursively delete the 'build' and 'dist' folders. """Recursively delete the 'build' and 'dist' folders.
""" """
print("") print("")
@@ -156,7 +170,7 @@ def cleanInstall():
shutil.rmtree(rmDir) shutil.rmtree(rmDir)
print("Deleted: %s" % rmDir) print("Deleted: %s" % rmDir)
except OSError: except OSError:
pass print("Failed: %s" % rmDir)
else: else:
print("Missing: %s" % rmDir) print("Missing: %s" % rmDir)
@@ -191,11 +205,19 @@ def buildPdfManual():
finalFile = os.path.join("novelwriter", "assets", "manual.pdf") finalFile = os.path.join("novelwriter", "assets", "manual.pdf")
try: try:
subprocess.call(["make", "-C", "docs", "clean"]) subprocess.call(["make", "clean"], cwd="docs")
_, stdErr, exCode = sysCall(["make -C docs latexpdf"]) stdOut, stdErr, exCode = sysCall(["make latexpdf"], cwd="docs")
if exCode == 0: if exCode == 0:
if os.path.isfile(finalFile): if os.path.isfile(finalFile):
os.unlink(finalFile) os.unlink(finalFile)
outLines = stdOut.splitlines()
for aLine in outLines:
if aLine.startswith("processing manual.tex..."):
break
print(aLine)
print("\n[LaTeX output truncated ...]\n")
print("\n".join(outLines[-6:]))
print("")
os.rename(buildFile, finalFile) os.rename(buildFile, finalFile)
else: else:
raise Exception(stdErr) raise Exception(stdErr)
@@ -234,6 +256,7 @@ def buildQtI18n():
subprocess.call(["lrelease", "-verbose", "novelWriter.pro"]) subprocess.call(["lrelease", "-verbose", "novelWriter.pro"])
except Exception as e: except Exception as e:
print("Qt5 Linguist tools seem to be missing") print("Qt5 Linguist tools seem to be missing")
print("On Debian/Ubuntu, install: qttools5-dev-tools pyqt5-dev-tools")
print(str(e)) print(str(e))
sys.exit(1) sys.exit(1)
@@ -273,6 +296,7 @@ def buildQtI18nTS():
subprocess.call(["pylupdate5", "-verbose", "-noobsolete", "novelWriter.pro"]) subprocess.call(["pylupdate5", "-verbose", "-noobsolete", "novelWriter.pro"])
except Exception as e: except Exception as e:
print("PyQt5 Linguist tools seem to be missing") print("PyQt5 Linguist tools seem to be missing")
print("On Debian/Ubuntu, install: qttools5-dev-tools pyqt5-dev-tools")
print(str(e)) print(str(e))
sys.exit(1) sys.exit(1)
@@ -367,10 +391,12 @@ def makeMinimalPackage(targetOS):
# ================= # =================
numVers, _, _ = extractVersion() numVers, _, _ = extractVersion()
zipFile = f"novelWriter-{numVers}-minimal{targName}.zip" pkgVers = compactVersion(numVers)
zipFile = f"novelWriter-{pkgVers}-minimal{targName}.zip"
outFile = os.path.join(bldDir, zipFile) outFile = os.path.join(bldDir, zipFile)
if os.path.isfile(outFile): if os.path.isfile(outFile):
os.unlink(outFile) os.unlink(outFile)
print("")
rootFiles = [ rootFiles = [
"README.md", "README.md",
@@ -387,10 +413,10 @@ def makeMinimalPackage(targetOS):
for nRoot, _, nFiles in os.walk("novelwriter"): for nRoot, _, nFiles in os.walk("novelwriter"):
if nRoot.endswith("__pycache__"): if nRoot.endswith("__pycache__"):
print("Skipping Folder: %s" % nRoot) print("Skipped: %s" % nRoot)
continue continue
print("Adding Folder: %s [%d files]" % (nRoot, len(nFiles))) print("Added: %s/* [Files: %d]" % (nRoot, len(nFiles)))
for aFile in nFiles: for aFile in nFiles:
if aFile.endswith(".pyc"): if aFile.endswith(".pyc"):
print("Skipping File: %s" % aFile) print("Skipping File: %s" % aFile)
@@ -399,31 +425,31 @@ def makeMinimalPackage(targetOS):
if targetOS == OS_WIN: if targetOS == OS_WIN:
zipObj.write("novelWriter.py", "novelWriter.pyw") zipObj.write("novelWriter.py", "novelWriter.pyw")
print("Adding File: novelWriter.pyw") print("Added: novelWriter.pyw")
zipObj.write(os.path.join("setup", "windows_install.bat"), "windows_install.bat") zipObj.write(os.path.join("setup", "windows_install.bat"), "windows_install.bat")
print("Adding File: windows_install.bat") print("Added: windows_install.bat")
zipObj.write(os.path.join("setup", "windows_uninstall.bat"), "windows_uninstall.bat") zipObj.write(os.path.join("setup", "windows_uninstall.bat"), "windows_uninstall.bat")
print("Adding File: windows_uninstall.bat") print("Added: windows_uninstall.bat")
else: # Linux and Mac else: # Linux and Mac
# Add icons # Add icons
for nRoot, _, nFiles in os.walk(os.path.join("setup", "data")): for nRoot, _, nFiles in os.walk(os.path.join("setup", "data")):
print("Adding Folder: %s [%d files]" % (nRoot, len(nFiles))) print("Added: %s/* [Files: %d]" % (nRoot, len(nFiles)))
for aFile in nFiles: for aFile in nFiles:
zipObj.write(os.path.join(nRoot, aFile)) zipObj.write(os.path.join(nRoot, aFile))
zipObj.write(os.path.join("setup", "description_pypi.md")) zipObj.write(os.path.join("setup", "description_pypi.md"))
print("Adding File: setup/description_pypi.md") print("Added: setup/description_pypi.md")
zipObj.write("novelWriter.py") zipObj.write("novelWriter.py")
print("Adding File: novelWriter.py") print("Added: novelWriter.py")
for aFile in rootFiles: for aFile in rootFiles:
print("Adding File: %s" % aFile) print("Added: %s" % aFile)
zipObj.write(aFile) zipObj.write(aFile)
zipObj.write(os.path.join("novelwriter", "assets", "manual.pdf"), "UserManual.pdf") zipObj.write(os.path.join("novelwriter", "assets", "manual.pdf"), "UserManual.pdf")
print("Adding File: UserManual.pdf") print("Added: UserManual.pdf")
print("") print("")
print("Created File: %s" % outFile) print("Created File: %s" % outFile)
@@ -432,14 +458,17 @@ def makeMinimalPackage(targetOS):
# ==================== # ====================
try: try:
shaFile = open(outFile+".sha256", mode="w") shaFile = outFile+".sha256"
subprocess.call(["sha256sum", zipFile], stdout=shaFile, cwd=bldDir) with open(shaFile, mode="w") as fOut:
shaFile.close() subprocess.call(["sha256sum", zipFile], stdout=fOut, cwd=bldDir)
print("SHA256 Sum: %s" % (outFile+".sha256")) print("SHA256 Sum: %s" % shaFile)
except Exception as e: except Exception as e:
print("Could not generate sha256 file") print("Could not generate sha256 file")
print(str(e)) print(str(e))
toUpload(outFile)
toUpload(shaFile)
print("") print("")
return return
@@ -449,7 +478,7 @@ def makeMinimalPackage(targetOS):
# Make Debian Package (build-deb) # Make Debian Package (build-deb)
## ##
def makeDebianPackage(): def makeDebianPackage(signKey=None, sourceBuild=False, distName="unstable", buildName=""):
"""Build a Debian package. """Build a Debian package.
""" """
print("") print("")
@@ -460,17 +489,21 @@ def makeDebianPackage():
# Version Info # Version Info
# ============ # ============
numVers, _, relDate = extractVersion() numVers, hexVers, relDate = extractVersion()
pkgVers = compactVersion(numVers) pkgVers = compactVersion(numVers)
relDate = datetime.datetime.strptime(relDate, "%Y-%m-%d") relDate = datetime.datetime.strptime(relDate, "%Y-%m-%d")
pkgDate = email.utils.format_datetime(relDate.replace(hour=12, tzinfo=None)) pkgDate = email.utils.format_datetime(relDate.replace(hour=12, tzinfo=None))
print("")
if buildName:
pkgVers = f"{pkgVers}~{buildName}"
# Set Up Folder # Set Up Folder
# ============= # =============
bldDir = "dist_deb" bldDir = "dist_deb"
pkgDir = f"novelWriter-{pkgVers}" bldPkg = f"novelwriter_{pkgVers}"
outDir = f"{bldDir}/{pkgDir}" outDir = f"{bldDir}/{bldPkg}"
debDir = f"{outDir}/debian" debDir = f"{outDir}/debian"
datDir = f"{outDir}/data" datDir = f"{outDir}/data"
@@ -527,7 +560,7 @@ def makeDebianPackage():
# Copy/Write Root Files # Copy/Write Root Files
# ===================== # =====================
copyFiles = ["CREDITS.md", "CHANGELOG.md", "LICENSE.md", "pyproject.toml"] copyFiles = ["LICENSE.md", "CREDITS.md", "CHANGELOG.md", "pyproject.toml"]
for copyFile in copyFiles: for copyFile in copyFiles:
shutil.copyfile(copyFile, f"{outDir}/{copyFile}") shutil.copyfile(copyFile, f"{outDir}/{copyFile}")
print("Copied: %s" % copyFile) print("Copied: %s" % copyFile)
@@ -560,7 +593,7 @@ def makeDebianPackage():
print("Copied: debian/*") print("Copied: debian/*")
writeFile(f"{debDir}/changelog", ( writeFile(f"{debDir}/changelog", (
f"novelwriter ({pkgVers}) unstable; urgency=medium\n\n" f"novelwriter ({pkgVers}) {distName}; urgency=low\n\n"
f" * Update to version {pkgVers}\n\n" f" * Update to version {pkgVers}\n\n"
f" -- Veronica Berglyd Olsen <code@vkbo.net> {pkgDate}\n" f" -- Veronica Berglyd Olsen <code@vkbo.net> {pkgDate}\n"
)) ))
@@ -582,15 +615,101 @@ def makeDebianPackage():
print("Running dpkg-buildpackage ...") print("Running dpkg-buildpackage ...")
print("") print("")
currDir = os.curdir if signKey is None:
os.chdir(outDir) signArgs = ["-us", "-uc"]
subprocess.call(["dpkg-buildpackage", "-us", "-ui", "-uc"]) else:
os.chdir(currDir) signArgs = [f"-k{signKey}"]
if sourceBuild:
subprocess.call(["debuild", "-S"] + signArgs, cwd=outDir)
toUpload(f"{bldDir}/{bldPkg}.tar.xz")
else:
subprocess.call(["dpkg-buildpackage"] + signArgs, cwd=outDir)
toUpload(f"{bldDir}/{bldPkg}.tar.xz", f"{bldPkg}.debian.tar.xz")
toUpload(f"{bldDir}/{bldPkg}_all.deb")
print("") print("")
print("Done!") print("Done!")
print("") print("")
if sourceBuild:
if hexVers[-2] == "f":
ppaName = "novelwriter"
else:
ppaName = "novelwriter-pre"
return f"dput {ppaName}/{distName} {bldDir}/{bldPkg}_source.changes"
return ""
##
# Make Launchpad Package (build-ubuntu)
##
def makeForLaunchpad(doSign=False, isFirst=False, isSnapshot=False):
"""Wrapper for building debian packages for launcpad.
"""
print("")
print("Launchpad Packages")
print("==================")
print("")
if isFirst or isSnapshot:
bldNum = "0"
else:
bldNum = input("Build number [0]: ")
if bldNum == "":
bldNum = "0"
distLoop = [
("18.04", "bionic"),
("20.04", "focal"),
("21.04", "hirsute"),
("21.10", "impish"),
]
tStamp = datetime.datetime.now().strftime("%Y%m%d~%H%M%S")
if isSnapshot:
print(f"Building Ununtu SNAPSHOT~{tStamp} for:")
print("")
else:
print("Building Ubuntu packages for:")
print("")
for distNum, codeName in distLoop:
print(f" * Ubuntu {distNum} {codeName.title()}")
print("")
if doSign:
signKey = "D6A9F6B8F227CF7C6F6D1EE84DBBE4B734B0BD08"
else:
signKey = None
print(f"Sign Key: {str(signKey)}")
print("")
dputCmd = []
for distNum, codeName in distLoop:
if isSnapshot:
buildName = f"SNAPSHOT~{tStamp}~ubuntu{distNum}.0"
else:
buildName = f"ubuntu{distNum}.{bldNum}"
dCmd = makeDebianPackage(
signKey=signKey,
sourceBuild=True,
distName=codeName,
buildName=buildName
)
dputCmd.append(dCmd)
print("Packages Built")
print("==============")
print("")
for dCmd in dputCmd:
print(f" > {dCmd}")
print("")
return return
@@ -1030,6 +1149,7 @@ def winInstall():
if not os.path.isfile(targetPy): if not os.path.isfile(targetPy):
shutil.copy2(os.path.join(targetDir, "novelWriter.py"), targetPy) shutil.copy2(os.path.join(targetDir, "novelWriter.py"), targetPy)
print("")
print("Collecting Info ...") print("Collecting Info ...")
print("Desktop Folder: %s" % desktopDir) print("Desktop Folder: %s" % desktopDir)
print("Start Menu Folder: %s" % startMenuDir) print("Start Menu Folder: %s" % startMenuDir)
@@ -1146,6 +1266,7 @@ def winUninstall():
startMenuProg = os.path.join(startMenuDir, "Programs", "novelWriter") startMenuProg = os.path.join(startMenuDir, "Programs", "novelWriter")
startMenuIcon = os.path.join(startMenuProg, linkName) startMenuIcon = os.path.join(startMenuProg, linkName)
print("")
print("Deleting Links ...") print("Deleting Links ...")
if os.path.isfile(desktopIcon): if os.path.isfile(desktopIcon):
os.unlink(desktopIcon) os.unlink(desktopIcon)
@@ -1217,6 +1338,7 @@ def innoSetup():
issData = issData.replace(r"%%version%%", numVers) issData = issData.replace(r"%%version%%", numVers)
issData = issData.replace(r"%%dir%%", os.getcwd()) issData = issData.replace(r"%%dir%%", os.getcwd())
writeFile("setup.iss", issData) writeFile("setup.iss", issData)
print("")
try: try:
subprocess.call(["iscc", "setup.iss"]) subprocess.call(["iscc", "setup.iss"])
@@ -1260,6 +1382,27 @@ if __name__ == "__main__":
else: else:
targetOS = hostOS targetOS = hostOS
# Sign package
if "--sign" in sys.argv:
sys.argv.remove("--sign")
doSign = True
else:
doSign = False
# First build
if "--first" in sys.argv:
sys.argv.remove("--first")
isFirstBuild = True
else:
isFirstBuild = False
# Build snapshot
if "--snapshot" in sys.argv:
sys.argv.remove("--snapshot")
isSnapshot = True
else:
isSnapshot = False
helpMsg = [ helpMsg = [
"", "",
"novelWriter Setup Tool", "novelWriter Setup Tool",
@@ -1292,8 +1435,12 @@ if __name__ == "__main__":
" all the other source files. Defaults to tailor the zip file", " all the other source files. Defaults to tailor the zip file",
" for the current OS, but accepts a target OS flag to build", " for the current OS, but accepts a target OS flag to build",
" for another OS.", " for another OS.",
" build-deb Buiild a .deb package for Debian and Ubuntu.", " build-deb Build a .deb package for Debian and Ubuntu. Add --sign to ",
" build-pyz Buiild a .pyz package in a folder with all dependencies", " sign package.",
" build-ubuntu Build a .deb packages Launchpad. Add --sign to ",
" sign package. Add --first to set build number to 0.",
" Add --snapshot to make a snapshot package."
" build-pyz Build a .pyz package in a folder with all dependencies",
" using the zipapp tool. On Windows, python embeddable is", " using the zipapp tool. On Windows, python embeddable is",
" added to the folder.", " added to the folder.",
" setup-pyz Build a Windows executable installer from a zipapp package", " setup-pyz Build a Windows executable installer from a zipapp package",
@@ -1340,9 +1487,9 @@ if __name__ == "__main__":
sys.argv.remove("pip") sys.argv.remove("pip")
installPackages(hostOS) installPackages(hostOS)
if "clean" in sys.argv: if "build-clean" in sys.argv:
sys.argv.remove("clean") sys.argv.remove("build-clean")
cleanInstall() cleanBuildDirs()
# Additional Builds # Additional Builds
# ================= # =================
@@ -1373,11 +1520,23 @@ if __name__ == "__main__":
if "build-deb" in sys.argv: if "build-deb" in sys.argv:
sys.argv.remove("build-deb") sys.argv.remove("build-deb")
if hostOS == OS_LINUX: if hostOS == OS_LINUX:
makeDebianPackage() if doSign:
signKey = "D6A9F6B8F227CF7C6F6D1EE84DBBE4B734B0BD08"
else:
signKey = None
makeDebianPackage(signKey=signKey)
else: else:
print("ERROR: Command 'build-deb' can only be used on Linux") print("ERROR: Command 'build-deb' can only be used on Linux")
sys.exit(1) sys.exit(1)
if "build-ubuntu" in sys.argv:
sys.argv.remove("build-ubuntu")
if hostOS == OS_LINUX:
makeForLaunchpad(doSign=doSign, isFirst=isFirstBuild, isSnapshot=isSnapshot)
else:
print("ERROR: Command 'build-ubuntu' can only be used on Linux")
sys.exit(1)
if "build-pyz" in sys.argv: if "build-pyz" in sys.argv:
sys.argv.remove("build-pyz") sys.argv.remove("build-pyz")
simplePack = True simplePack = True
+1 -1
View File
@@ -2,7 +2,7 @@ Source: novelwriter
Maintainer: Veronica Berglyd Olsen <code@vkbo.net> Maintainer: Veronica Berglyd Olsen <code@vkbo.net>
Section: text Section: text
Priority: optional Priority: optional
Build-Depends: dh-python, python3-setuptools, python3-all, debhelper (>= 9) Build-Depends: dh-python, python3-setuptools, python3-all, debhelper (>= 9), python3 (>=3.6), python3-pyqt5 (>= 5.3), python3-lxml (>= 4.0), python3-enchant (>= 2.0)
Standards-Version: 4.5.1 Standards-Version: 4.5.1
Homepage: https://novelwriter.io Homepage: https://novelwriter.io
X-Python3-Version: >= 3.6 X-Python3-Version: >= 3.6
+44 -4
View File
@@ -3,14 +3,54 @@ Upstream-Name: novelWriter
Upstream-Contact: Veronica Berglyd Olsen <code@vkbo.net> Upstream-Contact: Veronica Berglyd Olsen <code@vkbo.net>
Source: https://github.com/vkbo/novelWriter Source: https://github.com/vkbo/novelWriter
Files: *
Copyright: 2018-2021, Veronica Berglyd Olsen
License: GPL-3.0-or-later
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
Files: novelwriter/assets/fonts/Cantarell/* Files: novelwriter/assets/fonts/Cantarell/*
Copyright: 2009-2010, Understanding Limited Copyright: 2009-2010, Understanding Limited
License: OFL-1.1 License: OFL-1.1
This Font Software is licensed under the SIL Open Font License, Version 1.1.
This license is available with a FAQ at: http://scripts.sil.org/OFL
Files: novelwriter/assets/icons/typicons_*.svg Files: novelwriter/assets/icons/typicons_*.svg
Copyright: 2019, Stephen Hutchings Copyright: 2019, Stephen Hutchings
License: CC-BY-SA-4.0 License: CC-BY-SA-4.0
This work is licensed under the Creative Commons Attribution-ShareAlike 4.0
Files: novelwriter/* International License. To view a copy of this license, visit
Copyright: 2018-2021, Veronica Berglyd Olsen http://creativecommons.org/licenses/by-sa/4.0/ or send a letter to Creative
License: GPL-3.0-or-later Commons, PO Box 1866, Mountain View, CA 94042, USA.
.
Share — copy and redistribute the material in any medium or format
.
Adapt — remix, transform, and build upon the material for any purpose, even
commercially. This license is acceptable for Free Cultural Works. The licensor
cannot revoke these freedoms as long as you follow the license terms.
.
Attribution — You must give appropriate credit, provide a link to the license,
and indicate if changes were made. You may do so in any reasonable manner, but
not in any way that suggests the licensor endorses you or your use.
.
ShareAlike — If you remix, transform, or build upon the material, you must
distribute your contributions under the same license as the original.
No additional restrictions — You may not apply legal terms or technological
measures that legally restrict others from doing anything the license permits.
.
Notices: You do not have to comply with the license for elements of the
material in the public domain or where your use is permitted by an applicable
exception or limitation. No warranties are given. The license may not give you
all of the permissions necessary for your intended use. For example, other
rights such as publicity, privacy, or moral rights may limit how you use the
material.
+2
View File
@@ -11,6 +11,8 @@ echo " Building Packages"
echo "================================================================================" echo "================================================================================"
echo "" echo ""
python3 setup.py sdist bdist_wheel python3 setup.py sdist bdist_wheel
mkdir -pv dist_upload
cp -v dist/novelWriter-*.whl dist_upload/
echo "" echo ""
echo " Checking Packages" echo " Checking Packages"
+2 -1
View File
@@ -18,4 +18,5 @@ echo ""
echo " Building Linux Packages" echo " Building Linux Packages"
echo "================================================================================" echo "================================================================================"
echo "" echo ""
python3 setup.py build-deb python3 setup.py build-deb --sign
python3 setup.py build-ubuntu --sign --first