mirror of
https://github.com/miyu0-bit/frameeye-helper.git
synced 2026-10-06 01:00:14 +02:00
first version
This commit is contained in:
commit
3d43bfe5ca
47 files changed
+25167
No files matched your search
@@ -0,0 +1,16 @@
|
||||
# Build environment for FrameEye Helper (Windows + Linux) and the Linux panel preview.
|
||||
# Everything is built inside this container so nothing has to be installed on the host.
|
||||
# podman build -t frameeye-build -f build/Containerfile build/
|
||||
FROM registry.fedoraproject.org/fedora:44
|
||||
RUN dnf -y install --setopt=install_weak_deps=False \
|
||||
rust cargo rust-std-static-x86_64-pc-windows-gnu \
|
||||
mingw64-gcc mingw64-binutils mingw64-winpthreads-static \
|
||||
gcc gcc-c++ cmake ninja-build pkgconf-pkg-config make \
|
||||
cairo-devel freetype-devel sdl2-compat-devel vulkan-loader-devel vulkan-headers \
|
||||
file python3 \
|
||||
&& dnf clean all
|
||||
ENV CARGO_TARGET_X86_64_PC_WINDOWS_GNU_LINKER=x86_64-w64-mingw32-gcc \
|
||||
CC_x86_64_pc_windows_gnu=x86_64-w64-mingw32-gcc \
|
||||
AR_x86_64_pc_windows_gnu=x86_64-w64-mingw32-ar \
|
||||
CARGO_HOME=/cargo-home
|
||||
WORKDIR /src
|
||||
Executable
+24
@@ -0,0 +1,24 @@
|
||||
#!/usr/bin/env bash
|
||||
# Builds FrameEye Helper for Windows (x86_64, .exe) and Linux inside the frameeye-build container,
|
||||
# runs the unit tests, and copies the results to dist/.
|
||||
# build/build-helper.sh (from the project root, or anywhere)
|
||||
set -euo pipefail
|
||||
root="$(cd "$(dirname "$0")/.." && pwd)"
|
||||
image=frameeye-build
|
||||
if ! podman image exists "$image"; then
|
||||
podman build -t "$image" -f "$root/build/Containerfile" "$root/build"
|
||||
fi
|
||||
mkdir -p "$root/build/cargo-home" "$root/dist"
|
||||
podman run --rm --userns=keep-id \
|
||||
-v "$root/helper:/src:Z" \
|
||||
-v "$root/build/cargo-home:/cargo-home:Z" \
|
||||
-e CARGO_TARGET_DIR=/src/target-container \
|
||||
"$image" bash -c '
|
||||
set -euo pipefail
|
||||
cargo test --release --locked
|
||||
cargo build --release --locked --target x86_64-unknown-linux-gnu
|
||||
cargo build --release --locked --target x86_64-pc-windows-gnu
|
||||
'
|
||||
cp "$root/helper/target-container/x86_64-pc-windows-gnu/release/FrameEyeHelper.exe" "$root/dist/FrameEyeHelper.exe"
|
||||
cp "$root/helper/target-container/x86_64-unknown-linux-gnu/release/FrameEyeHelper" "$root/dist/FrameEyeHelper-linux"
|
||||
ls -la "$root/dist"
|
||||
Executable
+26
@@ -0,0 +1,26 @@
|
||||
#!/usr/bin/env bash
|
||||
# Builds the Linux preview of the headset's Eye panel inside the frameeye-build container:
|
||||
# frameeyeosc (the headset program, for this PC), the pretend eye tracker, and the panel as a window.
|
||||
# Results go to preview/bin/.
|
||||
set -euo pipefail
|
||||
root="$(cd "$(dirname "$0")/.." && pwd)"
|
||||
image=frameeye-build
|
||||
if ! podman image exists "$image"; then
|
||||
podman build -t "$image" -f "$root/build/Containerfile" "$root/build"
|
||||
fi
|
||||
mkdir -p "$root/build/cargo-home" "$root/preview/bin"
|
||||
podman run --rm --userns=keep-id \
|
||||
-v "$root:/w:Z" \
|
||||
-v "$root/build/cargo-home:/cargo-home:Z" \
|
||||
"$image" bash -c '
|
||||
set -euo pipefail
|
||||
cd /w/upstream/frameeyeosc && cargo build --release --locked --target-dir /w/build/target-upstream
|
||||
cd /w/preview/fake-eye-server && cargo build --release --target-dir /w/build/target-fake
|
||||
cmake -G Ninja -S /w/preview/panel-desktop -B /w/build/panel-preview -DCMAKE_BUILD_TYPE=Release >/dev/null
|
||||
ninja -C /w/build/panel-preview
|
||||
'
|
||||
cp "$root/build/target-upstream/release/frameeyeosc" "$root/preview/bin/"
|
||||
cp "$root/build/target-fake/release/fake-eye-server" "$root/preview/bin/"
|
||||
cp "$root/build/panel-preview/frameeyeosc-panel-preview" "$root/preview/bin/"
|
||||
chmod +x "$root/preview/run-panel-preview.sh"
|
||||
ls -la "$root/preview/bin"
|
||||
Executable
+71
@@ -0,0 +1,71 @@
|
||||
#!/usr/bin/env bash
|
||||
# Puts the finished downloads together in dist/ (run build-helper.sh and build-preview.sh first):
|
||||
# dist/FrameEyeHelper.exe the Windows app
|
||||
# dist/FrameEyeHelper-Windows.zip the same, with a short "read me first", for sending
|
||||
# dist/linux/ the same app for Linux, plus the Eye panel preview
|
||||
# dist/FrameEyeHelper-Linux.tar.gz dist/linux/ packed up for the release page
|
||||
set -euo pipefail
|
||||
root="$(cd "$(dirname "$0")/.." && pwd)"
|
||||
dist="$root/dist"
|
||||
if [[ -f "$dist/linux/FrameEyeHelper" && ! -f "$dist/FrameEyeHelper-linux" ]]; then
|
||||
mv "$dist/linux/FrameEyeHelper" "$dist/FrameEyeHelper-linux" # packaging again
|
||||
fi
|
||||
test -f "$dist/FrameEyeHelper.exe" && test -f "$dist/FrameEyeHelper-linux" || { echo "run build/build-helper.sh first" >&2; exit 1; }
|
||||
test -x "$root/preview/bin/frameeyeosc-panel-preview" || { echo "run build/build-preview.sh first" >&2; exit 1; }
|
||||
|
||||
rm -rf "$dist/linux" "$dist/FrameEyeHelper-Windows.zip"
|
||||
mkdir -p "$dist/linux/FrameEye-Panel-Preview/bin"
|
||||
mv "$dist/FrameEyeHelper-linux" "$dist/linux/FrameEyeHelper"
|
||||
cp "$root/preview/run-panel-preview.sh" "$dist/linux/FrameEye-Panel-Preview/"
|
||||
cp "$root/preview/bin/"* "$dist/linux/FrameEye-Panel-Preview/bin/"
|
||||
cp "$root/helper/assets/FRAMEEYEOSC_LICENSE.txt" "$dist/linux/FrameEye-Panel-Preview/FRAMEEYEOSC_LICENSE.txt"
|
||||
cp "$root/upstream/frameeyeosc/THIRD_PARTY_LICENSES.md" "$dist/linux/FrameEye-Panel-Preview/FRAMEEYEOSC_THIRD_PARTY_LICENSES.md"
|
||||
cp "$root/LICENSE" "$root/THIRD_PARTY_LICENSES.md" "$dist/linux/"
|
||||
|
||||
cat > "$dist/linux/README.txt" <<'EOF'
|
||||
FrameEye Helper for Linux: the same app as FrameEyeHelper.exe, plus a preview of the headset's Eye panel.
|
||||
|
||||
FrameEyeHelper
|
||||
Double-click it (or run ./FrameEyeHelper). "Try the demo" on the first page walks through every
|
||||
step with a pretend headset. The "Open the Eye panel preview" button (Linux only) opens the
|
||||
in-headset Eye panel in a window.
|
||||
|
||||
FrameEye-Panel-Preview/run-panel-preview.sh
|
||||
The same preview from a terminal. It runs the real frameeyeosc and its Eye panel, fed by a pretend
|
||||
Steam Frame. Space (or the button at the top) closes and opens the pretend dashboard; with it closed
|
||||
you see what the headset shows, like the eye fit's dot. --reset starts over with default settings.
|
||||
|
||||
Nothing here sends anything to VRChat: the preview's frameeyeosc runs in its own empty network, and its
|
||||
settings live in a scratch folder ($XDG_RUNTIME_DIR/frameeye-preview) that is gone after logging out.
|
||||
Needs SDL2, cairo, freetype and the Noto Sans CJK fonts (all standard on Fedora).
|
||||
EOF
|
||||
|
||||
readme="$(mktemp)"
|
||||
cat > "$readme" <<'EOF'
|
||||
FrameEye Helper - Steam Frame eye tracking for VRChat
|
||||
======================================================
|
||||
|
||||
1. Double-click FrameEyeHelper.exe.
|
||||
If Windows says "Windows protected your PC", click "More info", then "Run anyway".
|
||||
(The app isn't signed by a company, so Windows doesn't know it yet. Nothing gets installed on this PC.)
|
||||
|
||||
2. Follow the 4 steps in the window:
|
||||
Prepare headset -> Connect -> Install -> Check it works
|
||||
|
||||
You only need it once. After that, eye tracking starts by itself whenever SteamVR runs on the headset.
|
||||
EOF
|
||||
python3 - "$dist/FrameEyeHelper-Windows.zip" "$dist/FrameEyeHelper.exe" "$readme" "$root/LICENSE" "$root/THIRD_PARTY_LICENSES.md" <<'EOF'
|
||||
import sys, zipfile
|
||||
out, exe, readme, license_file, third_party = sys.argv[1:6]
|
||||
crlf = lambda path: open(path, encoding="utf-8").read().replace("\n", "\r\n")
|
||||
with zipfile.ZipFile(out, "w", zipfile.ZIP_DEFLATED, compresslevel=9) as z:
|
||||
z.write(exe, "FrameEyeHelper/FrameEyeHelper.exe")
|
||||
z.writestr("FrameEyeHelper/READ ME FIRST.txt", crlf(readme))
|
||||
z.writestr("FrameEyeHelper/LICENSE.txt", crlf(license_file))
|
||||
z.writestr("FrameEyeHelper/THIRD_PARTY_LICENSES.md", crlf(third_party))
|
||||
EOF
|
||||
rm -f "$readme"
|
||||
rm -f "$dist/FrameEyeHelper-Linux.tar.gz"
|
||||
tar -C "$dist" --transform 's,^linux,FrameEyeHelper-Linux,' -czf "$dist/FrameEyeHelper-Linux.tar.gz" linux
|
||||
(cd "$dist" && sha256sum FrameEyeHelper-Windows.zip FrameEyeHelper-Linux.tar.gz FrameEyeHelper.exe > SHA256SUMS)
|
||||
find "$dist" -type f -printf '%10s %P\n' | sort -k2
|
||||
@@ -0,0 +1,100 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Writes THIRD_PARTY_LICENSES.md: the licenses of the Rust crates built into FrameEyeHelper (Windows and
|
||||
Linux) and the preview's fake-eye-server. Crates with the same license text are listed together.
|
||||
|
||||
CARGO_HOME=build/cargo-home python3 build/third-party-licenses.py > THIRD_PARTY_LICENSES.md
|
||||
"""
|
||||
import hashlib
|
||||
import json
|
||||
import os
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
||||
PROJECTS = [
|
||||
("helper", ["x86_64-pc-windows-gnu", "x86_64-unknown-linux-gnu"]),
|
||||
("preview/fake-eye-server", ["x86_64-unknown-linux-gnu"]),
|
||||
]
|
||||
LICENSE_NAMES = ("license", "licence", "copying", "notice", "unlicense")
|
||||
|
||||
|
||||
def linked_packages(project, target):
|
||||
"""Packages reachable from the project through normal dependencies (build scripts' own deps are left out)."""
|
||||
out = subprocess.run(
|
||||
["cargo", "metadata", "--format-version", "1", "--filter-platform", target],
|
||||
cwd=os.path.join(ROOT, project), check=True, capture_output=True, text=True,
|
||||
).stdout
|
||||
meta = json.loads(out)
|
||||
packages = {p["id"]: p for p in meta["packages"]}
|
||||
nodes = {n["id"]: n for n in meta["resolve"]["nodes"]}
|
||||
root = meta["resolve"]["root"]
|
||||
seen, stack = set(), [root]
|
||||
while stack:
|
||||
node = nodes[stack.pop()]
|
||||
for dep in node["deps"]:
|
||||
if any(kind["kind"] is None for kind in dep["dep_kinds"]) and dep["pkg"] not in seen:
|
||||
seen.add(dep["pkg"])
|
||||
stack.append(dep["pkg"])
|
||||
return [packages[i] for i in seen]
|
||||
|
||||
|
||||
def license_files(package):
|
||||
folder = os.path.dirname(package["manifest_path"])
|
||||
candidates = [(name, os.path.join(folder, name)) for name in sorted(os.listdir(folder))]
|
||||
# egui's font crate keeps the licenses of the fonts it embeds next to them
|
||||
fonts = os.path.join(folder, "fonts")
|
||||
if os.path.isdir(fonts):
|
||||
candidates += [(f"fonts/{name}", os.path.join(fonts, name)) for name in sorted(os.listdir(fonts)) if name.endswith(".txt")]
|
||||
found = []
|
||||
for name, path in candidates:
|
||||
base = os.path.basename(name).lower()
|
||||
if os.path.isfile(path) and (base.startswith(LICENSE_NAMES) or name.startswith("fonts/")):
|
||||
with open(path, encoding="utf-8", errors="replace") as f:
|
||||
found.append((name, f.read().strip()))
|
||||
return found
|
||||
|
||||
|
||||
def main():
|
||||
crates = {}
|
||||
for project, targets in PROJECTS:
|
||||
for target in targets:
|
||||
for package in linked_packages(project, target):
|
||||
if package["source"] is None: # our own crates
|
||||
continue
|
||||
crates[(package["name"], package["version"])] = package
|
||||
groups = {} # text hash -> (text, [crate labels])
|
||||
no_file = []
|
||||
for (name, version), package in sorted(crates.items()):
|
||||
label = f"{name} {version}"
|
||||
files = license_files(package)
|
||||
if not files:
|
||||
authors = ", ".join(package.get("authors") or []) or "its authors"
|
||||
source = package.get("repository") or package.get("homepage") or ""
|
||||
no_file.append(f"{label}: {package.get('license') or 'no license field'}, (c) {authors} {source}".rstrip())
|
||||
continue
|
||||
for filename, text in files:
|
||||
key = hashlib.sha256(text.encode()).hexdigest()
|
||||
groups.setdefault(key, (filename, text, []))[2].append(label)
|
||||
|
||||
print("# Third-party licenses\n")
|
||||
print("FrameEye Helper is MIT licensed (see LICENSE). Its binaries contain the Rust crates below; each")
|
||||
print("crate's license text follows, crates with the same text grouped together.\n")
|
||||
print("frameeyeosc itself (bundled in the helper, and built into the Linux preview) is MIT, (c) konsti219 and")
|
||||
print("sasaken1102r; its own third-party licenses ship inside its release and in its repository.\n")
|
||||
print(f"{len(crates)} crates.\n")
|
||||
for filename, text, labels in sorted(groups.values(), key=lambda g: g[2][0]):
|
||||
print("---\n")
|
||||
print(f"**{', '.join(labels)}** ({filename})\n")
|
||||
print("```")
|
||||
print(text.replace("```", "'''"))
|
||||
print("```\n")
|
||||
if no_file:
|
||||
print("---\n")
|
||||
print("These crates publish no license file; their license comes from their manifest. The standard")
|
||||
print("texts (MIT, Apache-2.0, ...) appear above with other crates, and at https://spdx.org/licenses/.\n")
|
||||
for label in no_file:
|
||||
print(f"- {label}")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(main())
|
||||
Reference in new issue
Block a user