Skip to content

Commit

Permalink
Take another run at edit/build/testing in place
Browse files Browse the repository at this point in the history
  • Loading branch information
jonct committed Aug 8, 2024
1 parent 3cc95f3 commit acea434
Show file tree
Hide file tree
Showing 5 changed files with 114 additions and 23 deletions.
3 changes: 1 addition & 2 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -131,8 +131,7 @@ jobs:
# END

- name: Build
run: |
python3 -m zipapp src/jlmkr -p "/usr/bin/env python3" -o jlmkr
run: python3 build.py && ln dist/jlmkr .

# Run multiple commands using the runners shell
- name: Run the test script
Expand Down
46 changes: 46 additions & 0 deletions DEVELOPER.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
# Developer notes

## Building Jailmaker

No external dependencies are needed to perform a simple build from the project directory.

python3 build.py

Anything beyond this is *completely optional…*

## Development mode

Jailmaker's user-facing design and important safety features tend to get in the way of rapid development. To run directly from the editable source code, create an external configuration file.

mkdir -p ~/.local/share
cat <<EOF >~/.local/share/jailmaker.conf
[DEFAULT]
ignore_owner = 1
jailmaker_dir = /mnt/pool/jailmaker
EOF

If present, this file will override traditional self-detection of the Jailmaker directory.

## Code quality tooling

Additional tools for testing, coverage, and code quality review are available through [Hatch][1]. Install them in a self-contained, disposable virtual environment.

python3 -m venv --without-pip .venv
curl -OL https://bootstrap.pypa.io/pip/pip.pyz
.venv/bin/python3 pip.pyz install pip hatch
rm pip.pyz

Activate a session inside the virtual environment. (For more information see the `venv` [tutorial][2].)

source .venv/bin/activate

Use `hatch` to build, test, lint, etc.

hatch build

## Integration testing

See [`test/README.md`](./test/README.md).

[1]: https://hatch.pypa.io/
[2]: https://docs.python.org/3/tutorial/venv.html
12 changes: 6 additions & 6 deletions src/jlmkr/actions/create.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
from textwrap import dedent

from data import DISCLAIMER
from paths import COMMAND_NAME, JAILS_DIR_PATH, SCRIPT_DIR_PATH, SCRIPT_NAME
from paths import COMMAND_NAME, JAILS_DIR_PATH, JAILMAKER_DIR_PATH, SCRIPT_NAME
from utils.chroot import Chroot
from utils.config_parser import DEFAULT_CONFIG, KeyValueParser
from utils.console import BOLD, NORMAL, YELLOW, eprint
Expand All @@ -33,19 +33,19 @@
def create_jail(**kwargs):
print(DISCLAIMER)

if os.path.basename(SCRIPT_DIR_PATH) != "jailmaker":
if os.path.basename(JAILMAKER_DIR_PATH) != "jailmaker":
eprint(
dedent(
f"""
{COMMAND_NAME} needs to create files.
Currently it can not decide if it is safe to create files in:
{SCRIPT_DIR_PATH}
{JAILMAKER_DIR_PATH}
Please create a dedicated dataset called "jailmaker", store {SCRIPT_NAME} there and try again."""
)
)
return 1

if not PurePath(get_mount_point(SCRIPT_DIR_PATH)).is_relative_to("/mnt"):
if not PurePath(get_mount_point(JAILMAKER_DIR_PATH)).is_relative_to("/mnt"):
print(
dedent(
f"""
Expand All @@ -54,7 +54,7 @@ def create_jail(**kwargs):
{SCRIPT_NAME} should be on a dataset mounted under /mnt (it currently is not).
Storing it on the boot-pool means losing all jails when updating TrueNAS.
Jails will be stored under:
{SCRIPT_DIR_PATH}
{JAILMAKER_DIR_PATH}
"""
)
)
Expand Down Expand Up @@ -118,7 +118,7 @@ def create_jail(**kwargs):
try:
# Create the dir or dataset where to store the jails
if not os.path.exists(JAILS_DIR_PATH):
if get_zfs_dataset(SCRIPT_DIR_PATH):
if get_zfs_dataset(JAILMAKER_DIR_PATH):
# Creating "jails" dataset if "jailmaker" is a ZFS Dataset
create_zfs_dataset(JAILS_DIR_PATH)
else:
Expand Down
70 changes: 58 additions & 12 deletions src/jlmkr/paths.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,66 @@
#
# SPDX-License-Identifier: LGPL-3.0-only

