mirror of
https://github.com/FULU-Foundation/OrcaSlicer-bambulab.git
synced 2026-05-14 06:53:47 -07:00
Initial release
This commit is contained in:
66
tools/pjarczak_bambu_runtime/fetch_nlohmann_json.py
Normal file
66
tools/pjarczak_bambu_runtime/fetch_nlohmann_json.py
Normal file
@@ -0,0 +1,66 @@
|
||||
#!/usr/bin/env python3
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import pathlib
|
||||
import sys
|
||||
import tempfile
|
||||
import urllib.request
|
||||
|
||||
URLS = [
|
||||
"https://raw.githubusercontent.com/nlohmann/json/v3.11.3/single_include/nlohmann/json.hpp",
|
||||
"https://raw.githubusercontent.com/nlohmann/json/develop/single_include/nlohmann/json.hpp",
|
||||
]
|
||||
|
||||
|
||||
def default_dest() -> pathlib.Path:
|
||||
return pathlib.Path(__file__).resolve().parents[2] / "src" / "nlohmann" / "json.hpp"
|
||||
|
||||
|
||||
def valid_header(text: str) -> bool:
|
||||
return "NLOHMANN_JSON_VERSION_MAJOR" in text and "namespace nlohmann" in text
|
||||
|
||||
|
||||
def download(url: str) -> str:
|
||||
with urllib.request.urlopen(url, timeout=60) as r:
|
||||
data = r.read()
|
||||
return data.decode("utf-8")
|
||||
|
||||
|
||||
def main() -> int:
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument("--dest", default=str(default_dest()))
|
||||
args = parser.parse_args()
|
||||
|
||||
dest = pathlib.Path(args.dest).resolve()
|
||||
if dest.is_file() and dest.stat().st_size > 0:
|
||||
text = dest.read_text(encoding="utf-8", errors="ignore")
|
||||
if valid_header(text):
|
||||
print(f"nlohmann json already present: {dest}")
|
||||
return 0
|
||||
|
||||
dest.parent.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
last_error = None
|
||||
for url in URLS:
|
||||
try:
|
||||
print(f"downloading {url}")
|
||||
text = download(url)
|
||||
if not valid_header(text):
|
||||
raise RuntimeError("downloaded file does not look like nlohmann/json.hpp")
|
||||
with tempfile.NamedTemporaryFile("w", delete=False, encoding="utf-8", dir=str(dest.parent)) as tmp:
|
||||
tmp.write(text)
|
||||
tmp_path = pathlib.Path(tmp.name)
|
||||
tmp_path.replace(dest)
|
||||
print(f"saved {dest}")
|
||||
return 0
|
||||
except Exception as exc:
|
||||
last_error = exc
|
||||
print(f"failed {url}: {exc}", file=sys.stderr)
|
||||
|
||||
print(f"failed to fetch nlohmann/json.hpp: {last_error}", file=sys.stderr)
|
||||
return 1
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main())
|
||||
245
tools/pjarczak_bambu_runtime/macos/pjarczak_install_macos_runtime.sh
Executable file
245
tools/pjarczak_bambu_runtime/macos/pjarczak_install_macos_runtime.sh
Executable file
@@ -0,0 +1,245 @@
|
||||
#!/bin/bash
|
||||
set -euo pipefail
|
||||
|
||||
PACKAGE_DIR=""
|
||||
PLUGIN_DIR=""
|
||||
PLUGIN_CACHE_DIR=""
|
||||
REPLACE_EXISTING=0
|
||||
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case "$1" in
|
||||
-PackageDir)
|
||||
PACKAGE_DIR="${2:-}"
|
||||
shift 2
|
||||
;;
|
||||
-PluginDir)
|
||||
PLUGIN_DIR="${2:-}"
|
||||
shift 2
|
||||
;;
|
||||
-PluginCacheDir)
|
||||
PLUGIN_CACHE_DIR="${2:-}"
|
||||
shift 2
|
||||
;;
|
||||
-ReplaceExisting)
|
||||
REPLACE_EXISTING=1
|
||||
shift
|
||||
;;
|
||||
*)
|
||||
echo "unknown argument: $1" >&2
|
||||
exit 2
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
if [[ -z "$PLUGIN_DIR" ]]; then
|
||||
PLUGIN_DIR="$PACKAGE_DIR"
|
||||
fi
|
||||
if [[ -z "$PLUGIN_DIR" ]]; then
|
||||
echo "PluginDir is required" >&2
|
||||
exit 2
|
||||
fi
|
||||
|
||||
APP_SUPPORT_DIR="$HOME/Library/Application Support/OrcaSlicer/macos-bridge"
|
||||
LOCAL_LIMA_ROOT="$APP_SUPPORT_DIR/lima"
|
||||
LOCAL_LIMA_BIN="$LOCAL_LIMA_ROOT/bin"
|
||||
RUNTIME_DIR="${PJARCZAK_MAC_RUNTIME_DIR:-$APP_SUPPORT_DIR/runtime}"
|
||||
mkdir -p "$APP_SUPPORT_DIR" "$LOCAL_LIMA_ROOT" "$RUNTIME_DIR"
|
||||
|
||||
trim_file() {
|
||||
local path="$1"
|
||||
if [[ ! -f "$path" ]]; then
|
||||
return 1
|
||||
fi
|
||||
LC_ALL=C tr -d '\r' < "$path" | head -n 1 | sed 's/^[[:space:]]*//;s/[[:space:]]*$//'
|
||||
}
|
||||
|
||||
find_limactl() {
|
||||
if [[ -n "${PJARCZAK_LIMACTL:-}" && -x "${PJARCZAK_LIMACTL}" ]]; then
|
||||
printf '%s
|
||||
' "$PJARCZAK_LIMACTL"
|
||||
return 0
|
||||
fi
|
||||
if command -v limactl >/dev/null 2>&1; then
|
||||
command -v limactl
|
||||
return 0
|
||||
fi
|
||||
if [[ -x "$LOCAL_LIMA_BIN/limactl" ]]; then
|
||||
printf '%s
|
||||
' "$LOCAL_LIMA_BIN/limactl"
|
||||
return 0
|
||||
fi
|
||||
for candidate in /opt/homebrew/bin/limactl /usr/local/bin/limactl; do
|
||||
if [[ -x "$candidate" ]]; then
|
||||
printf '%s
|
||||
' "$candidate"
|
||||
return 0
|
||||
fi
|
||||
done
|
||||
return 1
|
||||
}
|
||||
|
||||
resolve_lima_version_from_redirect() {
|
||||
local effective_url=""
|
||||
effective_url=$(curl -fsSL -o /dev/null -w '%{url_effective}' https://github.com/lima-vm/lima/releases/latest || true)
|
||||
case "$effective_url" in
|
||||
*/tag/*)
|
||||
printf '%s
|
||||
' "${effective_url##*/}"
|
||||
return 0
|
||||
;;
|
||||
esac
|
||||
return 1
|
||||
}
|
||||
|
||||
resolve_lima_version() {
|
||||
if [[ -n "${PJARCZAK_LIMA_VERSION:-}" ]]; then
|
||||
printf '%s
|
||||
' "$PJARCZAK_LIMA_VERSION"
|
||||
return 0
|
||||
fi
|
||||
|
||||
local version=""
|
||||
version=$(curl -fsSL https://api.github.com/repos/lima-vm/lima/releases/latest | awk -F'"' '/"tag_name"[[:space:]]*:/ { print $4; exit }' || true)
|
||||
if [[ -n "$version" ]]; then
|
||||
printf '%s
|
||||
' "$version"
|
||||
return 0
|
||||
fi
|
||||
|
||||
resolve_lima_version_from_redirect
|
||||
}
|
||||
|
||||
install_lima_binary_locally() {
|
||||
local version
|
||||
version=$(resolve_lima_version)
|
||||
if [[ -z "$version" ]]; then
|
||||
echo "failed to resolve latest Lima version from GitHub API" >&2
|
||||
return 1
|
||||
fi
|
||||
|
||||
local host_arch
|
||||
host_arch=$(uname -m)
|
||||
case "$host_arch" in
|
||||
arm64|aarch64)
|
||||
host_arch=arm64
|
||||
;;
|
||||
x86_64|amd64)
|
||||
host_arch=x86_64
|
||||
;;
|
||||
*)
|
||||
echo "unsupported macOS architecture for Lima: $host_arch" >&2
|
||||
return 1
|
||||
;;
|
||||
esac
|
||||
|
||||
local version_no_v="${version#v}"
|
||||
local base_url="https://github.com/lima-vm/lima/releases/download/${version}"
|
||||
local main_archive="lima-${version_no_v}-Darwin-${host_arch}.tar.gz"
|
||||
local guest_archive="lima-additional-guestagents-${version_no_v}-Darwin-${host_arch}.tar.gz"
|
||||
local tmpdir
|
||||
tmpdir=$(mktemp -d)
|
||||
trap 'rm -rf "$tmpdir"' RETURN
|
||||
|
||||
curl -fL --retry 3 --retry-delay 2 "$base_url/$main_archive" -o "$tmpdir/$main_archive"
|
||||
tar -xzf "$tmpdir/$main_archive" -C "$LOCAL_LIMA_ROOT"
|
||||
|
||||
if curl -fL --retry 3 --retry-delay 2 "$base_url/$guest_archive" -o "$tmpdir/$guest_archive"; then
|
||||
tar -xzf "$tmpdir/$guest_archive" -C "$LOCAL_LIMA_ROOT"
|
||||
fi
|
||||
|
||||
[[ -x "$LOCAL_LIMA_BIN/limactl" ]]
|
||||
}
|
||||
|
||||
ensure_lima_installed() {
|
||||
LIMACTL=$(find_limactl || true)
|
||||
if [[ -n "$LIMACTL" ]]; then
|
||||
return 0
|
||||
fi
|
||||
|
||||
if command -v brew >/dev/null 2>&1; then
|
||||
brew install lima
|
||||
LIMACTL=$(find_limactl || true)
|
||||
if [[ -n "$LIMACTL" ]]; then
|
||||
return 0
|
||||
fi
|
||||
fi
|
||||
|
||||
install_lima_binary_locally
|
||||
LIMACTL=$(find_limactl || true)
|
||||
[[ -n "$LIMACTL" ]]
|
||||
}
|
||||
|
||||
maybe_install_rosetta() {
|
||||
if [[ "$(uname -m)" != "arm64" ]]; then
|
||||
return 0
|
||||
fi
|
||||
if pgrep -q oahd >/dev/null 2>&1; then
|
||||
return 0
|
||||
fi
|
||||
/usr/sbin/softwareupdate --install-rosetta --agree-to-license >/dev/null 2>&1 || true
|
||||
}
|
||||
|
||||
copy_runtime_payload() {
|
||||
local src_dir="$1"
|
||||
local dst_dir="$2"
|
||||
local file
|
||||
local required_files=(
|
||||
libbambu_networking.so
|
||||
libBambuSource.so
|
||||
pjarczak_bambu_linux_host
|
||||
pjarczak_bambu_linux_host_abi1
|
||||
pjarczak_bambu_linux_host_abi0
|
||||
ca-certificates.crt
|
||||
slicer_base64.cer
|
||||
)
|
||||
|
||||
for file in "${required_files[@]}"; do
|
||||
if [[ ! -f "$src_dir/$file" ]]; then
|
||||
echo "missing required runtime payload file: $file" >&2
|
||||
exit 1
|
||||
fi
|
||||
cp -f "$src_dir/$file" "$dst_dir/$file"
|
||||
done
|
||||
|
||||
for file in liblive555.so libagora_rtc_sdk.so libagora-fdkaac.so; do
|
||||
if [[ -f "$src_dir/$file" ]]; then
|
||||
cp -f "$src_dir/$file" "$dst_dir/$file"
|
||||
fi
|
||||
done
|
||||
|
||||
chmod 755 "$dst_dir/pjarczak_bambu_linux_host" "$dst_dir/pjarczak_bambu_linux_host_abi1" "$dst_dir/pjarczak_bambu_linux_host_abi0"
|
||||
}
|
||||
|
||||
INSTANCE="${PJARCZAK_MAC_LIMA_INSTANCE:-}"
|
||||
if [[ -z "$INSTANCE" ]]; then
|
||||
INSTANCE=$(trim_file "$PLUGIN_DIR/pjarczak_lima_instance.txt" || true)
|
||||
fi
|
||||
if [[ -z "$INSTANCE" ]]; then
|
||||
INSTANCE="orcaslicer-bambu-network"
|
||||
fi
|
||||
|
||||
copy_runtime_payload "$PLUGIN_DIR" "$RUNTIME_DIR"
|
||||
ensure_lima_installed
|
||||
maybe_install_rosetta
|
||||
|
||||
START_ARGS=(start "--name=${INSTANCE}" --tty=false --mount-writable)
|
||||
MACOS_MAJOR=$(sw_vers -productVersion | awk -F. '{print $1}')
|
||||
if [[ "$MACOS_MAJOR" -ge 13 ]]; then
|
||||
START_ARGS+=(--vm-type=vz --network=vzNAT)
|
||||
if [[ "$(uname -m)" == "arm64" ]]; then
|
||||
START_ARGS+=(--rosetta)
|
||||
fi
|
||||
fi
|
||||
|
||||
if [[ "$REPLACE_EXISTING" -eq 1 ]]; then
|
||||
"$LIMACTL" stop "$INSTANCE" >/dev/null 2>&1 || true
|
||||
fi
|
||||
|
||||
if ! "$LIMACTL" shell "$INSTANCE" -- /usr/bin/env true >/dev/null 2>&1; then
|
||||
"$LIMACTL" "${START_ARGS[@]}" template:default
|
||||
fi
|
||||
|
||||
"$LIMACTL" start-at-login "$INSTANCE" --enabled >/dev/null 2>&1 || true
|
||||
"$LIMACTL" shell "$INSTANCE" -- /usr/bin/env true >/dev/null
|
||||
printf 'runtime installed
|
||||
'
|
||||
@@ -0,0 +1 @@
|
||||
orcaslicer-bambu-network
|
||||
162
tools/pjarczak_bambu_runtime/macos/pjarczak_verify_macos_runtime.sh
Executable file
162
tools/pjarczak_bambu_runtime/macos/pjarczak_verify_macos_runtime.sh
Executable file
@@ -0,0 +1,162 @@
|
||||
#!/bin/bash
|
||||
set -euo pipefail
|
||||
|
||||
PACKAGE_DIR=""
|
||||
PLUGIN_DIR=""
|
||||
PLUGIN_CACHE_DIR=""
|
||||
ALLOW_MISSING_LINUX_PLUGIN=0
|
||||
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case "$1" in
|
||||
-PackageDir)
|
||||
PACKAGE_DIR="${2:-}"
|
||||
shift 2
|
||||
;;
|
||||
-PluginDir)
|
||||
PLUGIN_DIR="${2:-}"
|
||||
shift 2
|
||||
;;
|
||||
-PluginCacheDir)
|
||||
PLUGIN_CACHE_DIR="${2:-}"
|
||||
shift 2
|
||||
;;
|
||||
-AllowMissingLinuxPlugin)
|
||||
ALLOW_MISSING_LINUX_PLUGIN=1
|
||||
shift
|
||||
;;
|
||||
*)
|
||||
echo "unknown argument: $1" >&2
|
||||
exit 2
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
if [[ -z "$PLUGIN_DIR" ]]; then
|
||||
PLUGIN_DIR="$PACKAGE_DIR"
|
||||
fi
|
||||
if [[ -z "$PLUGIN_DIR" ]]; then
|
||||
echo "PluginDir is required" >&2
|
||||
exit 2
|
||||
fi
|
||||
|
||||
APP_SUPPORT_DIR="$HOME/Library/Application Support/OrcaSlicer/macos-bridge"
|
||||
RUNTIME_DIR="${PJARCZAK_MAC_RUNTIME_DIR:-$APP_SUPPORT_DIR/runtime}"
|
||||
|
||||
trim_file() {
|
||||
local path="$1"
|
||||
if [[ ! -f "$path" ]]; then
|
||||
return 1
|
||||
fi
|
||||
LC_ALL=C tr -d '
|
||||
' < "$path" | head -n 1 | sed 's/^[[:space:]]*//;s/[[:space:]]*$//'
|
||||
}
|
||||
|
||||
find_limactl() {
|
||||
if [[ -n "${PJARCZAK_LIMACTL:-}" && -x "${PJARCZAK_LIMACTL}" ]]; then
|
||||
printf '%s
|
||||
' "$PJARCZAK_LIMACTL"
|
||||
return 0
|
||||
fi
|
||||
if command -v limactl >/dev/null 2>&1; then
|
||||
command -v limactl
|
||||
return 0
|
||||
fi
|
||||
local local_bin="$APP_SUPPORT_DIR/lima/bin/limactl"
|
||||
if [[ -x "$local_bin" ]]; then
|
||||
printf '%s
|
||||
' "$local_bin"
|
||||
return 0
|
||||
fi
|
||||
for candidate in /opt/homebrew/bin/limactl /usr/local/bin/limactl; do
|
||||
if [[ -x "$candidate" ]]; then
|
||||
printf '%s
|
||||
' "$candidate"
|
||||
return 0
|
||||
fi
|
||||
done
|
||||
return 1
|
||||
}
|
||||
|
||||
require_file() {
|
||||
local path="$1"
|
||||
local label="$2"
|
||||
if [[ ! -f "$path" ]]; then
|
||||
echo "missing required file: $label" >&2
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
compare_required_file() {
|
||||
local src="$1"
|
||||
local dst="$2"
|
||||
local label="$3"
|
||||
if [[ ! -f "$src" || ! -f "$dst" ]]; then
|
||||
echo "runtime payload file missing: $label" >&2
|
||||
exit 1
|
||||
fi
|
||||
if ! cmp -s "$src" "$dst"; then
|
||||
echo "runtime payload out of date: $label" >&2
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
mkdir -p "$APP_SUPPORT_DIR"
|
||||
|
||||
require_file "$PLUGIN_DIR/install_runtime_macos.sh" "install_runtime_macos.sh"
|
||||
require_file "$PLUGIN_DIR/verify_runtime_macos.sh" "verify_runtime_macos.sh"
|
||||
require_file "$PLUGIN_DIR/pjarczak_lima_instance.txt" "pjarczak_lima_instance.txt"
|
||||
require_file "$PLUGIN_DIR/pjarczak-bambu-linux-host-wrapper" "pjarczak-bambu-linux-host-wrapper"
|
||||
|
||||
if [[ "$ALLOW_MISSING_LINUX_PLUGIN" -eq 0 ]]; then
|
||||
require_file "$PLUGIN_DIR/libbambu_networking.so" "libbambu_networking.so"
|
||||
require_file "$PLUGIN_DIR/libBambuSource.so" "libBambuSource.so"
|
||||
fi
|
||||
require_file "$PLUGIN_DIR/pjarczak_bambu_linux_host" "pjarczak_bambu_linux_host"
|
||||
require_file "$PLUGIN_DIR/pjarczak_bambu_linux_host_abi1" "pjarczak_bambu_linux_host_abi1"
|
||||
require_file "$PLUGIN_DIR/pjarczak_bambu_linux_host_abi0" "pjarczak_bambu_linux_host_abi0"
|
||||
require_file "$PLUGIN_DIR/ca-certificates.crt" "ca-certificates.crt"
|
||||
require_file "$PLUGIN_DIR/slicer_base64.cer" "slicer_base64.cer"
|
||||
|
||||
require_file "$RUNTIME_DIR/libbambu_networking.so" "runtime/libbambu_networking.so"
|
||||
require_file "$RUNTIME_DIR/libBambuSource.so" "runtime/libBambuSource.so"
|
||||
require_file "$RUNTIME_DIR/pjarczak_bambu_linux_host" "runtime/pjarczak_bambu_linux_host"
|
||||
require_file "$RUNTIME_DIR/pjarczak_bambu_linux_host_abi1" "runtime/pjarczak_bambu_linux_host_abi1"
|
||||
require_file "$RUNTIME_DIR/pjarczak_bambu_linux_host_abi0" "runtime/pjarczak_bambu_linux_host_abi0"
|
||||
require_file "$RUNTIME_DIR/ca-certificates.crt" "runtime/ca-certificates.crt"
|
||||
require_file "$RUNTIME_DIR/slicer_base64.cer" "runtime/slicer_base64.cer"
|
||||
|
||||
compare_required_file "$PLUGIN_DIR/libbambu_networking.so" "$RUNTIME_DIR/libbambu_networking.so" "libbambu_networking.so"
|
||||
compare_required_file "$PLUGIN_DIR/libBambuSource.so" "$RUNTIME_DIR/libBambuSource.so" "libBambuSource.so"
|
||||
compare_required_file "$PLUGIN_DIR/pjarczak_bambu_linux_host" "$RUNTIME_DIR/pjarczak_bambu_linux_host" "pjarczak_bambu_linux_host"
|
||||
compare_required_file "$PLUGIN_DIR/pjarczak_bambu_linux_host_abi1" "$RUNTIME_DIR/pjarczak_bambu_linux_host_abi1" "pjarczak_bambu_linux_host_abi1"
|
||||
compare_required_file "$PLUGIN_DIR/pjarczak_bambu_linux_host_abi0" "$RUNTIME_DIR/pjarczak_bambu_linux_host_abi0" "pjarczak_bambu_linux_host_abi0"
|
||||
compare_required_file "$PLUGIN_DIR/ca-certificates.crt" "$RUNTIME_DIR/ca-certificates.crt" "ca-certificates.crt"
|
||||
compare_required_file "$PLUGIN_DIR/slicer_base64.cer" "$RUNTIME_DIR/slicer_base64.cer" "slicer_base64.cer"
|
||||
|
||||
for optional_file in liblive555.so libagora_rtc_sdk.so libagora-fdkaac.so; do
|
||||
if [[ -f "$PLUGIN_DIR/$optional_file" ]]; then
|
||||
compare_required_file "$PLUGIN_DIR/$optional_file" "$RUNTIME_DIR/$optional_file" "$optional_file"
|
||||
fi
|
||||
done
|
||||
|
||||
LIMACTL=$(find_limactl || true)
|
||||
if [[ -z "$LIMACTL" ]]; then
|
||||
echo "limactl not found" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
INSTANCE="${PJARCZAK_MAC_LIMA_INSTANCE:-}"
|
||||
if [[ -z "$INSTANCE" ]]; then
|
||||
INSTANCE=$(trim_file "$PLUGIN_DIR/pjarczak_lima_instance.txt" || true)
|
||||
fi
|
||||
if [[ -z "$INSTANCE" ]]; then
|
||||
echo "Lima instance name is not configured" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ! "$LIMACTL" shell "$INSTANCE" -- /usr/bin/env true >/dev/null 2>&1; then
|
||||
echo "Lima instance '$INSTANCE' is not ready" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
printf 'runtime ok
|
||||
@@ -0,0 +1,59 @@
|
||||
param(
|
||||
[Parameter(Mandatory = $true)][string]$OutputDir,
|
||||
[Parameter(Mandatory = $true)][string]$RootFs,
|
||||
[Parameter(Mandatory = $true)][string]$LinuxHostBinary,
|
||||
[string]$RuntimeDir = "",
|
||||
[string]$BridgeDll = "",
|
||||
[string]$DistroName = "PJARCZAK-BAMBU"
|
||||
)
|
||||
|
||||
$ErrorActionPreference = 'Stop'
|
||||
|
||||
function Get-ScriptDir {
|
||||
if ($PSScriptRoot) {
|
||||
return $PSScriptRoot
|
||||
}
|
||||
if ($PSCommandPath) {
|
||||
return (Split-Path -Parent $PSCommandPath)
|
||||
}
|
||||
if ($MyInvocation -and $MyInvocation.MyCommand -and $MyInvocation.MyCommand.Path) {
|
||||
return (Split-Path -Parent $MyInvocation.MyCommand.Path)
|
||||
}
|
||||
return (Get-Location).Path
|
||||
}
|
||||
|
||||
$scriptDir = Get-ScriptDir
|
||||
$toolsRoot = [System.IO.Path]::GetFullPath((Join-Path $scriptDir '..'))
|
||||
$wslRoot = Join-Path $toolsRoot 'wsl'
|
||||
|
||||
if (-not (Test-Path $RootFs)) { throw "RootFs not found: $RootFs" }
|
||||
if (-not (Test-Path $LinuxHostBinary)) { throw "LinuxHostBinary not found: $LinuxHostBinary" }
|
||||
if ($RuntimeDir -and -not (Test-Path $RuntimeDir)) { throw "RuntimeDir not found: $RuntimeDir" }
|
||||
if ($BridgeDll -and -not (Test-Path $BridgeDll)) { throw "BridgeDll not found: $BridgeDll" }
|
||||
|
||||
New-Item -ItemType Directory -Force -Path $OutputDir | Out-Null
|
||||
|
||||
Copy-Item -Force (Join-Path $wslRoot 'install_runtime.ps1') (Join-Path $OutputDir 'install_runtime.ps1')
|
||||
Copy-Item -Force (Join-Path $wslRoot 'install_runtime.cmd') (Join-Path $OutputDir 'install_runtime.cmd')
|
||||
Copy-Item -Force (Join-Path $wslRoot 'verify_runtime.ps1') (Join-Path $OutputDir 'verify_runtime.ps1')
|
||||
Copy-Item -Force (Join-Path $wslRoot 'pjarczak_wsl_run_host.sh') (Join-Path $OutputDir 'pjarczak_wsl_run_host.sh')
|
||||
Copy-Item -Force (Join-Path $wslRoot 'pjarczak_wsl_distro.txt') (Join-Path $OutputDir 'pjarczak_wsl_distro.txt')
|
||||
Copy-Item -Force (Join-Path $wslRoot 'pjarczak_plugin_cache_subdir.txt') (Join-Path $OutputDir 'pjarczak_plugin_cache_subdir.txt')
|
||||
|
||||
Set-Content -Path (Join-Path $OutputDir 'pjarczak_wsl_distro.txt') -Value ($DistroName + [Environment]::NewLine) -NoNewline:$false
|
||||
|
||||
Copy-Item -Force $RootFs (Join-Path $OutputDir 'windows-wsl2-rootfs.tar')
|
||||
Copy-Item -Force $LinuxHostBinary (Join-Path $OutputDir 'pjarczak_bambu_linux_host')
|
||||
|
||||
if ($BridgeDll) {
|
||||
Copy-Item -Force $BridgeDll (Join-Path $OutputDir 'pjarczak_bambu_networking_bridge.dll')
|
||||
}
|
||||
|
||||
if ($RuntimeDir) {
|
||||
Get-ChildItem -Path $RuntimeDir -File -ErrorAction Stop | ForEach-Object {
|
||||
Copy-Item -Force $_.FullName (Join-Path $OutputDir $_.Name)
|
||||
}
|
||||
}
|
||||
|
||||
Write-Host 'Bundle created:'
|
||||
Write-Host $OutputDir
|
||||
@@ -0,0 +1,75 @@
|
||||
param(
|
||||
[string]$OutputTar = "",
|
||||
[string]$BaseImage = "ubuntu:24.04",
|
||||
[switch]$Force
|
||||
)
|
||||
|
||||
$ErrorActionPreference = 'Stop'
|
||||
|
||||
function Get-ScriptDir {
|
||||
if (-not [string]::IsNullOrWhiteSpace($PSScriptRoot)) {
|
||||
return $PSScriptRoot
|
||||
}
|
||||
if (-not [string]::IsNullOrWhiteSpace($PSCommandPath)) {
|
||||
return (Split-Path -Parent $PSCommandPath)
|
||||
}
|
||||
if ($MyInvocation.MyCommand -and -not [string]::IsNullOrWhiteSpace($MyInvocation.MyCommand.Path)) {
|
||||
return (Split-Path -Parent $MyInvocation.MyCommand.Path)
|
||||
}
|
||||
return (Get-Location).Path
|
||||
}
|
||||
|
||||
$scriptDir = Get-ScriptDir
|
||||
if ([string]::IsNullOrWhiteSpace($OutputTar)) {
|
||||
$OutputTar = Join-Path $scriptDir 'windows-wsl2-rootfs.tar'
|
||||
}
|
||||
$OutputTar = [System.IO.Path]::GetFullPath($OutputTar)
|
||||
|
||||
if ((Test-Path $OutputTar) -and -not $Force) {
|
||||
Write-Host "Rootfs already exists: $OutputTar"
|
||||
exit 0
|
||||
}
|
||||
|
||||
$docker = Get-Command docker -ErrorAction SilentlyContinue
|
||||
if (-not $docker) {
|
||||
throw 'docker not found. Install Docker Desktop or set PJARCZAK_WSL_ROOTFS_TAR to an existing rootfs tar.'
|
||||
}
|
||||
|
||||
New-Item -ItemType Directory -Force -Path (Split-Path -Parent $OutputTar) | Out-Null
|
||||
|
||||
$containerName = "pjarczak-bambu-rootfs-" + [guid]::NewGuid().ToString('N')
|
||||
try {
|
||||
& docker pull --platform linux/amd64 $BaseImage
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
throw "docker pull failed for image: $BaseImage"
|
||||
}
|
||||
|
||||
& docker create --platform linux/amd64 --name $containerName $BaseImage /bin/sh -lc 'exit 0'
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
throw "docker create failed for image: $BaseImage"
|
||||
}
|
||||
|
||||
if (Test-Path $OutputTar) {
|
||||
Remove-Item -Force $OutputTar
|
||||
}
|
||||
|
||||
$exportProcess = Start-Process -FilePath docker -ArgumentList @('export', $containerName, '-o', $OutputTar) -NoNewWindow -Wait -PassThru
|
||||
if ($exportProcess.ExitCode -ne 0) {
|
||||
throw 'docker export failed'
|
||||
}
|
||||
|
||||
if (!(Test-Path $OutputTar)) {
|
||||
throw "rootfs tar was not created: $OutputTar"
|
||||
}
|
||||
|
||||
$size = (Get-Item $OutputTar).Length
|
||||
if ($size -le 0) {
|
||||
throw "rootfs tar is empty: $OutputTar"
|
||||
}
|
||||
|
||||
Write-Host "WSL rootfs created:"
|
||||
Write-Host $OutputTar
|
||||
}
|
||||
finally {
|
||||
& docker rm -f $containerName 2>$null | Out-Null
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
SCRIPT_DIR="$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)"
|
||||
OUTPUT_TAR="${1:-$SCRIPT_DIR/windows-wsl2-rootfs.tar}"
|
||||
BASE_IMAGE="${PJARCZAK_WSL_ROOTFS_IMAGE:-ubuntu:24.04}"
|
||||
|
||||
if ! command -v docker >/dev/null 2>&1; then
|
||||
echo "docker not found. Install Docker or provide a prebuilt windows-wsl2-rootfs.tar." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
mkdir -p "$(dirname -- "$OUTPUT_TAR")"
|
||||
|
||||
CONTAINER_NAME="pjarczak-bambu-rootfs-$(date +%s)-$$"
|
||||
cleanup() {
|
||||
docker rm -f "$CONTAINER_NAME" >/dev/null 2>&1 || true
|
||||
}
|
||||
trap cleanup EXIT
|
||||
|
||||
docker pull "$BASE_IMAGE" >/dev/null
|
||||
docker create --name "$CONTAINER_NAME" "$BASE_IMAGE" /bin/sh -lc 'exit 0' >/dev/null
|
||||
|
||||
rm -f "$OUTPUT_TAR"
|
||||
docker export "$CONTAINER_NAME" -o "$OUTPUT_TAR"
|
||||
|
||||
if [[ ! -s "$OUTPUT_TAR" ]]; then
|
||||
echo "failed to create rootfs tar: $OUTPUT_TAR" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "WSL rootfs created:"
|
||||
echo " $OUTPUT_TAR"
|
||||
10
tools/pjarczak_bambu_runtime/wsl/install_runtime.cmd
Normal file
10
tools/pjarczak_bambu_runtime/wsl/install_runtime.cmd
Normal file
@@ -0,0 +1,10 @@
|
||||
@echo off
|
||||
setlocal
|
||||
where pwsh >nul 2>nul
|
||||
if %errorlevel%==0 (
|
||||
pwsh -NoProfile -ExecutionPolicy Bypass -File "%~dp0install_runtime.ps1" %*
|
||||
) else (
|
||||
powershell -NoProfile -ExecutionPolicy Bypass -File "%~dp0install_runtime.ps1" %*
|
||||
)
|
||||
set "EXIT_CODE=%ERRORLEVEL%"
|
||||
endlocal & exit /b %EXIT_CODE%
|
||||
456
tools/pjarczak_bambu_runtime/wsl/install_runtime.ps1
Normal file
456
tools/pjarczak_bambu_runtime/wsl/install_runtime.ps1
Normal file
@@ -0,0 +1,456 @@
|
||||
param(
|
||||
[string]$PackageDir = "",
|
||||
[string]$PluginDir = "",
|
||||
[string]$PluginCacheDir = "",
|
||||
[string]$DistroName = "",
|
||||
[string]$InstallDir = "",
|
||||
[switch]$ReplaceExisting,
|
||||
[switch]$SkipCopyToPluginDir
|
||||
)
|
||||
|
||||
$ErrorActionPreference = 'Stop'
|
||||
|
||||
function Get-ScriptDir {
|
||||
if (-not [string]::IsNullOrWhiteSpace($PSScriptRoot)) {
|
||||
return $PSScriptRoot
|
||||
}
|
||||
if (-not [string]::IsNullOrWhiteSpace($PSCommandPath)) {
|
||||
return (Split-Path -Parent $PSCommandPath)
|
||||
}
|
||||
if ($MyInvocation.MyCommand -and -not [string]::IsNullOrWhiteSpace($MyInvocation.MyCommand.Path)) {
|
||||
return (Split-Path -Parent $MyInvocation.MyCommand.Path)
|
||||
}
|
||||
return (Get-Location).Path
|
||||
}
|
||||
|
||||
function Convert-FileToLf([string]$Path) {
|
||||
if ([string]::IsNullOrWhiteSpace($Path) -or !(Test-Path $Path)) {
|
||||
return
|
||||
}
|
||||
|
||||
$content = [System.IO.File]::ReadAllText($Path)
|
||||
$content = $content.Replace("`r`n", "`n").Replace("`r", "`n")
|
||||
$utf8NoBom = [System.Text.UTF8Encoding]::new($false)
|
||||
[System.IO.File]::WriteAllText($Path, $content, $utf8NoBom)
|
||||
}
|
||||
|
||||
function Copy-IfExists([string]$Source, [string]$Destination) {
|
||||
if (Test-Path $Source) {
|
||||
$srcFull = [System.IO.Path]::GetFullPath($Source)
|
||||
$dstFull = [System.IO.Path]::GetFullPath($Destination)
|
||||
if ($srcFull -ieq $dstFull) {
|
||||
return
|
||||
}
|
||||
New-Item -ItemType Directory -Force -Path (Split-Path -Parent $Destination) | Out-Null
|
||||
Copy-Item -Force $Source $Destination
|
||||
}
|
||||
}
|
||||
|
||||
function Sync-Directory([string]$SourceDir, [string]$DestinationDir) {
|
||||
if (!(Test-Path $SourceDir)) {
|
||||
return
|
||||
}
|
||||
if (Test-Path $DestinationDir) {
|
||||
Remove-Item -Recurse -Force $DestinationDir
|
||||
}
|
||||
New-Item -ItemType Directory -Force -Path $DestinationDir | Out-Null
|
||||
Copy-Item -Recurse -Force (Join-Path $SourceDir '*') $DestinationDir
|
||||
}
|
||||
|
||||
function Resolve-DistroName([string]$Dir, [string]$Current) {
|
||||
if (-not [string]::IsNullOrWhiteSpace($Current)) {
|
||||
return $Current
|
||||
}
|
||||
|
||||
$distroFile = Join-Path $Dir 'pjarczak_wsl_distro.txt'
|
||||
if (Test-Path $distroFile) {
|
||||
$value = (Get-Content $distroFile -Raw).Trim()
|
||||
if (-not [string]::IsNullOrWhiteSpace($value)) {
|
||||
return $value
|
||||
}
|
||||
}
|
||||
|
||||
if ($env:PJARCZAK_WSL_DISTRO) {
|
||||
return $env:PJARCZAK_WSL_DISTRO.Trim()
|
||||
}
|
||||
|
||||
return 'PJARCZAK-BAMBU'
|
||||
}
|
||||
|
||||
function Get-FileSha256([string]$Path) {
|
||||
return (Get-FileHash -Algorithm SHA256 -Path $Path).Hash.ToLowerInvariant()
|
||||
}
|
||||
|
||||
function Get-RootFsHashMarkerPath([string]$Dir) {
|
||||
return (Join-Path $Dir 'pjarczak-rootfs-sha256.txt')
|
||||
}
|
||||
|
||||
function Write-RootFsHashMarker([string]$Dir, [string]$Hash) {
|
||||
if ([string]::IsNullOrWhiteSpace($Dir) -or [string]::IsNullOrWhiteSpace($Hash)) {
|
||||
return
|
||||
}
|
||||
New-Item -ItemType Directory -Force -Path $Dir | Out-Null
|
||||
Set-Content -Path (Get-RootFsHashMarkerPath $Dir) -Value ($Hash.Trim().ToLowerInvariant()) -NoNewline
|
||||
}
|
||||
|
||||
function Read-RootFsHashMarker([string]$Dir) {
|
||||
$path = Get-RootFsHashMarkerPath $Dir
|
||||
if (!(Test-Path $path)) {
|
||||
return ''
|
||||
}
|
||||
return ((Get-Content $path -Raw).Trim().ToLowerInvariant())
|
||||
}
|
||||
|
||||
|
||||
function Resolve-PluginCacheDir([string]$Dir, [string]$Current) {
|
||||
if (-not [string]::IsNullOrWhiteSpace($Current)) {
|
||||
return [System.IO.Path]::GetFullPath($Current.Trim())
|
||||
}
|
||||
|
||||
if ($env:PJARCZAK_BAMBU_WINDOWS_PLUGIN_CACHE_DIR) {
|
||||
return [System.IO.Path]::GetFullPath($env:PJARCZAK_BAMBU_WINDOWS_PLUGIN_CACHE_DIR.Trim())
|
||||
}
|
||||
|
||||
$subdirFile = Join-Path $Dir 'pjarczak_plugin_cache_subdir.txt'
|
||||
if (Test-Path $subdirFile) {
|
||||
$subdir = (Get-Content $subdirFile -Raw).Trim()
|
||||
if (-not [string]::IsNullOrWhiteSpace($subdir)) {
|
||||
if (-not $env:APPDATA) { throw 'APPDATA is not available' }
|
||||
return [System.IO.Path]::GetFullPath((Join-Path $env:APPDATA $subdir))
|
||||
}
|
||||
}
|
||||
|
||||
if (-not $env:APPDATA) { throw 'APPDATA is not available' }
|
||||
return [System.IO.Path]::GetFullPath((Join-Path $env:APPDATA 'OrcaSlicer\ota\plugins'))
|
||||
}
|
||||
|
||||
function Normalize-PluginCacheDir([string]$Path) {
|
||||
if ([string]::IsNullOrWhiteSpace($Path)) {
|
||||
return $Path
|
||||
}
|
||||
$full = [System.IO.Path]::GetFullPath($Path)
|
||||
$pluginsChild = Join-Path $full 'plugins'
|
||||
if ((Split-Path -Leaf $full) -ieq 'ota' -and (Test-Path $pluginsChild)) {
|
||||
return [System.IO.Path]::GetFullPath($pluginsChild)
|
||||
}
|
||||
if ((Test-Path $pluginsChild) -and !(Test-Path (Join-Path $full 'libbambu_networking.so')) -and !(Test-Path (Join-Path $full 'libBambuSource.so'))) {
|
||||
return [System.IO.Path]::GetFullPath($pluginsChild)
|
||||
}
|
||||
return $full
|
||||
}
|
||||
|
||||
function Read-TextAuto([string]$Path) {
|
||||
if (!(Test-Path $Path)) {
|
||||
return ''
|
||||
}
|
||||
|
||||
$bytes = [System.IO.File]::ReadAllBytes($Path)
|
||||
if ($bytes.Length -eq 0) {
|
||||
return ''
|
||||
}
|
||||
|
||||
if ($bytes.Length -ge 2 -and $bytes[0] -eq 0xFF -and $bytes[1] -eq 0xFE) {
|
||||
return ([System.Text.Encoding]::Unicode.GetString($bytes, 2, $bytes.Length - 2) -replace "`0", '')
|
||||
}
|
||||
if ($bytes.Length -ge 2 -and $bytes[0] -eq 0xFE -and $bytes[1] -eq 0xFF) {
|
||||
return ([System.Text.Encoding]::BigEndianUnicode.GetString($bytes, 2, $bytes.Length - 2) -replace "`0", '')
|
||||
}
|
||||
if ($bytes.Length -ge 3 -and $bytes[0] -eq 0xEF -and $bytes[1] -eq 0xBB -and $bytes[2] -eq 0xBF) {
|
||||
return ([System.Text.Encoding]::UTF8.GetString($bytes, 3, $bytes.Length - 3) -replace "`0", '')
|
||||
}
|
||||
|
||||
for ($i = 1; $i -lt [Math]::Min($bytes.Length, 64); $i += 2) {
|
||||
if ($bytes[$i] -eq 0) {
|
||||
return ([System.Text.Encoding]::Unicode.GetString($bytes) -replace "`0", '')
|
||||
}
|
||||
}
|
||||
|
||||
return ([System.Text.Encoding]::UTF8.GetString($bytes) -replace "`0", '')
|
||||
}
|
||||
|
||||
function Normalize-NativeText([string]$Text) {
|
||||
if ([string]::IsNullOrEmpty($Text)) {
|
||||
return ''
|
||||
}
|
||||
$value = $Text -replace "`0", ''
|
||||
$value = $value -replace "`r`n", "`n"
|
||||
$value = $value -replace "`r", "`n"
|
||||
return $value
|
||||
}
|
||||
|
||||
function Invoke-NativeCapture([string]$FilePath, [string[]]$ArgumentList) {
|
||||
$stdoutPath = [System.IO.Path]::GetTempFileName()
|
||||
$stderrPath = [System.IO.Path]::GetTempFileName()
|
||||
try {
|
||||
$proc = Start-Process -FilePath $FilePath -ArgumentList $ArgumentList -Wait -PassThru -RedirectStandardOutput $stdoutPath -RedirectStandardError $stderrPath -WindowStyle Hidden
|
||||
$stdoutText = if (Test-Path $stdoutPath) { Normalize-NativeText (Read-TextAuto $stdoutPath) } else { '' }
|
||||
$stderrText = if (Test-Path $stderrPath) { Normalize-NativeText (Read-TextAuto $stderrPath) } else { '' }
|
||||
$combined = (($stdoutText + "`n" + $stderrText).Trim())
|
||||
return @{
|
||||
ExitCode = $proc.ExitCode
|
||||
StdOut = $stdoutText
|
||||
StdErr = $stderrText
|
||||
Combined = $combined
|
||||
}
|
||||
} finally {
|
||||
Remove-Item -Force -ErrorAction SilentlyContinue $stdoutPath, $stderrPath
|
||||
}
|
||||
}
|
||||
|
||||
function Test-WslDistroExists([string]$WslPath, [string]$Name, [ref]$Reason) {
|
||||
$list = Invoke-NativeCapture $WslPath @('--list', '--quiet')
|
||||
if ($list.ExitCode -ne 0) {
|
||||
$text = $list.Combined
|
||||
if ([string]::IsNullOrWhiteSpace($text)) {
|
||||
throw 'Failed to query WSL distributions'
|
||||
}
|
||||
throw ("Failed to query WSL distributions: {0}" -f $text)
|
||||
}
|
||||
|
||||
$exists = $false
|
||||
foreach ($line in ($list.StdOut -split "`n")) {
|
||||
$item = $line.Trim()
|
||||
if ([string]::IsNullOrWhiteSpace($item)) {
|
||||
continue
|
||||
}
|
||||
if ($item -ieq $Name) {
|
||||
$exists = $true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if (-not $exists) {
|
||||
$Reason.Value = "WSL distro '$Name' is not installed"
|
||||
return $false
|
||||
}
|
||||
|
||||
$probe = Invoke-NativeCapture $WslPath @('-d', $Name, '--user', 'root', '--', 'sh', '-lc', 'true')
|
||||
if ($probe.ExitCode -eq 0) {
|
||||
$Reason.Value = ''
|
||||
return $true
|
||||
}
|
||||
|
||||
$text = $probe.Combined
|
||||
if ([string]::IsNullOrWhiteSpace($text)) {
|
||||
throw "Failed to start WSL distro '$Name'"
|
||||
}
|
||||
|
||||
throw ("Failed to start WSL distro '{0}': {1}" -f $Name, $text)
|
||||
}
|
||||
|
||||
$scriptDir = Get-ScriptDir
|
||||
$defaultPackageDir = $scriptDir
|
||||
if ([string]::IsNullOrWhiteSpace($PackageDir)) {
|
||||
$PackageDir = $defaultPackageDir
|
||||
}
|
||||
$PackageDir = [System.IO.Path]::GetFullPath($PackageDir)
|
||||
|
||||
$DistroName = Resolve-DistroName $PackageDir $DistroName
|
||||
$PluginCacheDir = Normalize-PluginCacheDir (Resolve-PluginCacheDir $PackageDir $PluginCacheDir)
|
||||
|
||||
if ([string]::IsNullOrWhiteSpace($PluginDir)) {
|
||||
if (-not $env:APPDATA) {
|
||||
throw 'APPDATA is not available'
|
||||
}
|
||||
$PluginDir = Join-Path $env:APPDATA 'OrcaSlicer\plugins'
|
||||
}
|
||||
$PluginDir = [System.IO.Path]::GetFullPath($PluginDir)
|
||||
|
||||
if ([string]::IsNullOrWhiteSpace($InstallDir)) {
|
||||
if (-not $env:LOCALAPPDATA) {
|
||||
throw 'LOCALAPPDATA is not available'
|
||||
}
|
||||
$InstallDir = Join-Path $env:LOCALAPPDATA $DistroName
|
||||
}
|
||||
$InstallDir = [System.IO.Path]::GetFullPath($InstallDir)
|
||||
|
||||
$wsl = Join-Path $env:WINDIR 'System32\wsl.exe'
|
||||
if (!(Test-Path $wsl)) {
|
||||
throw 'wsl.exe not found'
|
||||
}
|
||||
|
||||
if (-not $SkipCopyToPluginDir) {
|
||||
New-Item -ItemType Directory -Force -Path $PluginDir | Out-Null
|
||||
|
||||
$fileNames = @(
|
||||
'pjarczak_bambu_networking_bridge.dll',
|
||||
'pjarczak_bambu_linux_host',
|
||||
'pjarczak_bambu_linux_host_abi1',
|
||||
'pjarczak_bambu_linux_host_abi0',
|
||||
'pjarczak_wsl_distro.txt',
|
||||
'pjarczak_plugin_cache_subdir.txt',
|
||||
'pjarczak_wsl_run_host.sh',
|
||||
'pjarczak-wsl-run-host.sh',
|
||||
'install_runtime.ps1',
|
||||
'install_runtime.cmd',
|
||||
'verify_runtime.ps1',
|
||||
'windows-wsl2-rootfs.tar',
|
||||
'README_runtime_bridge.txt',
|
||||
'assemble_windows_runtime_bundle.ps1',
|
||||
'linux_payload_manifest.json',
|
||||
'libbambu_networking.so',
|
||||
'libBambuSource.so',
|
||||
'liblive555.so',
|
||||
'libagora_rtc_sdk.so',
|
||||
'libagora-fdkaac.so',
|
||||
'ca-certificates.crt',
|
||||
'slicer_base64.cer'
|
||||
)
|
||||
|
||||
foreach ($name in $fileNames) {
|
||||
Copy-IfExists (Join-Path $PackageDir $name) (Join-Path $PluginDir $name)
|
||||
}
|
||||
|
||||
Get-ChildItem -Path $PackageDir -File -ErrorAction SilentlyContinue | ForEach-Object {
|
||||
$name = $_.Name
|
||||
if ($name -match '^lib.+\.so(\..+)?$') {
|
||||
Copy-IfExists $_.FullName (Join-Path $PluginDir $name)
|
||||
}
|
||||
}
|
||||
|
||||
$legacyRuntimeDir = Join-Path $PluginDir 'pjarczak_bambu_linux_host.runtime'
|
||||
if (Test-Path $legacyRuntimeDir) {
|
||||
Remove-Item -Recurse -Force $legacyRuntimeDir
|
||||
}
|
||||
$PackageDir = $PluginDir
|
||||
|
||||
Write-Host "Bridge package dir: $PackageDir"
|
||||
Write-Host "Plugin dir: $PluginDir"
|
||||
Write-Host "Plugin cache dir: $PluginCacheDir"
|
||||
Write-Host "WSL distro: $DistroName"
|
||||
}
|
||||
|
||||
$requiredFiles = @(
|
||||
'pjarczak_bambu_networking_bridge.dll',
|
||||
'pjarczak_bambu_linux_host',
|
||||
'pjarczak_bambu_linux_host_abi1',
|
||||
'pjarczak_bambu_linux_host_abi0',
|
||||
'pjarczak_wsl_distro.txt',
|
||||
'install_runtime.ps1',
|
||||
'verify_runtime.ps1',
|
||||
'windows-wsl2-rootfs.tar',
|
||||
'ca-certificates.crt',
|
||||
'slicer_base64.cer'
|
||||
)
|
||||
|
||||
foreach ($name in $requiredFiles) {
|
||||
$path = Join-Path $PackageDir $name
|
||||
if (!(Test-Path $path)) {
|
||||
throw "Missing package file: $name"
|
||||
}
|
||||
}
|
||||
|
||||
$bootstrapPath = Join-Path $PackageDir 'pjarczak_wsl_run_host.sh'
|
||||
if (!(Test-Path $bootstrapPath)) { $bootstrapPath = Join-Path $PackageDir 'pjarczak-wsl-run-host.sh' }
|
||||
if (!(Test-Path $bootstrapPath)) {
|
||||
throw 'Missing package file: pjarczak_wsl_run_host.sh'
|
||||
}
|
||||
|
||||
try {
|
||||
& $wsl --status | Out-Null
|
||||
} catch {
|
||||
throw 'WSL is not ready. Run as Administrator once and enable Microsoft-Windows-Subsystem-Linux and VirtualMachinePlatform, then reboot.'
|
||||
}
|
||||
|
||||
Convert-FileToLf $bootstrapPath
|
||||
|
||||
$rootFsTar = Join-Path $PackageDir 'windows-wsl2-rootfs.tar'
|
||||
$currentRootFsHash = Get-FileSha256 $rootFsTar
|
||||
$storedRootFsHash = Read-RootFsHashMarker $InstallDir
|
||||
|
||||
$distroReason = ''
|
||||
$alreadyInstalled = Test-WslDistroExists $wsl $DistroName ([ref]$distroReason)
|
||||
if ($alreadyInstalled) {
|
||||
if (-not $ReplaceExisting) {
|
||||
if ([string]::IsNullOrWhiteSpace($storedRootFsHash) -or $storedRootFsHash -ne $currentRootFsHash) {
|
||||
Write-Host "WSL rootfs changed or marker missing - reinstalling distro $DistroName"
|
||||
$ReplaceExisting = $true
|
||||
}
|
||||
}
|
||||
|
||||
if ($ReplaceExisting) {
|
||||
& $wsl --terminate $DistroName 2>$null | Out-Null
|
||||
& $wsl --unregister $DistroName
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
throw "Failed to unregister existing distro '$DistroName'"
|
||||
}
|
||||
$alreadyInstalled = $null
|
||||
}
|
||||
}
|
||||
|
||||
if (-not $alreadyInstalled) {
|
||||
New-Item -ItemType Directory -Force -Path $InstallDir | Out-Null
|
||||
|
||||
& $wsl --import $DistroName $InstallDir $rootFsTar --version 2
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
throw "wsl --import failed for distro '$DistroName'"
|
||||
}
|
||||
|
||||
$wslConf = @'
|
||||
[automount]
|
||||
enabled=true
|
||||
root=/mnt/
|
||||
mountFsTab=false
|
||||
|
||||
[interop]
|
||||
enabled=true
|
||||
appendWindowsPath=false
|
||||
'@
|
||||
|
||||
$setupCmd = @"
|
||||
cat > /etc/wsl.conf <<'WSL_EOF'
|
||||
$wslConf
|
||||
WSL_EOF
|
||||
mkdir -p /root/.pjarczak-bambu-runtime
|
||||
"@
|
||||
|
||||
& $wsl -d $DistroName --user root -- sh -lc $setupCmd
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
throw "Failed to initialize distro '$DistroName'"
|
||||
}
|
||||
|
||||
& $wsl --terminate $DistroName
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
throw "Failed to terminate distro '$DistroName' after initialization"
|
||||
}
|
||||
|
||||
Write-RootFsHashMarker $InstallDir $currentRootFsHash
|
||||
} elseif ($storedRootFsHash -ne $currentRootFsHash) {
|
||||
Write-RootFsHashMarker $InstallDir $currentRootFsHash
|
||||
}
|
||||
|
||||
$verifyArgs = @(
|
||||
'-NoProfile',
|
||||
'-ExecutionPolicy', 'Bypass',
|
||||
'-File', (Join-Path $PackageDir 'verify_runtime.ps1'),
|
||||
'-PackageDir', $PackageDir,
|
||||
'-DistroName', $DistroName,
|
||||
'-PluginCacheDir', $PluginCacheDir,
|
||||
'-AllowMissingLinuxPlugin',
|
||||
'-SkipProbe'
|
||||
)
|
||||
|
||||
$verifyShell = $null
|
||||
$pwshCmd = Get-Command pwsh -ErrorAction SilentlyContinue
|
||||
if ($pwshCmd) {
|
||||
$verifyShell = $pwshCmd.Source
|
||||
} else {
|
||||
$powershellCmd = Get-Command powershell -ErrorAction SilentlyContinue
|
||||
if ($powershellCmd) {
|
||||
$verifyShell = $powershellCmd.Source
|
||||
}
|
||||
}
|
||||
if ([string]::IsNullOrWhiteSpace($verifyShell)) {
|
||||
throw 'No PowerShell host found to run verify_runtime.ps1'
|
||||
}
|
||||
|
||||
& $verifyShell @verifyArgs
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
throw 'verify_runtime.ps1 failed'
|
||||
}
|
||||
|
||||
Write-Host ''
|
||||
Write-Host "WSL runtime installed to: $PackageDir"
|
||||
Write-Host "WSL distro: $DistroName"
|
||||
Write-Host "WSL install dir: $InstallDir"
|
||||
Write-Host 'Now start OrcaSlicer.'
|
||||
61
tools/pjarczak_bambu_runtime/wsl/pjarczak_bambu_linux_host
Executable file
61
tools/pjarczak_bambu_runtime/wsl/pjarczak_bambu_linux_host
Executable file
@@ -0,0 +1,61 @@
|
||||
#!/bin/sh
|
||||
set -eu
|
||||
|
||||
DIR=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)
|
||||
CACHE_FILE="$DIR/.selected_host_abi"
|
||||
|
||||
run_probe() {
|
||||
bin="$1"
|
||||
[ -x "$bin" ] || return 1
|
||||
LD_LIBRARY_PATH="$DIR${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH}" \
|
||||
PJARCZAK_BAMBU_PROBE_LOG_DIR="${PJARCZAK_BAMBU_PROBE_LOG_DIR:-$DIR}" \
|
||||
PJARCZAK_BAMBU_COUNTRY_CODE="${PJARCZAK_BAMBU_COUNTRY_CODE:-PL}" \
|
||||
"$bin" --probe-auth >/dev/null 2>&1
|
||||
}
|
||||
|
||||
choose_bin() {
|
||||
forced="${PJARCZAK_FORCE_HOST_ABI:-}"
|
||||
if [ -n "$forced" ] && [ -x "$DIR/pjarczak_bambu_linux_host_$forced" ]; then
|
||||
printf '%s\n' "$DIR/pjarczak_bambu_linux_host_$forced"
|
||||
return 0
|
||||
fi
|
||||
|
||||
if [ -f "$CACHE_FILE" ]; then
|
||||
cached=$(cat "$CACHE_FILE" 2>/dev/null || true)
|
||||
if [ -n "$cached" ] && [ -x "$DIR/pjarczak_bambu_linux_host_$cached" ]; then
|
||||
printf '%s\n' "$DIR/pjarczak_bambu_linux_host_$cached"
|
||||
return 0
|
||||
fi
|
||||
fi
|
||||
|
||||
for abi in abi1 abi0; do
|
||||
if run_probe "$DIR/pjarczak_bambu_linux_host_$abi"; then
|
||||
printf '%s' "$abi" > "$CACHE_FILE"
|
||||
printf '%s\n' "$DIR/pjarczak_bambu_linux_host_$abi"
|
||||
return 0
|
||||
fi
|
||||
done
|
||||
|
||||
if [ -x "$DIR/pjarczak_bambu_linux_host_abi1" ]; then
|
||||
printf '%s\n' "$DIR/pjarczak_bambu_linux_host_abi1"
|
||||
return 0
|
||||
fi
|
||||
if [ -x "$DIR/pjarczak_bambu_linux_host_abi0" ]; then
|
||||
printf '%s\n' "$DIR/pjarczak_bambu_linux_host_abi0"
|
||||
return 0
|
||||
fi
|
||||
return 1
|
||||
}
|
||||
|
||||
BIN=$(choose_bin) || {
|
||||
echo "no compatible host ABI variant found" >&2
|
||||
exit 127
|
||||
}
|
||||
|
||||
if [ "${1:-}" = "--print-bin" ]; then
|
||||
printf '%s\n' "$BIN"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
export LD_LIBRARY_PATH="$DIR${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH}"
|
||||
exec "$BIN" "$@"
|
||||
@@ -0,0 +1 @@
|
||||
OrcaSlicer\ota\plugins
|
||||
1
tools/pjarczak_bambu_runtime/wsl/pjarczak_wsl_distro.txt
Normal file
1
tools/pjarczak_bambu_runtime/wsl/pjarczak_wsl_distro.txt
Normal file
@@ -0,0 +1 @@
|
||||
PJARCZAK-BAMBU
|
||||
229
tools/pjarczak_bambu_runtime/wsl/pjarczak_wsl_run_host.sh
Executable file
229
tools/pjarczak_bambu_runtime/wsl/pjarczak_wsl_run_host.sh
Executable file
@@ -0,0 +1,229 @@
|
||||
#!/bin/sh
|
||||
set -eu
|
||||
|
||||
log() {
|
||||
printf '%s\n' "[pjarczak_wsl_run_host] $*" >&2
|
||||
}
|
||||
|
||||
MODE="run"
|
||||
if [ "${1:-}" = "--probe" ]; then
|
||||
MODE="probe"
|
||||
shift
|
||||
fi
|
||||
|
||||
PACKAGE_DIR="${1:-${PJARCZAK_BAMBU_WINDOWS_PLUGIN_DIR:-}}"
|
||||
PLUGIN_CACHE_DIR="${2:-${PJARCZAK_BAMBU_WINDOWS_PLUGIN_CACHE_DIR:-}}"
|
||||
if [ -z "$PACKAGE_DIR" ]; then
|
||||
log "missing Windows package directory path"
|
||||
exit 127
|
||||
fi
|
||||
|
||||
if [ -n "$PLUGIN_CACHE_DIR" ] && [ ! -d "$PLUGIN_CACHE_DIR" ] && [ -d "$PLUGIN_CACHE_DIR/plugins" ]; then
|
||||
PLUGIN_CACHE_DIR="$PLUGIN_CACHE_DIR/plugins"
|
||||
fi
|
||||
if [ -n "$PLUGIN_CACHE_DIR" ] && [ -d "$PLUGIN_CACHE_DIR/plugins" ] && [ ! -f "$PLUGIN_CACHE_DIR/libbambu_networking.so" ] && [ ! -f "$PLUGIN_CACHE_DIR/libBambuSource.so" ]; then
|
||||
PLUGIN_CACHE_DIR="$PLUGIN_CACHE_DIR/plugins"
|
||||
fi
|
||||
|
||||
HOST_SRC="$PACKAGE_DIR/pjarczak_bambu_linux_host"
|
||||
if [ ! -f "$HOST_SRC" ]; then
|
||||
log "missing runtime file: $HOST_SRC"
|
||||
exit 127
|
||||
fi
|
||||
|
||||
find_preferred_file() {
|
||||
name="$1"
|
||||
if [ -f "$PACKAGE_DIR/$name" ]; then
|
||||
printf '%s\n' "$PACKAGE_DIR/$name"
|
||||
return 0
|
||||
fi
|
||||
if [ -n "$PLUGIN_CACHE_DIR" ] && [ -f "$PLUGIN_CACHE_DIR/$name" ]; then
|
||||
printf '%s\n' "$PLUGIN_CACHE_DIR/$name"
|
||||
return 0
|
||||
fi
|
||||
return 1
|
||||
}
|
||||
|
||||
resolve_payload_sources() {
|
||||
NETWORK_SRC="$(find_preferred_file libbambu_networking.so || true)"
|
||||
SOURCE_SRC="$(find_preferred_file libBambuSource.so || true)"
|
||||
ABI1_SRC="$(find_preferred_file pjarczak_bambu_linux_host_abi1 || true)"
|
||||
ABI0_SRC="$(find_preferred_file pjarczak_bambu_linux_host_abi0 || true)"
|
||||
CA_BUNDLE_SRC="$(find_preferred_file ca-certificates.crt || true)"
|
||||
SLICER_CERT_SRC="$(find_preferred_file slicer_base64.cer || true)"
|
||||
MANIFEST_SRC="$(find_preferred_file linux_payload_manifest.json || true)"
|
||||
}
|
||||
|
||||
wait_for_payload_sources() {
|
||||
if [ "$MODE" = "probe" ]; then
|
||||
return 1
|
||||
fi
|
||||
WAIT_SECS="${PJARCZAK_BAMBU_PLUGIN_WAIT_SECS:-300}"
|
||||
SLEEP_SECS="${PJARCZAK_BAMBU_PLUGIN_WAIT_INTERVAL_SECS:-2}"
|
||||
DEADLINE=$(( $(date +%s) + WAIT_SECS ))
|
||||
while :; do
|
||||
resolve_payload_sources
|
||||
if [ -n "$NETWORK_SRC" ] && [ -n "$SOURCE_SRC" ]; then
|
||||
return 0
|
||||
fi
|
||||
NOW=$(date +%s)
|
||||
[ "$NOW" -lt "$DEADLINE" ] || return 1
|
||||
sleep "$SLEEP_SECS"
|
||||
done
|
||||
}
|
||||
|
||||
append_source() {
|
||||
dst_name="$1"
|
||||
src_path="$2"
|
||||
[ -n "$src_path" ] || return 0
|
||||
[ -f "$src_path" ] || return 0
|
||||
printf '%s\t%s\n' "$dst_name" "$src_path" >> "$SOURCE_LIST"
|
||||
}
|
||||
|
||||
append_package_extras() {
|
||||
for path in "$PACKAGE_DIR"/*; do
|
||||
[ -f "$path" ] || continue
|
||||
base="$(basename "$path")"
|
||||
case "$base" in
|
||||
pjarczak_bambu_linux_host|pjarczak_bambu_linux_host_abi1|pjarczak_bambu_linux_host_abi0|libbambu_networking.so|libBambuSource.so|linux_payload_manifest.json|ca-certificates.crt|slicer_base64.cer)
|
||||
continue
|
||||
;;
|
||||
*.dll|*.ps1|*.txt|*.tar|*.zip|*.cmd|*.bat|*.sh)
|
||||
continue
|
||||
;;
|
||||
esac
|
||||
append_source "$base" "$path"
|
||||
done
|
||||
}
|
||||
|
||||
copy_source_list() {
|
||||
while IFS="$(printf '\t')" read -r dst_name src_path; do
|
||||
[ -n "$dst_name" ] || continue
|
||||
cp "$src_path" "$TMP_DIR/$dst_name"
|
||||
done < "$SOURCE_LIST"
|
||||
}
|
||||
|
||||
compute_runtime_hash() {
|
||||
{
|
||||
while IFS="$(printf '\t')" read -r dst_name src_path; do
|
||||
[ -n "$dst_name" ] || continue
|
||||
printf '%s\n' "$dst_name"
|
||||
sha256sum "$src_path"
|
||||
done < "$SOURCE_LIST"
|
||||
} | sha256sum | cut -d ' ' -f1
|
||||
}
|
||||
|
||||
list_runtime_files() {
|
||||
find -L "$CURRENT_DIR" -maxdepth 1 -type f -printf '%f\n' | sort | tr '\n' ',' | sed 's/,$//'
|
||||
}
|
||||
|
||||
resolve_payload_sources
|
||||
if [ -z "$NETWORK_SRC" ] || [ -z "$SOURCE_SRC" ]; then
|
||||
log "plugin_not_downloaded package_dir=$PACKAGE_DIR plugin_cache_dir=${PLUGIN_CACHE_DIR:-none}"
|
||||
if [ "$MODE" = "probe" ]; then
|
||||
exit 3
|
||||
fi
|
||||
if ! wait_for_payload_sources; then
|
||||
log "plugin_not_downloaded_timeout package_dir=$PACKAGE_DIR plugin_cache_dir=${PLUGIN_CACHE_DIR:-none}"
|
||||
exit 127
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ -z "$ABI1_SRC" ] && [ -z "$ABI0_SRC" ]; then
|
||||
log "missing host ABI binaries in package_dir=$PACKAGE_DIR plugin_cache_dir=${PLUGIN_CACHE_DIR:-none}"
|
||||
exit 127
|
||||
fi
|
||||
|
||||
if ! command -v sha256sum >/dev/null 2>&1; then
|
||||
log "sha256sum not found inside WSL distro"
|
||||
exit 127
|
||||
fi
|
||||
|
||||
export HOME="${HOME:-/root}"
|
||||
export XDG_CONFIG_HOME="${XDG_CONFIG_HOME:-$HOME/.config}"
|
||||
export XDG_CACHE_HOME="${XDG_CACHE_HOME:-$HOME/.cache}"
|
||||
export XDG_STATE_HOME="${XDG_STATE_HOME:-$HOME/.local/state}"
|
||||
export XDG_DATA_HOME="${XDG_DATA_HOME:-$HOME/.local/share}"
|
||||
mkdir -p "$XDG_CONFIG_HOME" "$XDG_CACHE_HOME" "$XDG_STATE_HOME" "$XDG_DATA_HOME" "$HOME/.pjarczak-bambu-runtime"
|
||||
unset APPDATA LOCALAPPDATA USERPROFILE HOMEDRIVE HOMEPATH TEMP TMP TMPDIR
|
||||
|
||||
RUNTIME_BASE="${PJARCZAK_BAMBU_WSL_RUNTIME_DIR:-$HOME/.pjarczak-bambu-runtime}"
|
||||
mkdir -p "$RUNTIME_BASE"
|
||||
SOURCE_LIST="$(mktemp "$RUNTIME_BASE/.sources.XXXXXX")"
|
||||
trap 'rm -f "$SOURCE_LIST"' EXIT INT TERM
|
||||
|
||||
append_source "pjarczak_bambu_linux_host" "$HOST_SRC"
|
||||
append_source "libbambu_networking.so" "$NETWORK_SRC"
|
||||
append_source "libBambuSource.so" "$SOURCE_SRC"
|
||||
append_source "pjarczak_bambu_linux_host_abi1" "$ABI1_SRC"
|
||||
append_source "pjarczak_bambu_linux_host_abi0" "$ABI0_SRC"
|
||||
append_source "linux_payload_manifest.json" "$MANIFEST_SRC"
|
||||
append_source "ca-certificates.crt" "$CA_BUNDLE_SRC"
|
||||
append_source "slicer_base64.cer" "$SLICER_CERT_SRC"
|
||||
append_package_extras
|
||||
|
||||
RUNTIME_HASH="$(compute_runtime_hash)"
|
||||
TARGET_DIR="$RUNTIME_BASE/$RUNTIME_HASH"
|
||||
CURRENT_DIR="$RUNTIME_BASE/current"
|
||||
|
||||
log "mode=$MODE package_dir=$PACKAGE_DIR plugin_cache_dir=${PLUGIN_CACHE_DIR:-none} runtime_hash=$RUNTIME_HASH"
|
||||
log "wrapper_src=$HOST_SRC"
|
||||
log "network_src=${NETWORK_SRC:-missing}"
|
||||
log "source_src=${SOURCE_SRC:-missing}"
|
||||
log "abi1_src=${ABI1_SRC:-missing}"
|
||||
log "abi0_src=${ABI0_SRC:-missing}"
|
||||
log "manifest_src=${MANIFEST_SRC:-missing}"
|
||||
log "ca_bundle_src=${CA_BUNDLE_SRC:-missing}"
|
||||
log "slicer_cert_src=${SLICER_CERT_SRC:-missing}"
|
||||
|
||||
if [ ! -d "$TARGET_DIR" ]; then
|
||||
TMP_DIR="$RUNTIME_BASE/.tmp-$RUNTIME_HASH-$$"
|
||||
rm -rf "$TMP_DIR"
|
||||
mkdir -p "$TMP_DIR"
|
||||
copy_source_list
|
||||
chmod 755 "$TMP_DIR/pjarczak_bambu_linux_host" "$TMP_DIR"/pjarczak_bambu_linux_host_abi* 2>/dev/null || true
|
||||
mv "$TMP_DIR" "$TARGET_DIR"
|
||||
log "created_runtime_dir=$TARGET_DIR"
|
||||
else
|
||||
log "reusing_runtime_dir=$TARGET_DIR"
|
||||
fi
|
||||
|
||||
rm -rf "$CURRENT_DIR"
|
||||
ln -s "$TARGET_DIR" "$CURRENT_DIR"
|
||||
export PJARCZAK_BAMBU_PLUGIN_DIR="$CURRENT_DIR"
|
||||
export PJARCZAK_BAMBU_NETWORK_SO="$CURRENT_DIR/libbambu_networking.so"
|
||||
export PJARCZAK_BAMBU_SOURCE_SO="$CURRENT_DIR/libBambuSource.so"
|
||||
export LD_LIBRARY_PATH="$CURRENT_DIR${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH}"
|
||||
if [ -f "$CURRENT_DIR/ca-certificates.crt" ]; then
|
||||
export SSL_CERT_FILE="$CURRENT_DIR/ca-certificates.crt"
|
||||
export CURL_CA_BUNDLE="$CURRENT_DIR/ca-certificates.crt"
|
||||
fi
|
||||
if [ -d /etc/ssl/certs ]; then
|
||||
export SSL_CERT_DIR="/etc/ssl/certs"
|
||||
fi
|
||||
|
||||
BIN_PATH=$("$CURRENT_DIR/pjarczak_bambu_linux_host" --print-bin 2>/tmp/pjarczak-bin.txt || true)
|
||||
if [ -z "$BIN_PATH" ] || [ ! -x "$BIN_PATH" ]; then
|
||||
log "failed to resolve host binary"
|
||||
cat /tmp/pjarczak-bin.txt >&2 || true
|
||||
exit 127
|
||||
fi
|
||||
|
||||
log "selected_bin=$BIN_PATH"
|
||||
log "runtime_files=$(list_runtime_files)"
|
||||
|
||||
if command -v ldd >/dev/null 2>&1; then
|
||||
LDD_OUT="$(ldd "$BIN_PATH" 2>&1 || true)"
|
||||
if printf '%s\n' "$LDD_OUT" | grep -q 'not found'; then
|
||||
log "ldd reported missing libraries for $BIN_PATH"
|
||||
printf '%s\n' "$LDD_OUT" >&2
|
||||
exit 127
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ "$MODE" = "probe" ]; then
|
||||
echo "probe_ok runtime_dir=$CURRENT_DIR runtime_hash=$RUNTIME_HASH bin=$BIN_PATH"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
exec "$CURRENT_DIR/pjarczak_bambu_linux_host"
|
||||
245
tools/pjarczak_bambu_runtime/wsl/verify_runtime.ps1
Normal file
245
tools/pjarczak_bambu_runtime/wsl/verify_runtime.ps1
Normal file
@@ -0,0 +1,245 @@
|
||||
param(
|
||||
[string]$PackageDir = "",
|
||||
[string]$DistroName = "",
|
||||
[string]$PluginCacheDir = "",
|
||||
[switch]$AllowMissingLinuxPlugin,
|
||||
[switch]$SkipProbe
|
||||
)
|
||||
|
||||
$ErrorActionPreference = 'Stop'
|
||||
if (Get-Variable -Name PSNativeCommandUseErrorActionPreference -ErrorAction SilentlyContinue) {
|
||||
$script:__pj_prev_native_pref = $PSNativeCommandUseErrorActionPreference
|
||||
$PSNativeCommandUseErrorActionPreference = $false
|
||||
}
|
||||
|
||||
function Get-ScriptDir {
|
||||
if (-not [string]::IsNullOrWhiteSpace($PSScriptRoot)) {
|
||||
return $PSScriptRoot
|
||||
}
|
||||
if (-not [string]::IsNullOrWhiteSpace($PSCommandPath)) {
|
||||
return (Split-Path -Parent $PSCommandPath)
|
||||
}
|
||||
if ($MyInvocation.MyCommand -and -not [string]::IsNullOrWhiteSpace($MyInvocation.MyCommand.Path)) {
|
||||
return (Split-Path -Parent $MyInvocation.MyCommand.Path)
|
||||
}
|
||||
return (Get-Location).Path
|
||||
}
|
||||
|
||||
function Convert-FileToLf([string]$Path) {
|
||||
if ([string]::IsNullOrWhiteSpace($Path) -or !(Test-Path $Path)) {
|
||||
return
|
||||
}
|
||||
|
||||
$content = [System.IO.File]::ReadAllText($Path)
|
||||
$content = $content.Replace("`r`n", "`n").Replace("`r", "`n")
|
||||
$utf8NoBom = [System.Text.UTF8Encoding]::new($false)
|
||||
[System.IO.File]::WriteAllText($Path, $content, $utf8NoBom)
|
||||
}
|
||||
|
||||
function To-WslPath([string]$Path) {
|
||||
$full = [System.IO.Path]::GetFullPath($Path)
|
||||
if ($full.Length -ge 2 -and $full[1] -eq ':') {
|
||||
$drive = $full.Substring(0, 1).ToLowerInvariant()
|
||||
$tail = ($full.Substring(2) -replace '\\', '/')
|
||||
if ($tail.StartsWith('/')) {
|
||||
$tail = $tail.Substring(1)
|
||||
}
|
||||
return "/mnt/$drive/$tail"
|
||||
}
|
||||
return ($full -replace '\\', '/')
|
||||
}
|
||||
|
||||
function Read-TextAuto([string]$Path) {
|
||||
if (!(Test-Path $Path)) {
|
||||
return ''
|
||||
}
|
||||
|
||||
$bytes = [System.IO.File]::ReadAllBytes($Path)
|
||||
if ($bytes.Length -eq 0) {
|
||||
return ''
|
||||
}
|
||||
|
||||
if ($bytes.Length -ge 2 -and $bytes[0] -eq 0xFF -and $bytes[1] -eq 0xFE) {
|
||||
return ([System.Text.Encoding]::Unicode.GetString($bytes, 2, $bytes.Length - 2) -replace "`0", '')
|
||||
}
|
||||
if ($bytes.Length -ge 2 -and $bytes[0] -eq 0xFE -and $bytes[1] -eq 0xFF) {
|
||||
return ([System.Text.Encoding]::BigEndianUnicode.GetString($bytes, 2, $bytes.Length - 2) -replace "`0", '')
|
||||
}
|
||||
if ($bytes.Length -ge 3 -and $bytes[0] -eq 0xEF -and $bytes[1] -eq 0xBB -and $bytes[2] -eq 0xBF) {
|
||||
return ([System.Text.Encoding]::UTF8.GetString($bytes, 3, $bytes.Length - 3) -replace "`0", '')
|
||||
}
|
||||
|
||||
for ($i = 1; $i -lt [Math]::Min($bytes.Length, 64); $i += 2) {
|
||||
if ($bytes[$i] -eq 0) {
|
||||
return ([System.Text.Encoding]::Unicode.GetString($bytes) -replace "`0", '')
|
||||
}
|
||||
}
|
||||
|
||||
return ([System.Text.Encoding]::UTF8.GetString($bytes) -replace "`0", '')
|
||||
}
|
||||
|
||||
function Normalize-NativeText([string]$Text) {
|
||||
if ([string]::IsNullOrEmpty($Text)) {
|
||||
return ''
|
||||
}
|
||||
$value = $Text -replace "`0", ''
|
||||
$value = $value -replace "`r`n", "`n"
|
||||
$value = $value -replace "`r", "`n"
|
||||
return $value
|
||||
}
|
||||
|
||||
function Invoke-NativeCapture([string]$FilePath, [string[]]$ArgumentList) {
|
||||
$stdoutPath = [System.IO.Path]::GetTempFileName()
|
||||
$stderrPath = [System.IO.Path]::GetTempFileName()
|
||||
try {
|
||||
$proc = Start-Process -FilePath $FilePath -ArgumentList $ArgumentList -Wait -PassThru -RedirectStandardOutput $stdoutPath -RedirectStandardError $stderrPath -WindowStyle Hidden
|
||||
$stdoutText = if (Test-Path $stdoutPath) { Normalize-NativeText (Read-TextAuto $stdoutPath) } else { '' }
|
||||
$stderrText = if (Test-Path $stderrPath) { Normalize-NativeText (Read-TextAuto $stderrPath) } else { '' }
|
||||
$combined = (($stdoutText + "`n" + $stderrText).Trim())
|
||||
return @{
|
||||
ExitCode = $proc.ExitCode
|
||||
StdOut = $stdoutText
|
||||
StdErr = $stderrText
|
||||
Combined = $combined
|
||||
}
|
||||
} finally {
|
||||
Remove-Item -Force -ErrorAction SilentlyContinue $stdoutPath, $stderrPath
|
||||
}
|
||||
}
|
||||
|
||||
function Test-WslDistroExists([string]$WslPath, [string]$Name) {
|
||||
$probe = Invoke-NativeCapture $WslPath @('-d', $Name, '--user', 'root', '--', 'sh', '-lc', 'true')
|
||||
if ($probe.ExitCode -eq 0) {
|
||||
return @{
|
||||
Exists = $true
|
||||
Reason = ''
|
||||
}
|
||||
}
|
||||
|
||||
$text = $probe.Combined
|
||||
$lower = $text.ToLowerInvariant()
|
||||
|
||||
if ($lower.Contains('there is no distribution with the supplied name') -or
|
||||
$lower.Contains('wsl_e_distribution_not_found') -or
|
||||
($lower.Contains('distribution') -and $lower.Contains('not') -and $lower.Contains('found'))) {
|
||||
return @{
|
||||
Exists = $false
|
||||
Reason = "WSL distro '$Name' is not installed"
|
||||
}
|
||||
}
|
||||
|
||||
if ([string]::IsNullOrWhiteSpace($text)) {
|
||||
throw "Failed to start WSL distro '$Name'"
|
||||
}
|
||||
|
||||
throw ("Failed to start WSL distro '{0}': {1}" -f $Name, $text)
|
||||
}
|
||||
|
||||
if ([string]::IsNullOrWhiteSpace($PackageDir)) {
|
||||
$PackageDir = Get-ScriptDir
|
||||
}
|
||||
$PackageDir = [System.IO.Path]::GetFullPath($PackageDir)
|
||||
|
||||
if ([string]::IsNullOrWhiteSpace($PluginCacheDir)) {
|
||||
if ($env:PJARCZAK_BAMBU_WINDOWS_PLUGIN_CACHE_DIR) {
|
||||
$PluginCacheDir = $env:PJARCZAK_BAMBU_WINDOWS_PLUGIN_CACHE_DIR
|
||||
} else {
|
||||
$subdirFile = Join-Path $PackageDir 'pjarczak_plugin_cache_subdir.txt'
|
||||
if ((-not [string]::IsNullOrWhiteSpace($env:APPDATA)) -and (Test-Path $subdirFile)) {
|
||||
$subdir = (Get-Content $subdirFile -Raw).Trim()
|
||||
if (-not [string]::IsNullOrWhiteSpace($subdir)) {
|
||||
$PluginCacheDir = Join-Path $env:APPDATA $subdir
|
||||
}
|
||||
}
|
||||
if ([string]::IsNullOrWhiteSpace($PluginCacheDir) -and $env:APPDATA) {
|
||||
$PluginCacheDir = Join-Path $env:APPDATA 'OrcaSlicer\ota\plugins'
|
||||
}
|
||||
}
|
||||
}
|
||||
if (-not [string]::IsNullOrWhiteSpace($PluginCacheDir)) {
|
||||
$PluginCacheDir = [System.IO.Path]::GetFullPath($PluginCacheDir)
|
||||
$pluginsChild = Join-Path $PluginCacheDir 'plugins'
|
||||
if ((Split-Path -Leaf $PluginCacheDir) -ieq 'ota' -and (Test-Path $pluginsChild)) {
|
||||
$PluginCacheDir = [System.IO.Path]::GetFullPath($pluginsChild)
|
||||
} elseif ((Test-Path $pluginsChild) -and !(Test-Path (Join-Path $PluginCacheDir 'libbambu_networking.so')) -and !(Test-Path (Join-Path $PluginCacheDir 'libBambuSource.so'))) {
|
||||
$PluginCacheDir = [System.IO.Path]::GetFullPath($pluginsChild)
|
||||
}
|
||||
}
|
||||
|
||||
if ([string]::IsNullOrWhiteSpace($DistroName)) {
|
||||
$distroFile = Join-Path $PackageDir 'pjarczak_wsl_distro.txt'
|
||||
if (Test-Path $distroFile) {
|
||||
$DistroName = (Get-Content $distroFile -Raw).Trim()
|
||||
}
|
||||
}
|
||||
if ([string]::IsNullOrWhiteSpace($DistroName)) {
|
||||
throw 'Missing distro name. Set PJARCZAK_WSL_DISTRO or provide pjarczak_wsl_distro.txt.'
|
||||
}
|
||||
|
||||
$requiredFiles = @(
|
||||
'pjarczak_bambu_networking_bridge.dll',
|
||||
'pjarczak_wsl_distro.txt',
|
||||
'install_runtime.ps1',
|
||||
'verify_runtime.ps1',
|
||||
'pjarczak_bambu_linux_host',
|
||||
'pjarczak_bambu_linux_host_abi1',
|
||||
'pjarczak_bambu_linux_host_abi0',
|
||||
'windows-wsl2-rootfs.tar',
|
||||
'ca-certificates.crt',
|
||||
'slicer_base64.cer'
|
||||
)
|
||||
|
||||
foreach ($name in $requiredFiles) {
|
||||
$path = Join-Path $PackageDir $name
|
||||
if (!(Test-Path $path)) {
|
||||
throw "Missing package file: $name"
|
||||
}
|
||||
}
|
||||
|
||||
$bootstrapPath = Join-Path $PackageDir 'pjarczak_wsl_run_host.sh'
|
||||
if (!(Test-Path $bootstrapPath)) { $bootstrapPath = Join-Path $PackageDir 'pjarczak-wsl-run-host.sh' }
|
||||
if (!(Test-Path $bootstrapPath)) {
|
||||
throw 'Missing package file: pjarczak_wsl_run_host.sh'
|
||||
}
|
||||
Convert-FileToLf $bootstrapPath
|
||||
|
||||
$wsl = Join-Path $env:WINDIR 'System32\wsl.exe'
|
||||
if (!(Test-Path $wsl)) {
|
||||
throw 'wsl.exe not found'
|
||||
}
|
||||
|
||||
$distroStatus = Test-WslDistroExists $wsl $DistroName
|
||||
if (-not $distroStatus.Exists) {
|
||||
throw $distroStatus.Reason
|
||||
}
|
||||
|
||||
$packageDirWsl = To-WslPath $PackageDir
|
||||
$pluginCacheDirWsl = ""
|
||||
if (-not [string]::IsNullOrWhiteSpace($PluginCacheDir)) {
|
||||
$pluginCacheDirWsl = To-WslPath $PluginCacheDir
|
||||
}
|
||||
$bootstrapWsl = "$packageDirWsl/$([System.IO.Path]::GetFileName($bootstrapPath))"
|
||||
|
||||
Write-Host "Bridge package dir: $PackageDir"
|
||||
Write-Host "Plugin cache dir: $PluginCacheDir"
|
||||
Write-Host "WSL distro: $DistroName"
|
||||
Write-Host "Bootstrap script: $bootstrapPath"
|
||||
|
||||
if ($SkipProbe) {
|
||||
Write-Host 'WSL runtime core OK'
|
||||
exit 0
|
||||
}
|
||||
|
||||
$probe = Invoke-NativeCapture $wsl @('-d', $DistroName, '--user', 'root', '--', 'sh', $bootstrapWsl, '--probe', $packageDirWsl, $pluginCacheDirWsl)
|
||||
if ($probe.ExitCode -ne 0) {
|
||||
$probeText = $probe.Combined
|
||||
if ($AllowMissingLinuxPlugin -and $probeText -match 'plugin_not_downloaded') {
|
||||
Write-Host 'WSL runtime package OK, linux plugin not downloaded yet.'
|
||||
Write-Host $probeText
|
||||
exit 0
|
||||
}
|
||||
throw "WSL runtime probe failed: $probeText"
|
||||
}
|
||||
|
||||
Write-Host 'WSL runtime probe OK'
|
||||
Write-Host $probe.Combined
|
||||
Reference in New Issue
Block a user