Release v0.2.4
This commit is contained in:
@@ -2,15 +2,18 @@
|
||||
|
||||
set -u
|
||||
|
||||
SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)"
|
||||
|
||||
ROOT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||
CONFIG_DIR="${FFX_CONFIG_DIR:-${HOME}/.local/etc}"
|
||||
CONFIG_FILE="${FFX_CONFIG_FILE:-${CONFIG_DIR}/ffx.json}"
|
||||
VAR_DIR="${FFX_VAR_DIR:-${HOME}/.local/var/ffx}"
|
||||
LOG_DIR="${FFX_LOG_DIR:-${HOME}/.local/var/log}"
|
||||
DATABASE_FILE="${FFX_DATABASE_FILE:-${VAR_DIR}/ffx.db}"
|
||||
SUBTITLES_BASE_DIR="${FFX_SUBTITLES_BASE_DIR:-${HOME}/.local/var/sync/subtitles}"
|
||||
FFX_PYTHON="${FFX_PYTHON:-${HOME}/.local/share/ffx.venv/bin/python}"
|
||||
CONFIG_TEMPLATE_FILE="${FFX_CONFIG_TEMPLATE:-${ROOT_DIR}/assets/ffx.json.j2}"
|
||||
|
||||
CHECK_ONLY=0
|
||||
WITH_TESTS=0
|
||||
|
||||
MUTATIONS=0
|
||||
INSTALL_FAILURES=0
|
||||
@@ -33,12 +36,13 @@ fi
|
||||
|
||||
usage() {
|
||||
cat <<EOF
|
||||
Usage: $(basename "$0") [--check] [--help]
|
||||
Usage: $(basename "$0") [--check] [--with-tests] [--help]
|
||||
|
||||
Prepare the local FFX development environment for this repository.
|
||||
Prepare the local workstation environment for an already installed FFX bundle.
|
||||
|
||||
Options:
|
||||
--check Report readiness only. Do not create, install, or modify.
|
||||
--with-tests Include test-related notes while preparing system dependencies and local config.
|
||||
--help Show this help text.
|
||||
|
||||
Environment overrides:
|
||||
@@ -47,6 +51,15 @@ Environment overrides:
|
||||
FFX_VAR_DIR Override the default data directory.
|
||||
FFX_LOG_DIR Override the default log directory.
|
||||
FFX_DATABASE_FILE Override the database path written into a newly seeded config.
|
||||
FFX_SUBTITLES_BASE_DIR Override the default subtitles base directory written into a newly seeded config.
|
||||
FFX_PYTHON Override the bundle venv Python used to render the seeded config.
|
||||
FFX_CONFIG_TEMPLATE Override the Jinja2 template path used to seed the config.
|
||||
|
||||
Notes:
|
||||
- tools/setup.sh is the first installation step and owns bundle venv setup.
|
||||
- This script is the second step and owns system dependencies plus local config.
|
||||
- After the bundle is installed, the aligned CLI wrapper is: ffx configure_workstation
|
||||
- Python test packages are installed by tools/setup.sh --with-tests, not here.
|
||||
EOF
|
||||
}
|
||||
|
||||
@@ -136,6 +149,13 @@ component_detail() {
|
||||
printf 'missing; prep can create it'
|
||||
fi
|
||||
;;
|
||||
subtitles-base-dir)
|
||||
if check_seeded_dir "${SUBTITLES_BASE_DIR}"; then
|
||||
printf '%s' "${SUBTITLES_BASE_DIR}"
|
||||
else
|
||||
printf 'missing; prep can create it'
|
||||
fi
|
||||
;;
|
||||
ffx-config)
|
||||
if check_seeded_file "${CONFIG_FILE}"; then
|
||||
printf '%s' "${CONFIG_FILE}"
|
||||
@@ -189,6 +209,9 @@ report_seeded_component() {
|
||||
log-dir)
|
||||
check_seeded_dir "${LOG_DIR}" || ok=0
|
||||
;;
|
||||
subtitles-base-dir)
|
||||
check_seeded_dir "${SUBTITLES_BASE_DIR}" || ok=0
|
||||
;;
|
||||
ffx-config)
|
||||
check_seeded_file "${CONFIG_FILE}" || ok=0
|
||||
;;
|
||||
@@ -225,9 +248,20 @@ print_seeded_file_status() {
|
||||
report_seeded_component "Config dir" "config-dir" "optional"
|
||||
report_seeded_component "Var dir" "var-dir" "optional"
|
||||
report_seeded_component "Log dir" "log-dir" "optional"
|
||||
report_seeded_component "Subtitles base dir" "subtitles-base-dir" "optional"
|
||||
report_seeded_component "ffx config" "ffx-config" "optional"
|
||||
}
|
||||
|
||||
print_test_package_status() {
|
||||
if [ "${WITH_TESTS}" -eq 0 ]; then
|
||||
return 0
|
||||
fi
|
||||
|
||||
echo "Test environment notes:"
|
||||
report_component ok "system test dependencies" "no extra system packages beyond the standard runtime toolchain"
|
||||
report_component ok "Python test packages" "install via tools/setup.sh --with-tests"
|
||||
}
|
||||
|
||||
detect_package_manager() {
|
||||
if command_exists apt-get; then
|
||||
printf 'apt-get\n'
|
||||
@@ -287,6 +321,93 @@ install_system_requirements() {
|
||||
return 0
|
||||
}
|
||||
|
||||
render_default_config() {
|
||||
local output_path="$1"
|
||||
local temporary_output_path=""
|
||||
|
||||
if [ ! -x "${FFX_PYTHON}" ]; then
|
||||
printf 'Missing bundle Python interpreter at %s.\n' "${FFX_PYTHON}" >&2
|
||||
INSTALL_FAILURES=$((INSTALL_FAILURES + 1))
|
||||
return 1
|
||||
fi
|
||||
|
||||
if [ ! -f "${CONFIG_TEMPLATE_FILE}" ]; then
|
||||
printf 'Missing FFX config template at %s.\n' "${CONFIG_TEMPLATE_FILE}" >&2
|
||||
INSTALL_FAILURES=$((INSTALL_FAILURES + 1))
|
||||
return 1
|
||||
fi
|
||||
|
||||
if ! temporary_output_path="$(mktemp "${output_path}.tmp.XXXXXX")"; then
|
||||
printf 'Failed to create a temporary config file next to %s.\n' "${output_path}" >&2
|
||||
INSTALL_FAILURES=$((INSTALL_FAILURES + 1))
|
||||
return 1
|
||||
fi
|
||||
|
||||
if ! FFX_CONFIG_TEMPLATE_FILE="${CONFIG_TEMPLATE_FILE}" \
|
||||
FFX_REPO_ROOT="${ROOT_DIR}" \
|
||||
FFX_DATABASE_PATH="${DATABASE_FILE}" \
|
||||
FFX_LOG_DIRECTORY="${LOG_DIR}" \
|
||||
FFX_SUBTITLES_DIRECTORY="${SUBTITLES_BASE_DIR}" \
|
||||
"${FFX_PYTHON}" - >"${temporary_output_path}" <<'PY'
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
import os
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
from jinja2 import Environment, FileSystemLoader, StrictUndefined
|
||||
|
||||
repo_root = Path(os.environ["FFX_REPO_ROOT"])
|
||||
src_root = repo_root / "src"
|
||||
if str(src_root) not in sys.path:
|
||||
sys.path.insert(0, str(src_root))
|
||||
|
||||
from ffx.constants import (
|
||||
DEFAULT_SHOW_INDEX_EPISODE_DIGITS,
|
||||
DEFAULT_SHOW_INDEX_SEASON_DIGITS,
|
||||
DEFAULT_SHOW_INDICATOR_EPISODE_DIGITS,
|
||||
DEFAULT_SHOW_INDICATOR_SEASON_DIGITS,
|
||||
)
|
||||
|
||||
template_path = Path(os.environ["FFX_CONFIG_TEMPLATE_FILE"])
|
||||
environment = Environment(
|
||||
loader=FileSystemLoader(str(template_path.parent)),
|
||||
undefined=StrictUndefined,
|
||||
autoescape=False,
|
||||
keep_trailing_newline=True,
|
||||
)
|
||||
template = environment.get_template(template_path.name)
|
||||
|
||||
sys.stdout.write(
|
||||
template.render(
|
||||
database_path_json=json.dumps(os.environ["FFX_DATABASE_PATH"]),
|
||||
log_directory_json=json.dumps(os.environ["FFX_LOG_DIRECTORY"]),
|
||||
subtitles_directory_json=json.dumps(os.environ["FFX_SUBTITLES_DIRECTORY"]),
|
||||
default_index_season_digits=DEFAULT_SHOW_INDEX_SEASON_DIGITS,
|
||||
default_index_episode_digits=DEFAULT_SHOW_INDEX_EPISODE_DIGITS,
|
||||
default_indicator_season_digits=DEFAULT_SHOW_INDICATOR_SEASON_DIGITS,
|
||||
default_indicator_episode_digits=DEFAULT_SHOW_INDICATOR_EPISODE_DIGITS,
|
||||
)
|
||||
)
|
||||
PY
|
||||
then
|
||||
rm -f "${temporary_output_path}"
|
||||
printf 'Failed to render ffx config from template %s.\n' "${CONFIG_TEMPLATE_FILE}" >&2
|
||||
INSTALL_FAILURES=$((INSTALL_FAILURES + 1))
|
||||
return 1
|
||||
fi
|
||||
|
||||
if ! mv "${temporary_output_path}" "${output_path}"; then
|
||||
rm -f "${temporary_output_path}"
|
||||
printf 'Failed to move rendered ffx config into place at %s.\n' "${output_path}" >&2
|
||||
INSTALL_FAILURES=$((INSTALL_FAILURES + 1))
|
||||
return 1
|
||||
fi
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
seed_default_config() {
|
||||
if [ "${CHECK_ONLY}" -eq 1 ]; then
|
||||
return 0
|
||||
@@ -324,44 +445,19 @@ seed_default_config() {
|
||||
created_any=1
|
||||
fi
|
||||
|
||||
if [ ! -d "${SUBTITLES_BASE_DIR}" ]; then
|
||||
printf 'Creating subtitles base dir at %s...\n' "${SUBTITLES_BASE_DIR}"
|
||||
if ! mkdir -p "${SUBTITLES_BASE_DIR}"; then
|
||||
printf 'Failed to create subtitles base dir at %s.\n' "${SUBTITLES_BASE_DIR}" >&2
|
||||
INSTALL_FAILURES=$((INSTALL_FAILURES + 1))
|
||||
return 1
|
||||
fi
|
||||
created_any=1
|
||||
fi
|
||||
|
||||
if [ ! -f "${CONFIG_FILE}" ]; then
|
||||
printf 'Seeding ffx config at %s...\n' "${CONFIG_FILE}"
|
||||
if ! cat >"${CONFIG_FILE}" <<EOF
|
||||
{
|
||||
"databasePath": "${DATABASE_FILE}",
|
||||
"logDirectory": "${LOG_DIR}",
|
||||
"metadata": {
|
||||
"signature": {
|
||||
"RECODED_WITH": "FFX"
|
||||
},
|
||||
"remove": [
|
||||
"VERSION-eng",
|
||||
"creation_time",
|
||||
"NAME"
|
||||
],
|
||||
"streams": {
|
||||
"remove": [
|
||||
"BPS",
|
||||
"NUMBER_OF_FRAMES",
|
||||
"NUMBER_OF_BYTES",
|
||||
"_STATISTICS_WRITING_APP",
|
||||
"_STATISTICS_WRITING_DATE_UTC",
|
||||
"_STATISTICS_TAGS",
|
||||
"BPS-eng",
|
||||
"DURATION-eng",
|
||||
"NUMBER_OF_FRAMES-eng",
|
||||
"NUMBER_OF_BYTES-eng",
|
||||
"_STATISTICS_WRITING_APP-eng",
|
||||
"_STATISTICS_WRITING_DATE_UTC-eng",
|
||||
"_STATISTICS_TAGS-eng"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
EOF
|
||||
then
|
||||
printf 'Failed to write ffx config at %s.\n' "${CONFIG_FILE}" >&2
|
||||
INSTALL_FAILURES=$((INSTALL_FAILURES + 1))
|
||||
if ! render_default_config "${CONFIG_FILE}"; then
|
||||
return 1
|
||||
fi
|
||||
created_any=1
|
||||
@@ -380,6 +476,9 @@ parse_args() {
|
||||
--check)
|
||||
CHECK_ONLY=1
|
||||
;;
|
||||
--with-tests)
|
||||
WITH_TESTS=1
|
||||
;;
|
||||
--help|-h)
|
||||
usage
|
||||
exit 0
|
||||
@@ -409,10 +508,17 @@ main() {
|
||||
echo
|
||||
print_seeded_file_status
|
||||
|
||||
echo
|
||||
print_test_package_status
|
||||
|
||||
if [ "${CHECK_ONLY}" -eq 0 ]; then
|
||||
seed_default_config
|
||||
echo
|
||||
print_dependency_status
|
||||
echo
|
||||
print_seeded_file_status
|
||||
echo
|
||||
print_test_package_status
|
||||
fi
|
||||
|
||||
echo
|
||||
@@ -14,6 +14,7 @@ ALIAS_BLOCK_END="# <<< ffx alias <<<"
|
||||
ALIAS_LINE="alias ffx=\"${VENV_FFX}\""
|
||||
|
||||
CHECK_ONLY=0
|
||||
WITH_TESTS=0
|
||||
READINESS_FAILURES=0
|
||||
INSTALL_FAILURES=0
|
||||
|
||||
@@ -31,19 +32,26 @@ fi
|
||||
|
||||
usage() {
|
||||
cat <<EOF
|
||||
Usage: $(basename "$0") [--check] [--help]
|
||||
Usage: $(basename "$0") [--check] [--with-tests] [--help]
|
||||
|
||||
Prepare the persistent FFX bundle virtualenv at:
|
||||
Prepare the persistent FFX bundle installation at:
|
||||
${VENV_DIR}
|
||||
|
||||
Actions:
|
||||
- create or reuse ${VENV_DIR}
|
||||
- install this repository into the venv with pip --editable
|
||||
- ensure ${BASHRC_FILE} exposes alias ffx -> ${VENV_FFX}
|
||||
- optionally install Python packages required for modern tests
|
||||
|
||||
Options:
|
||||
--check Report readiness only. Do not create or modify anything.
|
||||
--help Show this help text.
|
||||
--check Report readiness only. Do not create or modify anything.
|
||||
--with-tests Also install and verify Python packages required for modern tests.
|
||||
--help Show this help text.
|
||||
|
||||
Notes:
|
||||
- This is the first installation step.
|
||||
- After the bundle is installed, the aligned CLI wrapper is: ffx setup
|
||||
- tools/configure_workstation.sh is the second step and configures system dependencies plus local user files.
|
||||
EOF
|
||||
}
|
||||
|
||||
@@ -100,6 +108,10 @@ check_venv_ffx() {
|
||||
[ -x "${VENV_FFX}" ]
|
||||
}
|
||||
|
||||
check_venv_pytest() {
|
||||
check_venv_dir && "${VENV_PYTHON}" -m pytest --version >/dev/null 2>&1
|
||||
}
|
||||
|
||||
check_bashrc_file() {
|
||||
[ -f "${BASHRC_FILE}" ]
|
||||
}
|
||||
@@ -136,6 +148,14 @@ detail_venv_ffx() {
|
||||
fi
|
||||
}
|
||||
|
||||
detail_venv_pytest() {
|
||||
if check_venv_pytest; then
|
||||
"${VENV_PYTHON}" -m pytest --version 2>/dev/null | head -n 1
|
||||
else
|
||||
printf 'missing pytest in %s' "${VENV_DIR}"
|
||||
fi
|
||||
}
|
||||
|
||||
detail_bashrc_file() {
|
||||
if check_bashrc_file; then
|
||||
printf '%s' "${BASHRC_FILE}"
|
||||
@@ -186,6 +206,17 @@ print_status_report() {
|
||||
READINESS_FAILURES=$((READINESS_FAILURES + 1))
|
||||
fi
|
||||
|
||||
if [ "${WITH_TESTS}" -eq 1 ]; then
|
||||
echo
|
||||
echo "Bundle test package status:"
|
||||
if check_venv_pytest; then
|
||||
report_component ok "bundle pytest" "$(detail_venv_pytest)"
|
||||
else
|
||||
report_component failed "bundle pytest" "$(detail_venv_pytest)"
|
||||
READINESS_FAILURES=$((READINESS_FAILURES + 1))
|
||||
fi
|
||||
fi
|
||||
|
||||
echo
|
||||
echo "Shell exposure status:"
|
||||
if check_bashrc_file; then
|
||||
@@ -220,11 +251,23 @@ ensure_bundle_venv() {
|
||||
return 1
|
||||
fi
|
||||
|
||||
printf 'Installing FFX package into %s...\n' "${VENV_DIR}"
|
||||
if ! "${VENV_PIP}" install --editable "${ROOT_DIR}"; then
|
||||
printf 'Failed to install FFX package into %s.\n' "${VENV_DIR}" >&2
|
||||
INSTALL_FAILURES=$((INSTALL_FAILURES + 1))
|
||||
return 1
|
||||
if [ "${WITH_TESTS}" -eq 1 ]; then
|
||||
printf 'Installing FFX package and test extras into %s...\n' "${VENV_DIR}"
|
||||
if ! (
|
||||
cd "${ROOT_DIR}" &&
|
||||
"${VENV_PIP}" install --editable '.[test]'
|
||||
); then
|
||||
printf 'Failed to install FFX package and test extras into %s.\n' "${VENV_DIR}" >&2
|
||||
INSTALL_FAILURES=$((INSTALL_FAILURES + 1))
|
||||
return 1
|
||||
fi
|
||||
else
|
||||
printf 'Installing FFX package into %s...\n' "${VENV_DIR}"
|
||||
if ! "${VENV_PIP}" install --editable "${ROOT_DIR}"; then
|
||||
printf 'Failed to install FFX package into %s.\n' "${VENV_DIR}" >&2
|
||||
INSTALL_FAILURES=$((INSTALL_FAILURES + 1))
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
|
||||
return 0
|
||||
@@ -300,6 +343,9 @@ parse_args() {
|
||||
--check)
|
||||
CHECK_ONLY=1
|
||||
;;
|
||||
--with-tests)
|
||||
WITH_TESTS=1
|
||||
;;
|
||||
--help|-h)
|
||||
usage
|
||||
exit 0
|
||||
|
||||
22
tools/test.sh
Executable file
22
tools/test.sh
Executable file
@@ -0,0 +1,22 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
REPO_ROOT="$(cd "${SCRIPT_DIR}/.." && pwd)"
|
||||
|
||||
PYTHON_BIN="${FFX_PYTHON:-${HOME}/.local/share/ffx.venv/bin/python}"
|
||||
|
||||
if [[ ! -x "${PYTHON_BIN}" ]]; then
|
||||
echo "Missing Python interpreter: ${PYTHON_BIN}" >&2
|
||||
echo "Set FFX_PYTHON to a suitable interpreter if needed." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
cd "${REPO_ROOT}"
|
||||
|
||||
exec "${PYTHON_BIN}" -m pytest \
|
||||
--ignore=tests/legacy \
|
||||
--ignore=tests/support \
|
||||
tests \
|
||||
"$@"
|
||||
Reference in New Issue
Block a user