import os.path
import os
import sys

# When running as a zipapp, the script file is a parent
ZIPAPP_PATH = os.path.realpath(__file__)
while not os.path.exists(ZIPAPP_PATH):
ZIPAPP_PATH = os.path.dirname(ZIPAPP_PATH)
from configparser import ConfigParser
from pathlib import Path
from utils.console import fail

SCRIPT_PATH = os.path.realpath(ZIPAPP_PATH)
SCRIPT_NAME = os.path.basename(SCRIPT_PATH)
SCRIPT_DIR_PATH = os.path.dirname(SCRIPT_PATH)
COMMAND_NAME = os.path.basename(ZIPAPP_PATH)

JAILS_DIR_PATH = os.path.join(SCRIPT_DIR_PATH, "jails")
JAIL_CONFIG_NAME = "config"
JAIL_ROOTFS_NAME = "rootfs"
def _get_selected_jailmaker_directory() -> Path:
'''
Determine the user's affirmative choice of parent jailmaker directory
'''
# first choice: global --dir/-D argument
#TODO

# next: JAILMAKER_DIR environment variable
envname = 'JAILMAKER_DIR'
if envname in os.environ:
return Path(os.environ[envname])

# next: ~/.local/share/jailmaker.conf
secname = 'DEFAULT'
cfgname = 'jailmaker_dir'
username = ''
if os.getuid() == 0 and 'SUDO_USER' in os.environ:
username = os.environ['SUDO_USER']
cfgpath = Path(f'~{username}/.local/share/jailmaker.conf').expanduser()
cfg = ConfigParser()
cfg.read(cfgpath)
if 'ignore_owner' in cfg[secname]:
os.environ['JLMKR_DEBUG'] = cfg[secname]['ignore_owner']
if cfgname in cfg[secname]:
return Path(cfg[secname][cfgname])

# next: current directory iff it's named jailmaker
script = Path(sys.argv[0]).resolve(True)
if script.parent.name == 'jailmaker':
return script.parent

fail("Please specify a jailmaker directory path (JAILMAKER_DIR)")


def get_tool_path_on_disk() -> Path:
'''
Determine the script's location on disk
'''
# When running as a zipapp, the script file is an ancestor
path = Path(__file__).resolve(strict=False)
while path and not path.is_file():
path = path.parent
return path


SCRIPT_PATH = get_tool_path_on_disk()
SCRIPT_NAME = SCRIPT_PATH.name
COMMAND_NAME = SCRIPT_NAME
SHORTNAME = "jlmkr"

JAILMAKER_DIR_PATH = _get_selected_jailmaker_directory()

JAILS_DIR_PATH = JAILMAKER_DIR_PATH.joinpath("jails")
JAIL_CONFIG_NAME = "config"
JAIL_ROOTFS_NAME = "rootfs"
6 changes: 3 additions & 3 deletions src/jlmkr/utils/dataset.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,13 @@
import subprocess
from pathlib import PurePath

from paths import SCRIPT_DIR_PATH
from paths import JAILMAKER_DIR_PATH

from utils.console import eprint, fail


def _get_relative_path_in_jailmaker_dir(absolute_path):
return PurePath(absolute_path).relative_to(SCRIPT_DIR_PATH)
return PurePath(absolute_path).relative_to(JAILMAKER_DIR_PATH)


def get_zfs_dataset(path):
Expand All @@ -37,7 +37,7 @@ def get_zfs_base_path():
"""
Get ZFS dataset path for jailmaker directory.
"""
zfs_base_path = get_zfs_dataset(SCRIPT_DIR_PATH)
zfs_base_path = get_zfs_dataset(JAILMAKER_DIR_PATH)
if not zfs_base_path:
fail("Failed to get dataset path for jailmaker directory.")

Expand Down

0 comments on commit acea434

Please sign in to comment.