Merge remote-tracking branch 'origin/main' into feat/ariadne-cli-skeleton
# Conflicts: # src/ariadne/README.md
This commit is contained in:
@@ -16,8 +16,3 @@ rust_binary(
|
||||
],
|
||||
)
|
||||
|
||||
sh_binary(
|
||||
name = "extract_and_decompile",
|
||||
srcs = ["extract-and-decompile.sh"],
|
||||
data = ["extract-tools.nix"],
|
||||
)
|
||||
|
||||
@@ -1,257 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
usage() {
|
||||
cat <<'USAGE'
|
||||
Usage: extract-and-decompile --game-root <path> [--output-root <path>] [--force]
|
||||
|
||||
Prepare local game-owned source for Ariadne.
|
||||
|
||||
Use the game installation directory as the game root to process all installed seasons.
|
||||
The utility writes recovered source under <output-root>/source/, transient work under <output-root>/work/, and local logs under <output-root>/logs/.
|
||||
The default output root is <workspace>/src/ariadne/output.
|
||||
Without --force, it refuses to run when any of those directories already exists.
|
||||
With --force, it deletes and recreates only source/, work/, and logs/ under the output root.
|
||||
The script enters a Nix shell for rpycdec when required tools are not already available.
|
||||
Game-derived preparation output must remain local and must not be committed.
|
||||
USAGE
|
||||
}
|
||||
|
||||
fail() {
|
||||
printf 'extract-and-decompile: %s\n' "$*" >&2
|
||||
exit 2
|
||||
}
|
||||
|
||||
require_tool() {
|
||||
local name=$1
|
||||
if ! command -v "$name" >/dev/null 2>&1; then
|
||||
fail "missing required tool '$name'"
|
||||
fi
|
||||
}
|
||||
|
||||
tools_available() {
|
||||
command -v python3 >/dev/null 2>&1 && command -v rpycdec >/dev/null 2>&1
|
||||
}
|
||||
|
||||
enter_nix_shell_if_needed() {
|
||||
if tools_available; then
|
||||
return
|
||||
fi
|
||||
|
||||
if [[ "${ARIADNE_NIX_SHELL:-}" == 1 ]]; then
|
||||
require_tool python3
|
||||
require_tool rpycdec
|
||||
return
|
||||
fi
|
||||
|
||||
require_tool nix
|
||||
|
||||
local tools_nix
|
||||
if [[ -n "${BUILD_WORKSPACE_DIRECTORY:-}" ]]; then
|
||||
tools_nix=$BUILD_WORKSPACE_DIRECTORY/src/ariadne/extract-tools.nix
|
||||
else
|
||||
tools_nix=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)/extract-tools.nix
|
||||
fi
|
||||
|
||||
[[ -f "$tools_nix" ]] || fail "missing Ariadne tool definition: $tools_nix"
|
||||
|
||||
say "entering Nix shell for rpycdec"
|
||||
export ARIADNE_NIX_SHELL=1
|
||||
exec nix shell \
|
||||
--extra-experimental-features 'nix-command flakes' \
|
||||
--file "$tools_nix" \
|
||||
--command bash "$0" "$@"
|
||||
}
|
||||
|
||||
say() {
|
||||
printf 'extract-and-decompile: %s\n' "$*" >&2
|
||||
}
|
||||
|
||||
game_root=
|
||||
script_dir=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)
|
||||
if [[ -n "${BUILD_WORKSPACE_DIRECTORY:-}" ]]; then
|
||||
default_output_root=$BUILD_WORKSPACE_DIRECTORY/src/ariadne/output
|
||||
else
|
||||
default_output_root=$script_dir/output
|
||||
fi
|
||||
output_root=$default_output_root
|
||||
force=false
|
||||
original_args=("$@")
|
||||
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case "$1" in
|
||||
--game-root)
|
||||
[[ $# -ge 2 ]] || fail '--game-root requires a path'
|
||||
game_root=$2
|
||||
shift 2
|
||||
;;
|
||||
--output-root)
|
||||
[[ $# -ge 2 ]] || fail '--output-root requires a path'
|
||||
output_root=$2
|
||||
shift 2
|
||||
;;
|
||||
--force)
|
||||
force=true
|
||||
shift
|
||||
;;
|
||||
-h|--help)
|
||||
usage
|
||||
exit 0
|
||||
;;
|
||||
*)
|
||||
fail "unexpected argument: $1"
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
[[ -n "$game_root" ]] || fail 'missing --game-root <path>'
|
||||
[[ -d "$game_root" ]] || fail "game root is not a directory: $game_root"
|
||||
|
||||
enter_nix_shell_if_needed "${original_args[@]}"
|
||||
|
||||
preparation_dirs=(source work logs)
|
||||
|
||||
for name in "${preparation_dirs[@]}"; do
|
||||
path="$output_root/$name"
|
||||
if [[ -e "$path" && "$force" != true ]]; then
|
||||
fail "refusing to overwrite existing preparation path without --force: $path"
|
||||
fi
|
||||
done
|
||||
|
||||
if [[ "$force" == true ]]; then
|
||||
say "removing existing preparation directories under $output_root"
|
||||
for name in "${preparation_dirs[@]}"; do
|
||||
rm -rf -- "${output_root:?}/$name"
|
||||
done
|
||||
fi
|
||||
|
||||
say "creating preparation directories under $output_root"
|
||||
for name in "${preparation_dirs[@]}"; do
|
||||
mkdir -p -- "$output_root/$name"
|
||||
done
|
||||
|
||||
source_dir=$output_root/source
|
||||
work_dir=$output_root/work
|
||||
logs_dir=$output_root/logs
|
||||
summary_log=$logs_dir/extract-and-decompile.log
|
||||
: > "$summary_log"
|
||||
|
||||
log() {
|
||||
printf '%s\n' "$*" >> "$summary_log"
|
||||
}
|
||||
|
||||
record() {
|
||||
say "$*"
|
||||
log "$*"
|
||||
}
|
||||
|
||||
relative_to_game_root() {
|
||||
realpath --relative-to="$game_root" "$1"
|
||||
}
|
||||
|
||||
is_renpy_runtime_path() {
|
||||
local relative=$1
|
||||
[[ "$relative" == renpy/* || "$relative" == */renpy/* ]]
|
||||
}
|
||||
|
||||
source_output_path() {
|
||||
local relative=$1
|
||||
local destination_prefix=${2:-}
|
||||
if [[ -n "$destination_prefix" ]]; then
|
||||
printf '%s/%s/%s\n' "$source_dir" "$destination_prefix" "$relative"
|
||||
else
|
||||
printf '%s/%s\n' "$source_dir" "$relative"
|
||||
fi
|
||||
}
|
||||
|
||||
source_log_relative() {
|
||||
local relative=$1
|
||||
local destination_prefix=${2:-}
|
||||
if [[ -n "$destination_prefix" ]]; then
|
||||
printf '%s/%s\n' "$destination_prefix" "$relative"
|
||||
else
|
||||
printf '%s\n' "$relative"
|
||||
fi
|
||||
}
|
||||
|
||||
copy_source_file() {
|
||||
local input=$1
|
||||
local input_root=$2
|
||||
local label=$3
|
||||
local destination_prefix=${4:-}
|
||||
local relative output log_relative
|
||||
relative=$(realpath --relative-to="$input_root" "$input")
|
||||
log_relative=$(source_log_relative "$relative" "$destination_prefix")
|
||||
if is_renpy_runtime_path "$relative"; then
|
||||
log "skipped $label Ren'Py runtime source: $log_relative"
|
||||
return
|
||||
fi
|
||||
output=$(source_output_path "$relative" "$destination_prefix")
|
||||
mkdir -p -- "$(dirname -- "$output")"
|
||||
cp -- "$input" "$output"
|
||||
record "copied $label source: $log_relative"
|
||||
}
|
||||
|
||||
copy_loose_source() {
|
||||
copy_source_file "$1" "$game_root" loose
|
||||
}
|
||||
|
||||
decompile_compiled_script() {
|
||||
local input=$1
|
||||
local input_root=$2
|
||||
local destination_prefix=${3:-}
|
||||
local relative output_dir log_file log_relative
|
||||
relative=$(realpath --relative-to="$input_root" "$input")
|
||||
log_relative=$(source_log_relative "$relative" "$destination_prefix")
|
||||
if is_renpy_runtime_path "$relative"; then
|
||||
log "skipped Ren'Py runtime compiled script: $log_relative"
|
||||
return
|
||||
fi
|
||||
output_dir=$(source_output_path "$(dirname -- "$relative")" "$destination_prefix")
|
||||
log_file=$logs_dir/decompile-${log_relative//\//__}.log
|
||||
mkdir -p -- "$output_dir"
|
||||
say "decompiling script: $log_relative"
|
||||
RPYCDEC_NO_WARNING=1 rpycdec decompile --output "$output_dir" "$input" > "$log_file" 2>&1
|
||||
log "decompiled script: $log_relative"
|
||||
}
|
||||
|
||||
extract_archive() {
|
||||
local archive=$1
|
||||
local relative archive_output log_file destination_prefix
|
||||
relative=$(relative_to_game_root "$archive")
|
||||
archive_output=$work_dir/archives/${relative%.rpa}
|
||||
log_file=$logs_dir/unrpa-${relative//\//__}.log
|
||||
destination_prefix=$(dirname -- "$relative")
|
||||
if [[ "$destination_prefix" == "." ]]; then
|
||||
destination_prefix=
|
||||
fi
|
||||
mkdir -p -- "$archive_output"
|
||||
say "extracting archive: $relative"
|
||||
RPYCDEC_NO_WARNING=1 rpycdec unrpa --output "$archive_output" "$archive" > "$log_file" 2>&1
|
||||
log "extracted archive: $relative"
|
||||
|
||||
while IFS= read -r -d '' archived_source; do
|
||||
copy_source_file "$archived_source" "$archive_output" archived "$destination_prefix"
|
||||
done < <(find "$archive_output" -type f -name '*.rpy' -print0 | sort -z)
|
||||
|
||||
while IFS= read -r -d '' compiled; do
|
||||
decompile_compiled_script "$compiled" "$archive_output" "$destination_prefix"
|
||||
done < <(find "$archive_output" -type f \( -name '*.rpyc' -o -name '*.rpymc' \) -print0 | sort -z)
|
||||
}
|
||||
|
||||
say "scanning loose source files"
|
||||
while IFS= read -r -d '' source_file; do
|
||||
copy_loose_source "$source_file"
|
||||
done < <(find "$game_root" -type f -name '*.rpy' -print0 | sort -z)
|
||||
|
||||
say "scanning archives"
|
||||
while IFS= read -r -d '' archive; do
|
||||
extract_archive "$archive"
|
||||
done < <(find "$game_root" -type f -name '*.rpa' -print0 | sort -z)
|
||||
|
||||
say "scanning loose compiled scripts"
|
||||
while IFS= read -r -d '' compiled; do
|
||||
decompile_compiled_script "$compiled" "$game_root"
|
||||
done < <(find "$game_root" -type f \( -name '*.rpyc' -o -name '*.rpymc' \) -print0 | sort -z)
|
||||
|
||||
say "done"
|
||||
@@ -1,29 +0,0 @@
|
||||
let
|
||||
pkgs = import (builtins.getFlake "nixpkgs") { system = builtins.currentSystem; };
|
||||
rpycdec = pkgs.python3Packages.buildPythonApplication {
|
||||
pname = "rpycdec";
|
||||
version = "0.0.0+1000bd1";
|
||||
pyproject = true;
|
||||
src = pkgs.fetchFromGitHub {
|
||||
owner = "cnfatal";
|
||||
repo = "rpycdec";
|
||||
rev = "1000bd1da10ef07e82f6fa560c621e6a4b55d1b8";
|
||||
hash = "sha256-VoVbIKs8xz5x2s0OGqdHbY55fWDruqMAX8YYjEQhwTQ=";
|
||||
};
|
||||
nativeBuildInputs = with pkgs.python3Packages; [
|
||||
hatch-vcs
|
||||
hatchling
|
||||
];
|
||||
env.SETUPTOOLS_SCM_PRETEND_VERSION_FOR_RPYCDEC = "0.0.0+1000bd1";
|
||||
};
|
||||
in
|
||||
pkgs.buildEnv {
|
||||
name = "ariadne-extract-and-decompile-tools";
|
||||
paths = [
|
||||
pkgs.bash
|
||||
pkgs.coreutils
|
||||
pkgs.findutils
|
||||
pkgs.python3
|
||||
rpycdec
|
||||
];
|
||||
}
|
||||
Reference in New Issue
Block a user