Skip to content

Commit

Permalink
Windows Installer and switch default DB location (#110)
Browse files Browse the repository at this point in the history
- Finished lowercasing `nexus`
- SECURITY.md added
- README revamp
- Version bump to v0.5.1
  • Loading branch information
Raymo111 authored Dec 25, 2023
1 parent ffd02ef commit 3e6d11f
Show file tree
Hide file tree
Showing 12 changed files with 260 additions and 52 deletions.
11 changes: 11 additions & 0 deletions .github/workflows/CI.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,15 @@ jobs:
python-version: ${{ matrix.python-version }}
- name: Package for ${{ matrix.os }}
run: python dist.py -d
- name: Add msbuild to PATH
uses: microsoft/[email protected]
if: runner.os == 'Windows'
- name: Install WiX
run: dotnet tool install --global wix
if: runner.os == 'Windows'
- name: Build WiX on Windows
run: wix build .\nexus.wxs
if: runner.os == 'Windows'
- name: Add generated binary to artifact
uses: actions/upload-artifact@v3
with:
Expand All @@ -37,6 +46,7 @@ jobs:
./dist/nexus-macos
./dist/nexus.exe
./dist/nexusw.exe
./nexus.msi
if-no-files-found: error
if: always()

Expand Down Expand Up @@ -104,6 +114,7 @@ jobs:
nexus
nexus.exe
nexusw.exe
nexus.msi
nexus-macos
README.md
LICENSE
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,5 @@ nexus.egg-info/
/nexus/ui/*.py
/nexus/translations/
/resources_rc.py
nexus.wixpdb
nexus.msi
105 changes: 84 additions & 21 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,49 +4,105 @@

CharaChorder's all-in-one desktop app, supporting Linux, Windows, and macOS.

## Build
## User Installation

1. Get Python >=3.11 (using [pyenv](https://github.com/pyenv/pyenv) recommended on Linux/macOS, Microsoft store has 3.11 for Windows)
1. Download the appropriate executable for your OS:

| OS | Executable |
|-----------------------------------------------------------------------------------|-------------------------------------------------------------------------------------------|
| Windows (Installer) | [nexus.msi](https://github.com/CharaChorder/nexus/releases/latest/download/nexus.msi) |
| Windows (Portable GUI-only) | [nexusw.exe](https://github.com/CharaChorder/nexus/releases/latest/download/nexusw.exe) |
| Windows (Portable with CLI) | [nexus.exe](https://github.com/CharaChorder/nexus/releases/latest/download/nexus.exe) |
| Linux | [nexus](https://github.com/CharaChorder/nexus/releases/latest/download/nexus) |
| macOS (Currently CLI-only ([#7](https://github.com/CharaChorder/nexus/issues/7))) | [nexus-macos](https://github.com/CharaChorder/nexus/releases/latest/download/nexus-macos) |

2. For the MSI, run the installer. If Windows Defender/Smart Screen asks, choose `More info`, then `Run Anyway`. The MSI
will install `nexusw.exe` to `%LOCALAPPDATA%\Programs\nexus\nexus.exe`, and add Desktop and
Start Menu shortcuts. (If you don't like this, sorry, why not contribute a PR to
implement [#114](https://github.com/CharaChorder/nexus/issues/114)?). You can now launch nexus from the Start Menu
like any other program.

For the portable versions, save the executable to a folder of your choice. On MacOS and Linux, you may need to
run `chmod +x nexus{,-macos}` from the directory you saved it to to make it executable.

## Usage

### GUI

1. Launch the program. This may take a while depending on your platform, as the executable must first self-extract.
2. Click `Start Logging` to start logging everything you type, `Refresh` to update the table, and `Stop Logging` to stop
logging. Starting and stopping may take a while depending on your platform.
3. nexus comes with a tray icon, which you can click on to hide and reopen the window.

### CLI

```
./nexus # Unix
.\nexus.exe # Windows
```

Use the `-h` flag to access CLI options.

## Data location

Your data will be stored platform-dependently in:
- `%APPDATA%\CharaChorder\nexus\` on Windows
- `~/Library/CharaChorder/nexus/` on MacOS
- `$XDG_CONFIG_HOME/nexus/` on *nix

## Development

### Setup

1. Get Python >=3.11 (using [pyenv](https://github.com/pyenv/pyenv) recommended)
2. Clone and build
```sh
git clone https://github.com/CharaChorder/nexus
cd nexus/
python dist.py -nd
```

With the `-n` and `-d` flags, `dist.py` automatically detects your OS, sets up a virtualenv in the root directory of the repo (if not provided one via args), installs requirements, converts UI files to Python, sets up git hooks, and installs the nexus module locally.
With the `-n` and `-d` flags, `dist.py` automatically detects your OS, sets up a virtualenv in the root directory of the
repo (if not provided one via args), installs requirements, converts UI files to Python, sets up git hooks, and installs
the nexus module locally.

To develop, you can now run it from within the virtualenv (activate it first) using the `python -m nexus <args>` command.
To develop, you can now run it from within the virtualenv (activate it first) using the `python -m nexus <args>`
command.

## Installation
### Package

```sh
python dist.py
```

Running `dist.py` without any args detects your OS, sets up a virtualenv, installs reqs, converts UI files, and generates a platform-dependent executable in the `dist/` directory.
Running `dist.py` without any args detects your OS, sets up a virtualenv, installs reqs, converts UI files, and
generates a platform-dependent executable in the `dist/` directory.

## Usage
## Platform-specific quirks

```
cd dist/ # if following the steps above
./nexus # Unix
.\nexus.exe # Windows
```
Use the `-h` flag to access CLI options
### Windows

## Platform-specific quirks
- You may have to allowlist downloaded executables in Windows Defender.
- Running the source code with Microsoft-store-installed Python will cause a shadow copy of `%APPDATA%` (where the DB
defaults to) to be used. The full exe from Python should be installed instead.
Read [this](https://docs.python.org/3/using/windows.html#redirection-of-local-data-registry-and-temporary-paths) for
more details.

### Wayland

- You need to have XWayland enabled, and allow X11 apps to read keystrokes in all apps (on KDE this is in `Settings > Applications > Legacy X11 App Support`).
- Move the `com.charachorder.nexus.desktop` file into either your `~/.local/share/applications/` or `/usr/share/applications/` directory, and edit the path to point to the nexus icon.
- You need to have XWayland enabled, and allow X11 apps to read keystrokes in all apps (on KDE this is
in `Settings > Applications > Legacy X11 App Support`).
- Move the `com.charachorder.nexus.desktop` file into either your `~/.local/share/applications/`
or `/usr/share/applications/` directory, and edit the path to point to the nexus icon.

## Contributing

Please create PRs and issues, we welcome all contributions. See issues tagged with `Help Wanted` for where you can best help.
Please create PRs and issues, we welcome all contributions. See issues tagged with `Help Wanted` for where you can best
help.

By creating issues, PRs, or any other contributions to this repo, you hereby agree to
our [Contribution License Agreement](Contributing.md). In short,

By creating issues, PRs, or any other contributions to this repo, you hereby agree to our [Contribution License Agreement](Contributing.md). In short,
- The entirety of all of your contributions are your own work,
- Your employer is okay with your contributions if you make them at work,
- You grant (and are legally allowed to grant) CharaChorder all rights to your contributions,
Expand All @@ -56,14 +112,21 @@ This summary is for information purposes only, and you are agreeing to the full

## Privacy policy/Data collection

No data is collected from you when you use nexus. Unless you somehow send us data manually (e.g. by creating an issue on GitHub), anything that you type that may be logged by nexus stays on your computer. You can verify this for yourself by reading the source code. We will update this section if this changes.
No data is collected from you when you use nexus. Unless you somehow send us data manually (e.g. by creating an issue on
GitHub), anything that you type that may be logged by nexus stays on your computer. You can verify this for yourself by
reading the source code. We will update this section if this changes.

## Security

### Using nexus

Parts of nexus (Freqlog) **log keystrokes**. This is necessary for that module to analyze the words you use the most. You should ban any sensitive information (passwords, credit card numbers, etc.) or stop logging before typing them. CharaChorder will not be held responsible for any data loss or theft, or any security breaches. You use nexus at your own risk.
Parts of nexus (Freqlog) **log keystrokes**. This is necessary for that module to analyze the words you use the most.
You should ban any sensitive information (passwords, credit card numbers, etc.) or stop logging before typing them.
CharaChorder will not be held responsible for any data loss or theft, or any security breaches. You use nexus at your
own risk.

### Reporting security issues/vulnerabilities

If you find a security issue, please reach out to a CC Rep on Discord or through our support email (support at charachorder dot com). We will work with you to resolve the issue. Please do not create a GitHub issue for security issues.
If you find a security issue, please reach out to a CC Rep on Discord or through our support email (support at
charachorder dot com). We will work with you to resolve the issue. Please do not create a GitHub issue for security
issues.
15 changes: 15 additions & 0 deletions SECURITY.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# Security Policy

## Supported Versions

Use this section to tell people about which versions of your project are
currently being supported with security updates.

| Version | Supported |
|----------|--------------------|
| Latest | :white_check_mark: |
| < Latest | :x: |

## Reporting a Vulnerability

See [README.md#Security](./README.md#reporting-security-issuesvulnerabilities).
43 changes: 43 additions & 0 deletions nexus.wxs
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
<?xml version="1.0" encoding="UTF-8"?>
<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs">
<Package Language="1033"
Manufacturer="CharaChorder"
Name="nexus"
Scope="perUserOrMachine"
UpgradeCode="C4A2AC40-2DE2-5241-594D-4F4E45585553"
Version="0.5.1">
<MajorUpgrade DowngradeErrorMessage="A later version of [ProductName] is already installed. Setup will now exit." />
<MediaTemplate EmbedCab="yes" />
<Icon Id="icon.ico" SourceFile="ui\images\icon.ico"/>
<Property Id="ARPPRODUCTICON" Value="icon.ico" />
<StandardDirectory Id="TARGETDIR">
<Directory Id="ProgramFilesFolder">
<Directory Id="INSTALLFOLDER" Name="nexus">
<Component Id="ProductComponent">
<File KeyPath="yes" Source="dist\nexusw.exe" Name="nexus.exe"></File>
<Shortcut Id="startmenuShortcut"
Directory="ProgramMenuDir"
Name="nexus"
WorkingDirectory='INSTALLFOLDER'
Icon="icon.ico"
IconIndex="0"
Advertise="yes" />
<Shortcut Id="desktopShortcut"
Directory="DesktopFolder"
Name="nexus"
WorkingDirectory='INSTALLFOLDER'
Icon="icon.ico"
IconIndex="0"
Advertise="yes" />
</Component>
</Directory>
</Directory>
</StandardDirectory>
<Directory Id="ProgramMenuFolder" Name="Programs">
<Directory Id="ProgramMenuDir" Name="nexus"/>
</Directory>
<StandardDirectory Id="DesktopFolder"/>
<Feature Id="nexus">
<ComponentRef Id="ProductComponent" />
</Feature></Package>
</Wix>
24 changes: 23 additions & 1 deletion nexus/Freqlog/Definitions.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
import os
import sys
from datetime import datetime, timedelta
from enum import Enum
from typing import Any, Self

from pynput.keyboard import Key

from nexus import __author__


class Defaults:
# Allowed keys in chord output: a-z, A-Z, 0-9, apostrophe, dash, underscore, slash, backslash, tilde
Expand All @@ -14,10 +18,28 @@ class Defaults:
Key.cmd_l, Key.cmd_r}
DEFAULT_NEW_WORD_THRESHOLD: float = 5 # seconds after which character input is considered a new word
DEFAULT_CHORD_CHAR_THRESHOLD: int = 5 # milliseconds between characters in a chord to be considered a chord
DEFAULT_DB_PATH: str = "nexus_freqlog_db.sqlite3"
DEFAULT_DB_FILE: str = "nexus_freqlog_db.sqlite3"
DEFAULT_NUM_WORDS_CLI: int = 10
DEFAULT_NUM_WORDS_GUI: int = 100

# Set per platform
DEFAULT_DB_PATH: str
if sys.platform.startswith("win"):
DEFAULT_DB_PATH = os.path.join(os.getenv("APPDATA"), "CharaChorder", "nexus", DEFAULT_DB_FILE)
elif sys.platform.startswith("darwin"):
DEFAULT_DB_PATH = os.path.join(os.getenv("HOME"), "Library", "Application Support", __author__, "nexus",
DEFAULT_DB_FILE)
elif sys.platform.startswith("linux") or sys.platform.startswith("freebsd") or sys.platform.startswith("openbsd"):
xdg_data_home = os.getenv("XDG_DATA_HOME")
if xdg_data_home is None:
xdg_data_home = os.path.join(os.getenv("HOME"), ".local", "share")
DEFAULT_DB_PATH = os.path.join(xdg_data_home, "nexus", DEFAULT_DB_FILE)
else: # Fallback (unknown platform)
DEFAULT_DB_PATH = DEFAULT_DB_FILE

# Create directory if it doesn't exist
os.makedirs(os.path.dirname(DEFAULT_DB_PATH), exist_ok=True)


class ActionType(Enum):
"""Enum for key action type"""
Expand Down
33 changes: 25 additions & 8 deletions nexus/GUI.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ def translate(self, context: str, source: str, disambiguation=None, n=-1):


class GUI(object):
"""Nexus GUI"""
"""nexus GUI"""

def __init__(self, args: argparse.Namespace):
"""Initialize GUI"""
Expand Down Expand Up @@ -102,7 +102,7 @@ def __init__(self, args: argparse.Namespace):

# Menu bar
self.window.actionQuit.triggered.connect(self.graceful_quit)
self.window.actionNexus_Dark.triggered.connect(lambda: self.set_style('Nexus_Dark'))
self.window.actionNexus_Dark.triggered.connect(lambda: self.set_style('nexus_Dark'))
self.window.actionQt_Default.triggered.connect(lambda: self.set_style('Fusion'))
self.window.actionPlatform_Default.triggered.connect(lambda: self.set_style('Default'))
self.window.actionBanlist.triggered.connect(self.show_banlist)
Expand Down Expand Up @@ -204,7 +204,7 @@ def __init__(self, args: argparse.Namespace):

# Styles
self.default_style: str = self.app.style().name()
self.set_style('Nexus_Dark')
self.set_style('nexus_Dark')

self.freqlog: Freqlog | None = None # for logging
self.temp_freqlog: Freqlog | None = None # for other operations
Expand All @@ -220,13 +220,13 @@ def show_hide(self, reason):
else:
self.window.hide()

def set_style(self, style: Literal['Nexus_Dark', 'Fusion', 'Default']):
def set_style(self, style: Literal['nexus_Dark', 'Fusion', 'Default']):
self.app.setStyleSheet('')
if style == 'Default':
self.app.setStyle(self.default_style)
else:
self.app.setStyle('Fusion')
if style == 'Nexus_Dark':
if style == 'nexus_Dark':
self.app.setStyleSheet(Stylesheet.dark)
self.window.update()

Expand Down Expand Up @@ -648,16 +648,33 @@ def exec(self):
QMessageBox.warning(
self.window, self.tr("GUI", "Update check failed"),
self.tr("GUI",
"Update check failed, there may be a new version of Nexus available. The latest version "
"Update check failed, there may be a new version of nexus available. The latest version "
"can be found at https://github.com/CharaChorder/nexus/releases/latest"))
else:
if QMessageBox.information(
self.window, self.tr("GUI", "Update available"),
self.tr("GUI", "Version {} of Nexus is available!\n(You are running v{})").format(
self.tr("GUI", "Version {} of nexus is available!\n(You are running v{})").format(
latest_version, __version__),
buttons=StandardButton.Ok | StandardButton.Open) == StandardButton.Open:
webbrowser.open("https://github.com/CharaChorder/nexus/releases/latest")
return # Don't start Nexus if the user opens the release page
return # Don't start nexus if the user opens the release page

# GUI upgrade
# DB path not manually specified and DB exists in current directory and no file is at default path
if (self.args.freqlog_db_path == Defaults.DEFAULT_DB_PATH
and Freqlog.is_backend_initialized(Defaults.DEFAULT_DB_FILE)
and not os.path.isfile(Defaults.DEFAULT_DB_PATH)):
if QMessageBox.question(
self.window, self.tr("GUI", "Database Move"),
self.tr("GUI", "Freqlog now defaults to '{}' for your database. "
"Move your database from the current directory ({})?").format(
Defaults.DEFAULT_DB_PATH, os.getcwd()),
StandardButton.Yes | StandardButton.No, defaultButton=StandardButton.No) == StandardButton.Yes:
try:
os.rename(Defaults.DEFAULT_DB_FILE, Defaults.DEFAULT_DB_PATH)
except OSError as e:
logging.error(e)
raise

# Initialize backend
while True:
Expand Down
2 changes: 1 addition & 1 deletion nexus/Version.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ def __lt__(self, other: Self | str | int):
@classmethod
def fetch_latest_nexus_version(cls) -> tuple[bool, Self | None]:
"""
Fetch the latest release of Nexus from GitHub
Fetch the latest release of nexus from GitHub
:returns: Tuple of an "outdated" boolean and the fetched version or None if the request failed
"""
try:
Expand Down
3 changes: 2 additions & 1 deletion nexus/__init__.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
"""All-in-one cross-platform CharaChorder desktop app."""

__author__ = "CharaChorder"
__name__ = "nexus"
__id__ = "com.charachorder.nexus"
__version__ = "0.5.0"
__version__ = "0.5.1"
Loading

0 comments on commit 3e6d11f

Please sign in to comment.