157 lines
4.1 KiB
Bash
157 lines
4.1 KiB
Bash
#!/usr/bin/env bash
|
|
set -euo pipefail
|
|
|
|
usage() {
|
|
cat <<'EOF'
|
|
Usage:
|
|
HYPERTWIST_REMOTE_WINDOWS_PASSWORD=... \
|
|
scripts/run-hypertwist-remote-windows-file-pull.sh \
|
|
--map "C:\HyperTwist_worktrees\phase10validate\docs\generated\higher_dimensional_training_maps\phase6c_dedicated_family_package_validation_report.json::docs/generated/higher_dimensional_training_maps/phase6c_dedicated_family_package_validation_report.json"
|
|
|
|
Options:
|
|
--map <remote_windows_path>::<local_repo_path>
|
|
Copy one remote Windows file back into the local repo. May be repeated.
|
|
|
|
--dry-run
|
|
Print the pull plan without transferring files.
|
|
|
|
Environment:
|
|
HYPERTWIST_REMOTE_WINDOWS_PASSWORD Required password for the reverse-SSH Windows user.
|
|
HYPERTWIST_REMOTE_TUNNEL_PORT Optional, defaults to 22022.
|
|
HYPERTWIST_REMOTE_WINDOWS_USER Optional, defaults to "anthracite ace".
|
|
HYPERTWIST_REMOTE_TUNNEL_HOST Optional, defaults to "localhost".
|
|
EOF
|
|
}
|
|
|
|
if ! command -v python3 >/dev/null 2>&1; then
|
|
echo "python3 is required but was not found on PATH." >&2
|
|
exit 1
|
|
fi
|
|
|
|
if ! command -v sha256sum >/dev/null 2>&1; then
|
|
echo "sha256sum is required but was not found on PATH." >&2
|
|
exit 1
|
|
fi
|
|
|
|
repo_root="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
|
remote_ps_wrapper="${repo_root}/scripts/run-hypertwist-remote-windows-powershell.sh"
|
|
|
|
if [[ ! -x "$remote_ps_wrapper" ]]; then
|
|
echo "Expected executable wrapper at $remote_ps_wrapper" >&2
|
|
exit 1
|
|
fi
|
|
|
|
dry_run="false"
|
|
maps=()
|
|
|
|
while [[ $# -gt 0 ]]; do
|
|
case "$1" in
|
|
--map)
|
|
maps+=("${2:-}")
|
|
shift 2
|
|
;;
|
|
--dry-run)
|
|
dry_run="true"
|
|
shift
|
|
;;
|
|
-h|--help)
|
|
usage
|
|
exit 0
|
|
;;
|
|
*)
|
|
usage >&2
|
|
exit 1
|
|
;;
|
|
esac
|
|
done
|
|
|
|
if [[ ${#maps[@]} -eq 0 ]]; then
|
|
echo "Provide at least one --map." >&2
|
|
exit 1
|
|
fi
|
|
|
|
ps_single_quote() {
|
|
printf "'%s'" "${1//\'/\'\'}"
|
|
}
|
|
|
|
write_base64_to_file() {
|
|
local destination_path="$1"
|
|
|
|
python3 -c '
|
|
import base64
|
|
import pathlib
|
|
import sys
|
|
|
|
destination = pathlib.Path(sys.argv[1])
|
|
destination.parent.mkdir(parents=True, exist_ok=True)
|
|
destination.write_bytes(base64.b64decode(sys.stdin.buffer.read()))
|
|
' "$destination_path"
|
|
}
|
|
|
|
for mapping in "${maps[@]}"; do
|
|
if [[ "$mapping" != *"::"* ]]; then
|
|
echo "Map must use <remote_windows_path>::<local_repo_path>: $mapping" >&2
|
|
exit 1
|
|
fi
|
|
|
|
remote_path="${mapping%%::*}"
|
|
local_path="${mapping#*::}"
|
|
|
|
if [[ -z "$remote_path" || -z "$local_path" ]]; then
|
|
echo "Map must include both remote and local paths: $mapping" >&2
|
|
exit 1
|
|
fi
|
|
|
|
if [[ "$local_path" = /* ]]; then
|
|
local_destination="$local_path"
|
|
else
|
|
local_destination="${repo_root}/${local_path}"
|
|
fi
|
|
|
|
if [[ "$dry_run" == "true" ]]; then
|
|
printf '%s -> %s\n' "$remote_path" "$local_destination"
|
|
continue
|
|
fi
|
|
|
|
remote_payload="$(
|
|
cat <<EOF
|
|
\$Path = $(ps_single_quote "$remote_path")
|
|
if (-not (Test-Path -LiteralPath \$Path)) {
|
|
throw "Remote file was not found at '\$Path'."
|
|
}
|
|
\$Bytes = [System.IO.File]::ReadAllBytes(\$Path)
|
|
\$Hash = (Get-FileHash -LiteralPath \$Path -Algorithm SHA256).Hash.ToLowerInvariant()
|
|
Write-Output ('REMOTE_HASH=' + \$Hash)
|
|
Write-Output 'REMOTE_BASE64_BEGIN'
|
|
[Console]::Out.Write([Convert]::ToBase64String(\$Bytes))
|
|
Write-Output ''
|
|
Write-Output 'REMOTE_BASE64_END'
|
|
EOF
|
|
)"
|
|
|
|
remote_output="$("$remote_ps_wrapper" --command "$remote_payload" | tr -d '\r')"
|
|
remote_hash="$(printf '%s\n' "$remote_output" | sed -n 's/^REMOTE_HASH=//p' | head -n 1)"
|
|
|
|
if [[ -z "$remote_hash" ]]; then
|
|
echo "Did not receive REMOTE_HASH for $remote_path" >&2
|
|
exit 1
|
|
fi
|
|
|
|
base64_payload="$(
|
|
printf '%s\n' "$remote_output" \
|
|
| awk '/^REMOTE_BASE64_BEGIN$/{flag=1; next} /^REMOTE_BASE64_END$/{flag=0} flag' \
|
|
| tr -d '\n'
|
|
)"
|
|
|
|
printf '%s' "$base64_payload" | write_base64_to_file "$local_destination"
|
|
|
|
local_hash="$(sha256sum "$local_destination" | awk '{print tolower($1)}')"
|
|
if [[ "$local_hash" != "$remote_hash" ]]; then
|
|
echo "Hash mismatch for $remote_path" >&2
|
|
echo " remote: $remote_hash" >&2
|
|
echo " local : $local_hash" >&2
|
|
exit 1
|
|
fi
|
|
|
|
printf 'Pulled %s -> %s (%s)\n' "$remote_path" "$local_destination" "$local_hash"
|
|
done
|