mirror of
https://github.com/vrc-get/vrc-get.git
synced 2026-06-21 09:58:08 +00:00
Compare commits
38 commits
copilot/mi
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9a1044df51 |
||
|
|
e71c48141b |
||
|
|
467434903a | ||
|
|
ba8606d312 | ||
|
|
ed42cdfca4 | ||
|
|
dbd479fbc9 |
||
|
|
db54f0c8ae |
||
|
|
da419a0374 |
||
|
|
8351270552 |
||
|
|
50fccc9a50 |
||
|
|
cf7075a6d5 |
||
|
|
5e4709209f |
||
|
|
269cb8aeda |
||
|
|
ba9ad1f59c |
||
|
|
23b1bb2515 |
||
|
|
2c36473e6e | ||
|
|
791e50d94f | ||
|
|
a77ab4a0a3 |
||
|
|
aa14673468 |
||
|
|
36aa59b304 |
||
|
|
b61c44c64a |
||
|
|
0a5ab490b8 |
||
|
|
cfc1b627eb |
||
|
|
1b2065afe0 |
||
|
|
4634c42410 |
||
|
|
fd8b735ac9 |
||
|
|
580c8da047 |
||
|
|
0ebfb25263 |
||
|
|
9eaf99b3d1 |
||
|
|
87753ceffa |
||
|
|
0fa954cef0 |
||
|
|
41e25d4e86 |
||
|
|
3c499f9d6a |
||
|
|
65e37ff7af |
||
|
|
48e1866ff3 |
||
|
|
968ae63a4c |
||
|
|
805be35ac6 |
||
|
|
901368c9bf |
45 changed files with 1164 additions and 5703 deletions
191
.github/workflows/ci-gui.yml
vendored
191
.github/workflows/ci-gui.yml
vendored
|
|
@ -16,7 +16,7 @@ jobs:
|
|||
include:
|
||||
- triple: x86_64-unknown-linux-gnu
|
||||
on: ubuntu-22.04
|
||||
bundles: appimage,appimage-updater,deb,rpm
|
||||
bundles: appimage,appimage-updater
|
||||
setup: |
|
||||
sudo apt update && sudo apt install -y lld
|
||||
ld.lld --version
|
||||
|
|
@ -122,6 +122,195 @@ jobs:
|
|||
target/${{ matrix.triple }}/release/bundle/*/ALCOM*
|
||||
target/${{ matrix.triple }}/release/bundle/*/alcom*
|
||||
|
||||
build-rpm:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- install_rust: false
|
||||
- no_dist: false
|
||||
- mock-env: fedora-40-x86_64
|
||||
install_rust: true
|
||||
no_dist: true
|
||||
mock-env:
|
||||
- fedora-40-x86_64
|
||||
- fedora-rawhide-x86_64
|
||||
runs-on: ubuntu-latest
|
||||
container:
|
||||
image: 'fedora:latest'
|
||||
options: --privileged
|
||||
env:
|
||||
MOCK_ENV: ${{ matrix.mock-env }}
|
||||
RPMBUILD_OPTS: ${{ case(matrix.no_dist, '-D "dist %{nil}"', '') }} ${{ case(matrix.install_rust, '-D "install_rust 1"', '') }}
|
||||
steps:
|
||||
- name: Install CI dependencies
|
||||
run: dnf install -y git tar curl
|
||||
|
||||
- uses: actions/checkout@v6
|
||||
with:
|
||||
submodules: recursive
|
||||
# https://github.com/actions/checkout/issues/1169
|
||||
- run: git config --system --add safe.directory $GITHUB_WORKSPACE
|
||||
- name: install dependencies
|
||||
run: dnf install -y mock rpmbuild
|
||||
- name: prepare rpm build environment
|
||||
run: mkdir -p ~/rpmbuild/{BUILD,RPMS,SOURCES,SPECS,SRPMS}
|
||||
- name: update version name in spec file
|
||||
run: |
|
||||
COMMIT_HASH="$(git rev-parse HEAD)"
|
||||
SHORT_HASH="$(git rev-parse --short HEAD)"
|
||||
PKG_VERSION="$(<vrc-get-gui/Cargo.toml sed -En -e '/^version/{s/.*"(.*)".*/\1/p;}')+${SHORT_HASH}"
|
||||
|
||||
echo "PKG_VERSION=$PKG_VERSION" >> $GITHUB_ENV
|
||||
|
||||
cp vrc-get-gui/Cargo.toml vrc-get-gui/Cargo.toml.bak
|
||||
sed -E "/^version/s/\"$/+$(git rev-parse --short HEAD)\"/" < vrc-get-gui/Cargo.toml.bak > vrc-get-gui/Cargo.toml
|
||||
rm vrc-get-gui/Cargo.toml.bak
|
||||
git add vrc-get-gui/Cargo.toml
|
||||
|
||||
sed -i vrc-get-gui/bundle/alcom.spec -e "/^Version:/c\Version: ${PKG_VERSION//-/\~}"
|
||||
- name: build source rpm package
|
||||
run: |
|
||||
git archive --format=tar --prefix=vrc-get-gui-v$PKG_VERSION/ $(git write-tree) | gzip > ~/rpmbuild/SOURCES/gui-v$PKG_VERSION.tar.gz
|
||||
eval "rpmbuild -bs vrc-get-gui/bundle/alcom.spec $RPMBUILD_OPTS"
|
||||
- name: build rpm package
|
||||
run: eval "mock -v -r '$(ls -1 /etc/mock{/eol,}/$MOCK_ENV.cfg 2>/dev/null)' --enable-network $RPMBUILD_OPTS rebuild ~/rpmbuild/SRPMS/alcom-${PKG_VERSION//-/\~}-1*.src.rpm"
|
||||
- name: copy built binaries
|
||||
run: |
|
||||
mkdir -p artifacts
|
||||
cp ~/rpmbuild/SRPMS/alcom-${PKG_VERSION//-/\~}-1*.src.rpm artifacts/
|
||||
cp /var/lib/mock/$MOCK_ENV/result/alcom-${PKG_VERSION//-/\~}-1*.${MOCK_ENV##*-}.rpm artifacts/
|
||||
|
||||
- name: Upload built binary
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: rpm-${{ matrix.mock-env }}
|
||||
path: artifacts/*
|
||||
|
||||
build-deb:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- install_rust: false
|
||||
- install_nodejs: false
|
||||
- apt-components: main
|
||||
- apt-with-updates: false
|
||||
|
||||
# Old distributions have older tools than we need. Download tools in build process
|
||||
- pbuilder-distribution: bookworm
|
||||
install_rust: true
|
||||
install_nodejs: true
|
||||
- pbuilder-distribution: jammy
|
||||
install_rust: true
|
||||
install_nodejs: true
|
||||
|
||||
# Debian uses mirror from debian-archive.trafficmanager.net which is managed by microsoft on azure
|
||||
- pbuilder-distribution: bookworm
|
||||
mirror: http://debian-archive.trafficmanager.net/debian/
|
||||
keyring: /usr/share/keyrings/debian-archive-keyring.gpg
|
||||
- pbuilder-distribution: sid
|
||||
mirror: http://debian-archive.trafficmanager.net/debian/
|
||||
keyring: /usr/share/keyrings/debian-archive-keyring.gpg
|
||||
# Ubuntu legacy release
|
||||
- pbuilder-distribution: jammy
|
||||
mirror: http://archive.ubuntu.com/ubuntu/
|
||||
apt-components: main universe
|
||||
apt-with-updates: true
|
||||
keyring: /usr/share/keyrings/ubuntu-archive-keyring.gpg
|
||||
# For note,
|
||||
# bookworm: libc6@2.36
|
||||
# sid: libc6@2.39 as of 2026/06/14
|
||||
# jammy: libc6@2.35
|
||||
pbuilder-distribution:
|
||||
# debian distribution
|
||||
- bookworm
|
||||
- sid
|
||||
# ubuntu distribution
|
||||
- jammy # jammy is the oldest ubuntu release with libwebkit2gtk-4.1 >= 2.41 (but requires -updates and universe)
|
||||
target-arch:
|
||||
- amd64
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
TARGET_ARCH: ${{ matrix.target-arch }}
|
||||
PBUILDER_DISTRIBUTION: ${{ matrix.pbuilder-distribution }}
|
||||
PBUILDER_MIRROR: ${{ matrix.mirror }}
|
||||
PBUILDER_KEYRING: ${{ matrix.keyring }}
|
||||
PBUILDER_COMPONENTS: ${{ matrix.apt-components }}
|
||||
PBUILDER_OTHERMIRROR: ${{ case(matrix.apt-with-updates, format('deb {0} {1}-updates {2}', matrix.mirror, matrix.pbuilder-distribution, matrix.apt-components), '') }}
|
||||
INSTALL_RUST: ${{ case(matrix.install_rust, '1', '0') }}
|
||||
INSTALL_NODEJS: ${{ case(matrix.install_nodejs, '1', '0') }}
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
with:
|
||||
path: vrc-get
|
||||
submodules: recursive
|
||||
- name: install dependencies
|
||||
run: sudo apt update && sudo apt install -y pbuilder debian-archive-keyring debhelper-compat=13
|
||||
- name: prepare deb build environment
|
||||
working-directory: vrc-get
|
||||
run: |
|
||||
cp -r vrc-get-gui/bundle/debian debian
|
||||
sudo pbuilder create \
|
||||
--architecture "$TARGET_ARCH" \
|
||||
--keyring "$PBUILDER_KEYRING" \
|
||||
--mirror "$PBUILDER_MIRROR" \
|
||||
--distribution "$PBUILDER_DISTRIBUTION" \
|
||||
--components "$PBUILDER_COMPONENTS" \
|
||||
--othermirror "$PBUILDER_OTHERMIRROR"
|
||||
- name: update changelog
|
||||
working-directory: vrc-get
|
||||
run: |
|
||||
COMMIT_HASH="$(git rev-parse HEAD)"
|
||||
SHORT_HASH="$(git rev-parse --short HEAD)"
|
||||
PKG_VERSION="$(<vrc-get-gui/Cargo.toml sed -En -e '/^version/{s/.*"(.*)".*/\1/p;}')+${SHORT_HASH}"
|
||||
|
||||
echo "PKG_VERSION=$PKG_VERSION" >> $GITHUB_ENV
|
||||
|
||||
cp debian/changelog debian/changelog.bak
|
||||
cat - debian/changelog.bak <<CHANGELOG > debian/changelog
|
||||
alcom (${PKG_VERSION//-/\~}-1) experimental;
|
||||
|
||||
* Upgraded version to ${PKG_VERSION}
|
||||
|
||||
-- anatawa12 <i@anatawa12.com> $(date -u +"%a, %d %b %Y %H:%M:%S +0000")
|
||||
|
||||
CHANGELOG
|
||||
rm debian/changelog.bak
|
||||
|
||||
cp vrc-get-gui/Cargo.toml vrc-get-gui/Cargo.toml.bak
|
||||
sed -E "/^version/s/\"$/+$(git rev-parse --short HEAD)\"/" < vrc-get-gui/Cargo.toml.bak > vrc-get-gui/Cargo.toml
|
||||
rm vrc-get-gui/Cargo.toml.bak
|
||||
git add vrc-get-gui/Cargo.toml
|
||||
|
||||
echo cat debian/changelog
|
||||
cat debian/changelog
|
||||
dpkg-parsechangelog
|
||||
- name: build source deb package
|
||||
working-directory: vrc-get
|
||||
run: |
|
||||
git archive --format=tar $(git write-tree) | xz > ../alcom_${PKG_VERSION//-/\~}.orig.tar.xz
|
||||
dpkg-buildpackage -d -S
|
||||
- name: build deb package
|
||||
working-directory: vrc-get
|
||||
run: |
|
||||
sudo --preserve-env=INSTALL_RUST,INSTALL_NODEJS pbuilder build --use-network yes ../alcom_${PKG_VERSION//-/\~}-1.dsc
|
||||
- name: copy built binaries
|
||||
run: |
|
||||
mkdir -p artifacts
|
||||
cp vrc-get/debian/changelog artifacts/
|
||||
cp /var/cache/pbuilder/result/alcom_${PKG_VERSION//-/\~}* artifacts/
|
||||
ls artifacts
|
||||
- name: Print information about built package
|
||||
run: dpkg-deb -I artifacts/alcom_${PKG_VERSION//-/\~}-1_$TARGET_ARCH.deb
|
||||
|
||||
- name: Upload built binary
|
||||
if: ${{ !cancelled() }}
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: deb-${{ matrix.pbuilder-distribution }}-${{ matrix.target-arch }}
|
||||
path: artifacts/*
|
||||
|
||||
conclude-gui:
|
||||
runs-on: ubuntu-latest
|
||||
if: ${{ always() }}
|
||||
|
|
|
|||
179
.github/workflows/publish-gui.yml
vendored
179
.github/workflows/publish-gui.yml
vendored
|
|
@ -67,6 +67,21 @@ jobs:
|
|||
;;
|
||||
esac
|
||||
|
||||
GUI_VERSION="$(get-version -t gui)"
|
||||
# update debian package
|
||||
cp vrc-get-gui/bundle/debian/changelog vrc-get-gui/bundle/debian/changelog.bak
|
||||
cat - vrc-get-gui/bundle/debian/changelog.bak <<CHANGELOG > vrc-get-gui/bundle/debian/changelog
|
||||
alcom (${GUI_VERSION//-/\~}-1) stable;
|
||||
|
||||
* Upgraded version to ${GUI_VERSION}
|
||||
|
||||
-- anatawa12 <i@anatawa12.com> $(date -u +"%a, %d %b %Y %H:%M:%S +0000")
|
||||
|
||||
CHANGELOG
|
||||
rm vrc-get-gui/bundle/debian/changelog.bak
|
||||
# update rpm package
|
||||
sed -i vrc-get-gui/bundle/alcom.spec -e "/^Version:/c\Version: ${GUI_VERSION//-/\~}"
|
||||
|
||||
case "$GITHUB_REF_NAME" in
|
||||
master | master-* )
|
||||
echo "head is master or master-*"
|
||||
|
|
@ -81,7 +96,7 @@ jobs:
|
|||
;;
|
||||
esac
|
||||
|
||||
gh-export-variable GUI_VERSION "$(get-version -t gui)"
|
||||
gh-export-variable GUI_VERSION "${GUI_VERSION}"
|
||||
env:
|
||||
RELEASE_KIND_IN: ${{ inputs.release_kind }}
|
||||
DRY_RUN: ${{ inputs.dry-run }}
|
||||
|
|
@ -152,21 +167,6 @@ jobs:
|
|||
bundle/appimage/ALCOM_${GUI_VERSION}_x86_64.AppImage.tar.gz:alcom-${GUI_VERSION}-x86_64.AppImage.tar.gz
|
||||
bundle/appimage/ALCOM_${GUI_VERSION}_x86_64.AppImage.tar.gz.sig:alcom-${GUI_VERSION}-x86_64.AppImage.tar.gz.sig
|
||||
|
||||
- name: x86_64-linux-package
|
||||
triple: x86_64-unknown-linux-gnu
|
||||
on: ubuntu-22.04
|
||||
setup: |
|
||||
sudo apt update && sudo apt install -y lld
|
||||
ld.lld --version
|
||||
|
||||
sudo apt-get install -y libgtk-3-dev libwebkit2gtk-4.1-dev libappindicator3-dev librsvg2-dev patchelf
|
||||
rustflags: "-C link-arg=-fuse-ld=lld"
|
||||
alcom-build-options: --no-self-updater --updater-instruction-message "en=You can download newer package from official website."
|
||||
last-bundles: deb,rpm
|
||||
dist-path: |
|
||||
bundle/deb/alcom_${GUI_VERSION}-1_amd64.deb:alcom_${GUI_VERSION}-1_amd64.deb
|
||||
bundle/rpm/alcom-${GUI_VERSION}-1.x86_64.rpm:alcom-${GUI_VERSION}-1.x86_64.rpm
|
||||
|
||||
- name: x86_64-windows-all
|
||||
triple: x86_64-pc-windows-msvc
|
||||
on: windows-2022
|
||||
|
|
@ -196,8 +196,6 @@ jobs:
|
|||
name:
|
||||
- x86_64-linux-appimage
|
||||
#- aarch64-unknown-linux-musl
|
||||
- x86_64-linux-package
|
||||
#- aarch64-linux-package
|
||||
- x86_64-windows-all
|
||||
#- aarch64-windows-all
|
||||
- universal-macos-all
|
||||
|
|
@ -311,6 +309,149 @@ jobs:
|
|||
name: artifacts-${{ matrix.name }}
|
||||
path: artifacts/*
|
||||
|
||||
build-rpm:
|
||||
needs: [ pre-build ]
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- install_rust: false
|
||||
- no_dist: false
|
||||
- mock-env: fedora-40-x86_64
|
||||
install_rust: true
|
||||
no_dist: true
|
||||
mock-env:
|
||||
- fedora-40-x86_64
|
||||
runs-on: ubuntu-latest
|
||||
container:
|
||||
image: 'fedora:latest'
|
||||
options: --privileged
|
||||
env:
|
||||
MOCK_ENV: ${{ matrix.mock-env }}
|
||||
RPMBUILD_OPTS: ${{ case(matrix.no_dist, '-D "dist %{nil}"', '') }} ${{ case(matrix.install_rust, '-D "install_rust 1"', '') }}
|
||||
|
||||
PKG_VERSION: ${{ needs.pre-build.outputs.gui-version }}
|
||||
steps:
|
||||
- name: Install CI dependencies
|
||||
run: dnf install -y git tar curl
|
||||
|
||||
- uses: actions/checkout@v6
|
||||
with:
|
||||
ref: 'releasing'
|
||||
submodules: recursive
|
||||
# https://github.com/actions/checkout/issues/1169
|
||||
- run: git config --system --add safe.directory $GITHUB_WORKSPACE
|
||||
- name: install dependencies
|
||||
run: dnf install -y mock rpmbuild
|
||||
- name: prepare rpm build environment
|
||||
run: mkdir -p ~/rpmbuild/{BUILD,RPMS,SOURCES,SPECS,SRPMS}
|
||||
- name: build source rpm package
|
||||
run: |
|
||||
git archive --format=tar --prefix=vrc-get-gui-v$PKG_VERSION/ $(git write-tree) | gzip > ~/rpmbuild/SOURCES/gui-v$PKG_VERSION.tar.gz
|
||||
eval "rpmbuild -bs vrc-get-gui/bundle/alcom.spec $RPMBUILD_OPTS"
|
||||
- name: build rpm package
|
||||
run: eval "mock -v -r '$(ls -1 /etc/mock{/eol,}/$MOCK_ENV.cfg 2>/dev/null)' --enable-network $RPMBUILD_OPTS rebuild ~/rpmbuild/SRPMS/alcom-${PKG_VERSION//-/\~}-1*.src.rpm"
|
||||
- name: copy built binaries
|
||||
run: |
|
||||
mkdir -p artifacts
|
||||
cp ~/rpmbuild/SRPMS/alcom-${PKG_VERSION//-/\~}-1*.src.rpm artifacts/
|
||||
cp /var/lib/mock/$MOCK_ENV/result/alcom-${PKG_VERSION//-/\~}-1*.${MOCK_ENV##*-}.rpm artifacts/
|
||||
|
||||
- name: Upload built binary
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: artifacts-rpm-${{ matrix.mock-env }}
|
||||
path: artifacts/*
|
||||
|
||||
build-deb:
|
||||
needs: [ pre-build ]
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- install_rust: false
|
||||
- install_nodejs: false
|
||||
- apt-components: main
|
||||
- apt-with-updates: false
|
||||
|
||||
# Old distributions have older tools than we need. Download tools in build process
|
||||
- pbuilder-distribution: jammy
|
||||
install_rust: true
|
||||
install_nodejs: true
|
||||
|
||||
# Debian uses mirror from debian-archive.trafficmanager.net which is managed by microsoft on azure
|
||||
- pbuilder-distribution: jammy
|
||||
mirror: http://archive.ubuntu.com/ubuntu/
|
||||
apt-components: main universe
|
||||
apt-with-updates: true
|
||||
keyring: /usr/share/keyrings/ubuntu-archive-keyring.gpg
|
||||
# We build on jammy since it's the distribution with a) libwebkit2gtk-4.1 >= 2.41 and 2) oldest libc version required.
|
||||
# bookworm: libc6@2.36
|
||||
# sid: libc6@2.39 as of 2026/06/14
|
||||
# jammy: libc6@2.35
|
||||
pbuilder-distribution:
|
||||
- jammy # jammy is the oldest ubuntu release with libwebkit2gtk-4.1 >= 2.41 (but requires -updates and universe)
|
||||
target-arch:
|
||||
- amd64
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
TARGET_ARCH: ${{ matrix.target-arch }}
|
||||
PBUILDER_DISTRIBUTION: ${{ matrix.pbuilder-distribution }}
|
||||
PBUILDER_MIRROR: ${{ matrix.mirror }}
|
||||
PBUILDER_KEYRING: ${{ matrix.keyring }}
|
||||
PBUILDER_COMPONENTS: ${{ matrix.apt-components }}
|
||||
PBUILDER_OTHERMIRROR: ${{ case(matrix.apt-with-updates, format('deb {0} {1}-updates {2}', matrix.mirror, matrix.pbuilder-distribution, matrix.apt-components), '') }}
|
||||
INSTALL_RUST: ${{ case(matrix.install_rust, '1', '0') }}
|
||||
INSTALL_NODEJS: ${{ case(matrix.install_nodejs, '1', '0') }}
|
||||
|
||||
PKG_VERSION: ${{ needs.pre-build.outputs.gui-version }}
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
with:
|
||||
ref: 'releasing'
|
||||
path: vrc-get
|
||||
submodules: recursive
|
||||
- name: install dependencies
|
||||
run: sudo apt update && sudo apt install -y pbuilder debian-archive-keyring debhelper-compat=13
|
||||
- name: prepare deb build environment
|
||||
working-directory: vrc-get
|
||||
run: |
|
||||
( mkdir debian && cd debian && ln -s ../vrc-get-gui/bundle/debian/* . )
|
||||
sudo pbuilder create \
|
||||
--architecture "$TARGET_ARCH" \
|
||||
--keyring "$PBUILDER_KEYRING" \
|
||||
--mirror "$PBUILDER_MIRROR" \
|
||||
--distribution "$PBUILDER_DISTRIBUTION" \
|
||||
--components "$PBUILDER_COMPONENTS" \
|
||||
--othermirror "$PBUILDER_OTHERMIRROR"
|
||||
- name: build source deb package
|
||||
working-directory: vrc-get
|
||||
run: |
|
||||
git archive --format=tar HEAD | xz > ../alcom_${PKG_VERSION//-/\~}.orig.tar.xz
|
||||
dpkg-buildpackage -d -S
|
||||
- name: build deb package
|
||||
working-directory: vrc-get
|
||||
run: |
|
||||
sudo --preserve-env=INSTALL_RUST,INSTALL_NODEJS pbuilder build --use-network yes ../alcom_${PKG_VERSION//-/\~}-1.dsc
|
||||
- name: copy built binaries
|
||||
run: |
|
||||
mkdir -p artifacts
|
||||
cp /var/cache/pbuilder/result/alcom_${PKG_VERSION//-/\~}-1_$TARGET_ARCH.deb artifacts/
|
||||
cp /var/cache/pbuilder/result/alcom_${PKG_VERSION//-/\~}-1_$TARGET_ARCH.buildinfo artifacts/
|
||||
cp /var/cache/pbuilder/result/alcom_${PKG_VERSION//-/\~}-1_$TARGET_ARCH.changes artifacts/
|
||||
cp /var/cache/pbuilder/result/alcom_${PKG_VERSION//-/\~}-1.debian.tar.xz artifacts/
|
||||
cp /var/cache/pbuilder/result/alcom_${PKG_VERSION//-/\~}-1.dsc artifacts/
|
||||
ls artifacts
|
||||
- name: Print information about built package
|
||||
run: dpkg-deb -I artifacts/alcom_${PKG_VERSION//-/\~}-1_$TARGET_ARCH.deb
|
||||
|
||||
- name: Upload built binary
|
||||
if: ${{ !cancelled() }}
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: artifacts-deb-${{ matrix.pbuilder-distribution }}-${{ matrix.target-arch }}
|
||||
path: artifacts/*
|
||||
|
||||
build-updater-json:
|
||||
runs-on: ubuntu-latest
|
||||
needs: [ pre-build, build-rust ]
|
||||
|
|
@ -347,7 +488,7 @@ jobs:
|
|||
permissions:
|
||||
contents: write
|
||||
runs-on: ubuntu-latest
|
||||
needs: [ pre-build, build-rust, build-updater-json ]
|
||||
needs: [ pre-build, build-rust, build-rpm, build-deb, build-updater-json ]
|
||||
env:
|
||||
GUI_VERSION: ${{ needs.pre-build.outputs.gui-version }}
|
||||
steps:
|
||||
|
|
|
|||
|
|
@ -8,63 +8,73 @@ The format is based on [Keep a Changelog].
|
|||
|
||||
## [Unreleased]
|
||||
### Added
|
||||
- The package list can show hidden packages. `#2731`
|
||||
- Build-time option to disable auto updater `#2759`
|
||||
- Please read README for new build instruction.
|
||||
- User repositories can now be reordered by drag and drop `#2935`
|
||||
- Implement project sorting by creation date `#2941`
|
||||
|
||||
### Changed
|
||||
- The "Clear Selection" button in the package management screen is now red (destructive style) to distinguish it from the "Install Selected" button [`#2803`](https://github.com/vrc-get/vrc-get/pull/2803)
|
||||
- File filled with '\0' or whitespace will be treated as empty file `#2710`
|
||||
- This should prevent `syntax error loading settings.json: expected value at line 1 column 1` if settings.json is broken
|
||||
- We also added a backup file to recover from settings.json corruption `#2933`
|
||||
- Completely changed how do we build ALCOM and how do we self-update ALCOM `#2759` `#2828` `#2881` `#2882` `#2885`
|
||||
- This fixes few problems relates to auto update
|
||||
- Please read README for new build instruction.
|
||||
- Improved backup speed by parallelizing the process [`#2746`](https://github.com/vrc-get/vrc-get/pull/2746)
|
||||
- Along with this change, the default compression level has been changed to `zip-fast`
|
||||
- We added dialog on enabling "Show Prerelease Packages" `#2795`
|
||||
- I hope this prevents users unexpectedly adding prerelease packages
|
||||
- Path for unitypackage on Template Editor now can be reselected `#2635`
|
||||
- ALCOM now refuses launching project if project is on noexec mount points `#2814`
|
||||
- This would cause problems with several native plugins
|
||||
- Already-added packages are now excluded from the package name suggestions in the Template Editor `#2828`
|
||||
- Extended some timeouts to 1 minute `#2826`
|
||||
- Prevents timeouts in slow DNS environments
|
||||
- Improved robustness for package installation errors `#2844`
|
||||
- It is now unlikely that vrc-get will leave the project directory corrupted if an I/O error occurs while installing a package
|
||||
- Backslashes in path in zip file are now treated as path separator on unix `#2845`
|
||||
- This fixes problem with Gesture Manager 3.9.7
|
||||
- Empty string for `documentationUrl` and `changelogUrl` are now allowed and ignored `#2930`
|
||||
- They are formerly rejected as invalid url
|
||||
|
||||
### Deprecated
|
||||
|
||||
### Removed
|
||||
|
||||
### Fixed
|
||||
|
||||
### Security
|
||||
|
||||
## [1.1.6] - 2026-06-02
|
||||
### Added
|
||||
- The package list can show hidden packages. [`#2731`](https://github.com/vrc-get/vrc-get/pull/2731)
|
||||
- Build-time option to disable auto updater [`#2759`](https://github.com/vrc-get/vrc-get/pull/2759)
|
||||
- Please read README for new build instruction.
|
||||
- User repositories can now be reordered by drag and drop [`#2935`](https://github.com/vrc-get/vrc-get/pull/2935)
|
||||
|
||||
### Changed
|
||||
- The "Clear Selection" button in the package management screen is now red (destructive style) to distinguish it from the "Install Selected" button [`#2803`](https://github.com/vrc-get/vrc-get/pull/2803)
|
||||
- File filled with '\0' or whitespace will be treated as empty file [`#2710`](https://github.com/vrc-get/vrc-get/pull/2710)
|
||||
- This should prevent `syntax error loading settings.json: expected value at line 1 column 1` if settings.json is broken
|
||||
- We also added a backup file to recover from settings.json corruption [`#2933`](https://github.com/vrc-get/vrc-get/pull/2933)
|
||||
- Completely changed how do we build ALCOM and how do we self-update ALCOM [`#2759`](https://github.com/vrc-get/vrc-get/pull/2759) [`#2828`](https://github.com/vrc-get/vrc-get/pull/2828) [`#2881`](https://github.com/vrc-get/vrc-get/pull/2881) [`#2882`](https://github.com/vrc-get/vrc-get/pull/2882) [`#2885`](https://github.com/vrc-get/vrc-get/pull/2885)
|
||||
- This fixes few problems relates to auto update
|
||||
- Please read README for new build instruction.
|
||||
- Improved backup speed by parallelizing the process [`#2746`](https://github.com/vrc-get/vrc-get/pull/2746)
|
||||
- Along with this change, the default compression level has been changed to `zip-fast`
|
||||
- We added dialog on enabling "Show Prerelease Packages" [`#2795`](https://github.com/vrc-get/vrc-get/pull/2795)
|
||||
- I hope this prevents users unexpectedly adding prerelease packages
|
||||
- Path for unitypackage on Template Editor now can be reselected [`#2635`](https://github.com/vrc-get/vrc-get/pull/2635)
|
||||
- ALCOM now refuses launching project if project is on noexec mount points [`#2814`](https://github.com/vrc-get/vrc-get/pull/2814)
|
||||
- This would cause problems with several native plugins
|
||||
- Already-added packages are now excluded from the package name suggestions in the Template Editor [`#2828`](https://github.com/vrc-get/vrc-get/pull/2828)
|
||||
- Extended some timeouts to 1 minute [`#2826`](https://github.com/vrc-get/vrc-get/pull/2826)
|
||||
- Prevents timeouts in slow DNS environments
|
||||
- Improved robustness for package installation errors [`#2844`](https://github.com/vrc-get/vrc-get/pull/2844)
|
||||
- It is now unlikely that vrc-get will leave the project directory corrupted if an I/O error occurs while installing a package
|
||||
- Backslashes in path in zip file are now treated as path separator on unix [`#2845`](https://github.com/vrc-get/vrc-get/pull/2845)
|
||||
- This fixes problem with Gesture Manager 3.9.7
|
||||
- Empty string for `documentationUrl` and `changelogUrl` are now allowed and ignored [`#2930`](https://github.com/vrc-get/vrc-get/pull/2930)
|
||||
- They are formerly rejected as invalid url
|
||||
|
||||
### Fixed
|
||||
- Fixed an issue where the progress bar flickered and did not display correct progress in environments using WebKit as the renderer. [`#2641`](https://github.com/vrc-get/vrc-get/pull/2641)
|
||||
- Fails to import UnityPackages with files in `Packages` directory `#2679`
|
||||
- null as vpmDependencies value is not allowed `#2709`
|
||||
- Fails to import UnityPackages with files in `Packages` directory [`#2679`](https://github.com/vrc-get/vrc-get/pull/2679)
|
||||
- null as vpmDependencies value is not allowed [`#2709`](https://github.com/vrc-get/vrc-get/pull/2709)
|
||||
- It's not recommended, but we allow null for `vpmDependencies` as a alias of `{}`
|
||||
- ALCOM cannot detect per-user flatpak installation of unity hub `#2812`
|
||||
- Unabled to import some untypackages `#2821`
|
||||
- ALCOM cannot detect per-user flatpak installation of unity hub [`#2812`](https://github.com/vrc-get/vrc-get/pull/2812)
|
||||
- Unabled to import some untypackages [`#2821`](https://github.com/vrc-get/vrc-get/pull/2821)
|
||||
- It's hard to say but some older unitypackages ware unsupported.
|
||||
- Panic when resolving projects where dependency packages depend on newer versions of locked packages `#2822`
|
||||
- Missing glibc and libgcc_s dependency notation in .deb / .rpm distributon `#2828`
|
||||
- Unclear error message for invalid version name or version range `#2842`
|
||||
- Default file names in save dialogs now include the appropriate file extension `#2846`
|
||||
- Panic when resolving projects where dependency packages depend on newer versions of locked packages [`#2822`](https://github.com/vrc-get/vrc-get/pull/2822)
|
||||
- Missing glibc and libgcc_s dependency notation in .deb / .rpm distributon [`#2828`](https://github.com/vrc-get/vrc-get/pull/2828)
|
||||
- Unclear error message for invalid version name or version range [`#2842`](https://github.com/vrc-get/vrc-get/pull/2842)
|
||||
- Default file names in save dialogs now include the appropriate file extension [`#2846`](https://github.com/vrc-get/vrc-get/pull/2846)
|
||||
- Template export now defaults to `{template name}.alcomtemplate`
|
||||
- Repository list export now defaults to `repositories.txt`
|
||||
- Uninformative `[object Object]` appearing as an error message `#2848`
|
||||
- New Unity Hub loading method may not load manually added Unity Editors `#2850`
|
||||
- New Unity Hub loading method does load unity hub configuration on Linux `#2850`
|
||||
- Uninformative `[object Object]` appearing as an error message [`#2848`](https://github.com/vrc-get/vrc-get/pull/2848)
|
||||
- New Unity Hub loading method may not load manually added Unity Editors [`#2850`](https://github.com/vrc-get/vrc-get/pull/2850)
|
||||
- New Unity Hub loading method does load unity hub configuration on Linux [`#2850`](https://github.com/vrc-get/vrc-get/pull/2850)
|
||||
- Too many open files when copying project `#2867
|
||||
- Added workaround for VRCDefaultWorldScene generation issue in SDK 3.10.2 or later `#2916`
|
||||
- Added workaround for VRCDefaultWorldScene generation issue in SDK 3.10.2 or later [`#2916`](https://github.com/vrc-get/vrc-get/pull/2916)
|
||||
- See [this][default-scene-canny] canny for bug in VRCSDK and issue [#2913][issue-2913] for our decision.
|
||||
|
||||
### Security
|
||||
- Package hash checks are now enforced when installing packages `#2849`
|
||||
- Package hash checks are now enforced when installing packages [`#2849`](https://github.com/vrc-get/vrc-get/pull/2849)
|
||||
- It has been about two years since the error message for package hash mismatches was introduced.
|
||||
- It is now enforced for security.
|
||||
|
||||
|
|
@ -693,7 +703,8 @@ Release pipeline fixes
|
|||
- Apple code signing [`#422`](https://github.com/anatawa12/vrc-get/pull/422)
|
||||
- Migrate vpm 2019 project to 2022 [`#435`](https://github.com/anatawa12/vrc-get/pull/435)
|
||||
|
||||
[Unreleased]: https://github.com/vrc-get/vrc-get/compare/gui-v1.1.5...HEAD
|
||||
[Unreleased]: https://github.com/vrc-get/vrc-get/compare/gui-v1.1.6...HEAD
|
||||
[1.1.6]: https://github.com/vrc-get/vrc-get/compare/gui-v1.1.5...gui-v1.1.6
|
||||
[1.1.5]: https://github.com/vrc-get/vrc-get/compare/gui-v1.1.4...gui-v1.1.5
|
||||
[1.1.4]: https://github.com/vrc-get/vrc-get/compare/gui-v1.1.3...gui-v1.1.4
|
||||
[1.1.3]: https://github.com/vrc-get/vrc-get/compare/gui-v1.1.2...gui-v1.1.3
|
||||
|
|
|
|||
4410
Cargo.lock
generated
4410
Cargo.lock
generated
File diff suppressed because it is too large
Load diff
|
|
@ -5,8 +5,6 @@ members = [
|
|||
"xtask",
|
||||
"vrc-get",
|
||||
"vrc-get-gui",
|
||||
"vrc-get-gui-gpui",
|
||||
"vrc-get-gui-runtime",
|
||||
"vrc-get-gui/windows-installer-wrapper",
|
||||
"vrc-get-vpm",
|
||||
]
|
||||
|
|
@ -33,6 +31,3 @@ incremental = false
|
|||
debug = 1
|
||||
opt-level = 0
|
||||
lto = "off"
|
||||
|
||||
[patch.crates-io]
|
||||
gpui = { git = "https://github.com/zed-industries/zed.git", rev = "69e2130295c2649963eb639fc70b4f2ee8ea1624", package = "gpui" }
|
||||
|
|
|
|||
|
|
@ -1,77 +0,0 @@
|
|||
# GPUI staged migration track
|
||||
|
||||
This repository now contains a staged migration track to move GUI rendering from Tauri/WebView to GPUI without deleting the working Tauri app.
|
||||
|
||||
## Scope
|
||||
|
||||
- Keep `vrc-get-gui` (Tauri) as the production frontend until feature parity is reached.
|
||||
- Add `vrc-get-gui-gpui` as an experimental frontend crate in the same workspace.
|
||||
- Keep `vrc-get-vpm` as the shared business/backend library for both frontends.
|
||||
- Introduce `vrc-get-gui-runtime` for a shared Tokio runtime bridge pattern.
|
||||
|
||||
## Stages
|
||||
|
||||
### Stage 1 – Validated ✅
|
||||
|
||||
Package management table POC (`app/_main/projects/manage/-package-list-card.tsx` equivalent):
|
||||
- GPUI table rendering with striped rows and column headers.
|
||||
- Text input with clear button and live search filtering.
|
||||
- Dialog lifecycle (title, confirm button, child content).
|
||||
- Native file dialog integration via `rfd`.
|
||||
- `TokioBridge` async plumbing (`spawn` / `call` / `shutdown`).
|
||||
|
||||
### Stage 2 – In progress
|
||||
|
||||
Wire real `vrc-get-vpm` data into a live Projects list screen:
|
||||
- `backend.rs` — async `load_projects()` using `VccDatabaseConnection`.
|
||||
- `ProjectsView` — loading state → live data, live search filtering via `cx.observe`.
|
||||
- `TokioBridge::call()` dispatches to Tokio; result is awaited in GPUI's async context via `cx.spawn`.
|
||||
|
||||
### Stage 3 – Planned
|
||||
|
||||
Port pages in this order:
|
||||
1. Setup wizard
|
||||
2. Settings
|
||||
3. Log viewer
|
||||
4. Projects (full, with create/add/remove)
|
||||
5. Packages (last, hardest)
|
||||
|
||||
## i18n migration
|
||||
|
||||
- Script added: `vrc-get-gui/scripts/i18next-to-rust-i18n.mjs`
|
||||
- Converts i18next dotted-key JSON5 format to nested rust-i18n YAML.
|
||||
- Run with:
|
||||
- `npm run i18n:to-rust`
|
||||
- `npm run i18n:to-rust -- locales/ja.json5 locales/ja.yml`
|
||||
|
||||
## Native file dialog policy
|
||||
|
||||
- GPUI migration path uses `rfd` for native file/folder dialogs on Windows/macOS/Linux.
|
||||
|
||||
## GPUI version pinning
|
||||
|
||||
- GPUI is pinned to Zed commit `69e2130295c2649963eb639fc70b4f2ee8ea1624` in workspace patch configuration.
|
||||
- Update only by intentional SHA bumps.
|
||||
|
||||
## Linux GPU note
|
||||
|
||||
- GPUI with Vulkan generally behaves better than WebKit for open-source NVIDIA users.
|
||||
- Nouveau may fall back to llvmpipe (software rendering).
|
||||
- Mesa + AMD/Intel Vulkan is the expected reliable path.
|
||||
|
||||
## Async bridge pattern
|
||||
|
||||
```rust
|
||||
// Dispatch heavy async work to Tokio; await result in GPUI.
|
||||
let rx = self.bridge.call(load_projects()).unwrap();
|
||||
cx.spawn(async move |this: WeakEntity<View>, cx: &mut AsyncApp| {
|
||||
if let Ok(Ok(data)) = rx.await {
|
||||
this.update(cx, |view, cx| {
|
||||
view.data = data;
|
||||
cx.notify();
|
||||
}).ok();
|
||||
}
|
||||
}).detach();
|
||||
```
|
||||
|
||||
The pattern works because `tokio::sync::oneshot::Receiver<T>` implements `Future` and can be awaited from within GPUI's executor.
|
||||
|
|
@ -1,22 +0,0 @@
|
|||
[package]
|
||||
name = "vrc-get-gui-gpui"
|
||||
version = "0.1.0"
|
||||
description = "Experimental GPUI frontend for vrc-get"
|
||||
|
||||
homepage.workspace = true
|
||||
authors.workspace = true
|
||||
license.workspace = true
|
||||
repository.workspace = true
|
||||
edition.workspace = true
|
||||
|
||||
[[bin]]
|
||||
name = "vrc-get-gui-gpui"
|
||||
path = "src/main.rs"
|
||||
|
||||
[dependencies]
|
||||
anyhow = "1"
|
||||
gpui = { git = "https://github.com/zed-industries/zed.git", rev = "69e2130295c2649963eb639fc70b4f2ee8ea1624", package = "gpui" }
|
||||
gpui-component = "=0.5.1"
|
||||
rfd = "0.15"
|
||||
vrc-get-vpm = { path = "../vrc-get-vpm", features = ["experimental-project-management", "experimental-unity-management"] }
|
||||
vrc-get-gui-runtime = { path = "../vrc-get-gui-runtime" }
|
||||
|
|
@ -1,11 +0,0 @@
|
|||
# vrc-get-gui-gpui
|
||||
|
||||
Experimental GPUI frontend crate for staged migration.
|
||||
|
||||
Current focus:
|
||||
|
||||
1. Validate package-management-style table rendering.
|
||||
2. Validate dialog lifecycle and text input behavior.
|
||||
3. Validate native file dialog integration through `rfd`.
|
||||
|
||||
This crate intentionally coexists with the production `vrc-get-gui` (Tauri) crate.
|
||||
|
|
@ -1,78 +0,0 @@
|
|||
use std::path::PathBuf;
|
||||
|
||||
use vrc_get_vpm::ProjectType;
|
||||
use vrc_get_vpm::environment::{VccDatabaseConnection, UserProject};
|
||||
use vrc_get_vpm::io::DefaultEnvironmentIo;
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct ProjectRow {
|
||||
pub name: String,
|
||||
pub path: String,
|
||||
pub project_type: String,
|
||||
pub unity: String,
|
||||
pub favorite: bool,
|
||||
pub last_modified_ms: i64,
|
||||
}
|
||||
|
||||
impl ProjectRow {
|
||||
fn from_user_project(p: &UserProject) -> Option<Self> {
|
||||
let path = p.path()?.to_owned();
|
||||
let name = PathBuf::from(&path)
|
||||
.file_name()
|
||||
.and_then(|s| s.to_str())
|
||||
.unwrap_or(&path)
|
||||
.to_owned();
|
||||
let project_type = project_type_label(p.project_type());
|
||||
let unity = p
|
||||
.unity_version()
|
||||
.map(|v| v.to_string())
|
||||
.unwrap_or_else(|| "unknown".to_owned());
|
||||
let favorite = p.favorite();
|
||||
let last_modified_ms = p
|
||||
.last_modified()
|
||||
.map(|d| d.as_unix_milliseconds())
|
||||
.unwrap_or(0);
|
||||
|
||||
Some(ProjectRow {
|
||||
name,
|
||||
path,
|
||||
project_type,
|
||||
unity,
|
||||
favorite,
|
||||
last_modified_ms,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
fn project_type_label(t: ProjectType) -> String {
|
||||
match t {
|
||||
ProjectType::Unknown => "Unknown",
|
||||
ProjectType::LegacySdk2 => "Legacy SDK2",
|
||||
ProjectType::LegacyWorlds => "Legacy Worlds",
|
||||
ProjectType::LegacyAvatars => "Legacy Avatars",
|
||||
ProjectType::UpmWorlds => "UPM Worlds",
|
||||
ProjectType::UpmAvatars => "UPM Avatars",
|
||||
ProjectType::UpmStarter => "UPM Starter",
|
||||
ProjectType::Worlds => "Worlds",
|
||||
ProjectType::Avatars => "Avatars",
|
||||
ProjectType::VpmStarter => "VPM Starter",
|
||||
}
|
||||
.to_owned()
|
||||
}
|
||||
|
||||
/// Load all projects from the VCC database. Intended to be called from a
|
||||
/// Tokio context (via `TokioBridge::call`).
|
||||
pub async fn load_projects() -> anyhow::Result<Vec<ProjectRow>> {
|
||||
let io = DefaultEnvironmentIo::new_default();
|
||||
let connection = VccDatabaseConnection::connect(&io).await?;
|
||||
|
||||
let mut projects = connection.get_projects();
|
||||
projects.retain(|p| p.path().is_some());
|
||||
|
||||
let rows = projects
|
||||
.iter()
|
||||
.filter_map(ProjectRow::from_user_project)
|
||||
.collect();
|
||||
|
||||
Ok(rows)
|
||||
}
|
||||
|
|
@ -1,267 +0,0 @@
|
|||
mod backend;
|
||||
|
||||
use backend::{ProjectRow, load_projects};
|
||||
|
||||
use gpui::prelude::*;
|
||||
use gpui::{
|
||||
App, Application, Context, IntoElement, ParentElement, Render, SharedString, Styled, Window,
|
||||
WindowOptions, div,
|
||||
};
|
||||
use gpui_component::{
|
||||
Root, StyledExt,
|
||||
button::{Button, ButtonVariants as _},
|
||||
h_flex,
|
||||
input::{Input, InputState},
|
||||
spinner::Spinner,
|
||||
table::{Column, Table, TableDelegate, TableState},
|
||||
v_flex,
|
||||
};
|
||||
use vrc_get_gui_runtime::TokioBridge;
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Projects table delegate
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
struct ProjectsDelegate {
|
||||
columns: Vec<Column>,
|
||||
rows: Vec<ProjectRow>,
|
||||
}
|
||||
|
||||
impl ProjectsDelegate {
|
||||
fn new() -> Self {
|
||||
Self {
|
||||
columns: vec![
|
||||
Column::new("name", "Name"),
|
||||
Column::new("type", "Type"),
|
||||
Column::new("unity", "Unity"),
|
||||
Column::new("path", "Path"),
|
||||
],
|
||||
rows: vec![],
|
||||
}
|
||||
}
|
||||
|
||||
fn set_rows(&mut self, rows: Vec<ProjectRow>) {
|
||||
self.rows = rows;
|
||||
}
|
||||
}
|
||||
|
||||
impl TableDelegate for ProjectsDelegate {
|
||||
fn columns_count(&self, _: &App) -> usize {
|
||||
self.columns.len()
|
||||
}
|
||||
|
||||
fn rows_count(&self, _: &App) -> usize {
|
||||
self.rows.len()
|
||||
}
|
||||
|
||||
fn column(&self, col_ix: usize, _: &App) -> &Column {
|
||||
&self.columns[col_ix]
|
||||
}
|
||||
|
||||
fn render_td(
|
||||
&mut self,
|
||||
row_ix: usize,
|
||||
col_ix: usize,
|
||||
_: &mut Window,
|
||||
_: &mut Context<TableState<Self>>,
|
||||
) -> impl IntoElement {
|
||||
let row = &self.rows[row_ix];
|
||||
let value: SharedString = match col_ix {
|
||||
0 => row.name.clone().into(),
|
||||
1 => row.project_type.clone().into(),
|
||||
2 => row.unity.clone().into(),
|
||||
_ => row.path.clone().into(),
|
||||
};
|
||||
div().child(value)
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Loading state
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
enum ProjectsData {
|
||||
Loading,
|
||||
Loaded(Vec<ProjectRow>),
|
||||
Error(String),
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Root view
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
struct ProjectsView {
|
||||
bridge: TokioBridge,
|
||||
search_input: gpui::Entity<InputState>,
|
||||
table_state: gpui::Entity<TableState<ProjectsDelegate>>,
|
||||
data: ProjectsData,
|
||||
}
|
||||
|
||||
impl ProjectsView {
|
||||
fn new(window: &mut Window, cx: &mut Context<Self>) -> Self {
|
||||
let bridge = TokioBridge::new("vrc-get-gpui-runtime");
|
||||
let search_input =
|
||||
cx.new(|cx| InputState::new(window, cx).placeholder("Search projects"));
|
||||
let table_state = cx.new(|cx| TableState::new(ProjectsDelegate::new(), window, cx));
|
||||
|
||||
// Re-filter the table whenever the search input changes.
|
||||
cx.observe(&search_input, |view, _, cx| {
|
||||
view.apply_search(cx);
|
||||
})
|
||||
.detach();
|
||||
|
||||
let mut view = Self {
|
||||
bridge,
|
||||
search_input,
|
||||
table_state,
|
||||
data: ProjectsData::Loading,
|
||||
};
|
||||
view.reload(cx);
|
||||
view
|
||||
}
|
||||
|
||||
fn reload(&mut self, cx: &mut Context<Self>) {
|
||||
self.data = ProjectsData::Loading;
|
||||
cx.notify();
|
||||
|
||||
let rx = self
|
||||
.bridge
|
||||
.call(load_projects())
|
||||
.expect("tokio bridge still alive");
|
||||
|
||||
cx.spawn(async move |this: gpui::WeakEntity<ProjectsView>, cx: &mut gpui::AsyncApp| {
|
||||
match rx.await {
|
||||
Ok(Ok(rows)) => {
|
||||
this.update(cx, |view, cx| {
|
||||
let search = view.search_input.read(cx).value().to_lowercase();
|
||||
let filtered = filter_rows(&rows, &search);
|
||||
view.table_state.update(cx, |table, _| {
|
||||
table.delegate_mut().set_rows(filtered);
|
||||
});
|
||||
view.data = ProjectsData::Loaded(rows);
|
||||
cx.notify();
|
||||
})
|
||||
.ok();
|
||||
}
|
||||
Ok(Err(err)) => {
|
||||
this.update(cx, |view, cx| {
|
||||
view.data = ProjectsData::Error(err.to_string());
|
||||
cx.notify();
|
||||
})
|
||||
.ok();
|
||||
}
|
||||
Err(_) => {}
|
||||
}
|
||||
})
|
||||
.detach();
|
||||
}
|
||||
|
||||
fn apply_search(&mut self, cx: &mut Context<Self>) {
|
||||
let ProjectsData::Loaded(ref all_rows) = self.data else {
|
||||
return;
|
||||
};
|
||||
let search = self.search_input.read(cx).value().to_lowercase();
|
||||
let rows = filter_rows(all_rows, &search);
|
||||
self.table_state.update(cx, |table, _| {
|
||||
table.delegate_mut().set_rows(rows);
|
||||
});
|
||||
cx.notify();
|
||||
}
|
||||
}
|
||||
|
||||
fn filter_rows(rows: &[ProjectRow], search: &str) -> Vec<ProjectRow> {
|
||||
if search.is_empty() {
|
||||
rows.to_vec()
|
||||
} else {
|
||||
rows.iter()
|
||||
.filter(|r| {
|
||||
r.name.to_lowercase().contains(search)
|
||||
|| r.path.to_lowercase().contains(search)
|
||||
})
|
||||
.cloned()
|
||||
.collect()
|
||||
}
|
||||
}
|
||||
|
||||
impl Render for ProjectsView {
|
||||
fn render(&mut self, _window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
|
||||
let is_loading = matches!(self.data, ProjectsData::Loading);
|
||||
let error_msg: Option<SharedString> = if let ProjectsData::Error(ref e) = self.data {
|
||||
Some(e.clone().into())
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
// Toolbar
|
||||
let search_el = Input::new(&self.search_input).cleanable(true);
|
||||
|
||||
let reload_btn = Button::new("reload")
|
||||
.label("Reload")
|
||||
.on_click(cx.listener(|view, _event: &gpui::ClickEvent, _window, cx| {
|
||||
view.reload(cx);
|
||||
}));
|
||||
|
||||
let add_btn = Button::new("add-project")
|
||||
.primary()
|
||||
.label("Add Project")
|
||||
.on_click(|_event, _window, _cx| {
|
||||
let _ = rfd::FileDialog::new().pick_folder();
|
||||
});
|
||||
|
||||
let toolbar = h_flex()
|
||||
.items_center()
|
||||
.justify_between()
|
||||
.child(search_el)
|
||||
.child(h_flex().gap_2().child(reload_btn).child(add_btn));
|
||||
|
||||
// Body
|
||||
let body: gpui::AnyElement = if is_loading {
|
||||
h_flex()
|
||||
.size_full()
|
||||
.items_center()
|
||||
.justify_center()
|
||||
.gap_2()
|
||||
.child(Spinner::new())
|
||||
.child(div().child("Loading projects…"))
|
||||
.into_any_element()
|
||||
} else if let Some(msg) = error_msg {
|
||||
div()
|
||||
.p_4()
|
||||
.text_color(gpui::red())
|
||||
.child(format!("Error: {msg}"))
|
||||
.into_any_element()
|
||||
} else {
|
||||
Table::new(&self.table_state)
|
||||
.stripe(true)
|
||||
.into_any_element()
|
||||
};
|
||||
|
||||
v_flex()
|
||||
.size_full()
|
||||
.p_4()
|
||||
.gap_3()
|
||||
.child(
|
||||
h_flex()
|
||||
.items_center()
|
||||
.gap_2()
|
||||
.child(div().font_bold().child("Projects"))
|
||||
.when(is_loading, |el| el.child(Spinner::new())),
|
||||
)
|
||||
.child(toolbar)
|
||||
.child(body)
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
Application::new().run(|cx: &mut App| {
|
||||
gpui_component::init(cx);
|
||||
|
||||
cx.open_window(WindowOptions::default(), |window, cx| {
|
||||
let view = cx.new(|cx| ProjectsView::new(window, cx));
|
||||
cx.new(|cx| Root::new(view, window, cx))
|
||||
})
|
||||
.expect("opening gpui window");
|
||||
|
||||
cx.activate(true);
|
||||
});
|
||||
}
|
||||
|
|
@ -1,14 +0,0 @@
|
|||
[package]
|
||||
name = "vrc-get-gui-runtime"
|
||||
version = "0.1.0"
|
||||
edition.workspace = true
|
||||
license.workspace = true
|
||||
authors.workspace = true
|
||||
homepage.workspace = true
|
||||
repository.workspace = true
|
||||
|
||||
[dependencies]
|
||||
tokio = { version = "1", features = ["rt-multi-thread", "sync"] }
|
||||
|
||||
[dev-dependencies]
|
||||
tokio = { version = "1", features = ["macros", "rt", "time"] }
|
||||
|
|
@ -1,135 +0,0 @@
|
|||
use std::future::Future;
|
||||
use std::pin::Pin;
|
||||
use std::sync::Arc;
|
||||
use std::sync::atomic::{AtomicBool, Ordering};
|
||||
use std::thread;
|
||||
|
||||
use tokio::runtime::Builder;
|
||||
use tokio::sync::{mpsc, oneshot};
|
||||
|
||||
type BoxFuture = Pin<Box<dyn Future<Output = ()> + Send + 'static>>;
|
||||
|
||||
enum Message {
|
||||
Task(BoxFuture),
|
||||
Shutdown,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub struct BridgeClosed;
|
||||
|
||||
impl std::fmt::Display for BridgeClosed {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
f.write_str("tokio bridge is closed")
|
||||
}
|
||||
}
|
||||
|
||||
impl std::error::Error for BridgeClosed {}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct TokioBridge {
|
||||
sender: mpsc::UnboundedSender<Message>,
|
||||
closed: Arc<AtomicBool>,
|
||||
}
|
||||
|
||||
impl TokioBridge {
|
||||
pub fn new(thread_name: &'static str) -> Self {
|
||||
let (sender, mut receiver) = mpsc::unbounded_channel();
|
||||
let closed = Arc::new(AtomicBool::new(false));
|
||||
let closed_for_thread = closed.clone();
|
||||
|
||||
thread::Builder::new()
|
||||
.name(thread_name.to_owned())
|
||||
.spawn(move || {
|
||||
let runtime = Builder::new_multi_thread()
|
||||
.worker_threads(1)
|
||||
.enable_all()
|
||||
.build()
|
||||
.expect("building tokio bridge runtime");
|
||||
|
||||
runtime.block_on(async move {
|
||||
while let Some(message) = receiver.recv().await {
|
||||
match message {
|
||||
Message::Task(task) => {
|
||||
tokio::spawn(task);
|
||||
}
|
||||
Message::Shutdown => break,
|
||||
}
|
||||
}
|
||||
closed_for_thread.store(true, Ordering::Release);
|
||||
});
|
||||
})
|
||||
.expect("spawning tokio bridge thread");
|
||||
|
||||
Self { sender, closed }
|
||||
}
|
||||
|
||||
pub fn is_closed(&self) -> bool {
|
||||
self.closed.load(Ordering::Acquire)
|
||||
}
|
||||
|
||||
pub fn spawn<Fut>(&self, task: Fut) -> Result<(), BridgeClosed>
|
||||
where
|
||||
Fut: Future<Output = ()> + Send + 'static,
|
||||
{
|
||||
self.sender
|
||||
.send(Message::Task(Box::pin(task)))
|
||||
.map_err(|_| BridgeClosed)
|
||||
}
|
||||
|
||||
pub fn call<Fut, T>(&self, task: Fut) -> Result<oneshot::Receiver<T>, BridgeClosed>
|
||||
where
|
||||
Fut: Future<Output = T> + Send + 'static,
|
||||
T: Send + 'static,
|
||||
{
|
||||
let (sender, receiver) = oneshot::channel();
|
||||
self.spawn(async move {
|
||||
let _ = sender.send(task.await);
|
||||
})?;
|
||||
Ok(receiver)
|
||||
}
|
||||
|
||||
pub fn shutdown(&self) -> Result<(), BridgeClosed> {
|
||||
self.sender
|
||||
.send(Message::Shutdown)
|
||||
.map_err(|_| BridgeClosed)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::TokioBridge;
|
||||
use std::time::Duration;
|
||||
use tokio::time::timeout;
|
||||
|
||||
#[tokio::test(flavor = "current_thread")]
|
||||
async fn call_returns_result() {
|
||||
let bridge = TokioBridge::new("test-runtime");
|
||||
|
||||
let receiver = bridge.call(async { 40 + 2 }).unwrap();
|
||||
assert_eq!(receiver.await.unwrap(), 42);
|
||||
|
||||
bridge.shutdown().unwrap();
|
||||
}
|
||||
|
||||
#[tokio::test(flavor = "current_thread")]
|
||||
async fn spawn_runs_in_background() {
|
||||
let bridge = TokioBridge::new("test-runtime-bg");
|
||||
|
||||
let receiver = bridge
|
||||
.call(async {
|
||||
tokio::time::sleep(Duration::from_millis(10)).await;
|
||||
"done"
|
||||
})
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(
|
||||
timeout(Duration::from_secs(1), receiver)
|
||||
.await
|
||||
.unwrap()
|
||||
.unwrap(),
|
||||
"done"
|
||||
);
|
||||
|
||||
bridge.shutdown().unwrap();
|
||||
}
|
||||
}
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "vrc-get-gui"
|
||||
version = "1.1.6-rc.0"
|
||||
version = "1.1.7-beta.0"
|
||||
description = "A fast open-source alternative of VRChat Creator Companion"
|
||||
|
||||
homepage.workspace = true
|
||||
|
|
@ -24,7 +24,6 @@ serde = { version = "1", features = ["derive"] }
|
|||
serde_with = { version = "3", features = ["base64"] }
|
||||
tauri = { version = "=2.11.2", features = [ "config-toml" ] } # = for sync version between npm and cargo
|
||||
vrc-get-vpm = { path = "../vrc-get-vpm", features = ["experimental-project-management", "experimental-unity-management"] }
|
||||
vrc-get-gui-runtime = { path = "../vrc-get-gui-runtime" }
|
||||
reqwest = { version = "0.13", features = ["gzip", "brotli", "json"] }
|
||||
specta = { version = "2.0.0-rc.24", features = [ "chrono", "url", "indexmap" ] }
|
||||
tauri-specta = { version = "2.0.0-rc.24", features = ["typescript"] }
|
||||
|
|
@ -62,7 +61,7 @@ yoke = { version = "0.8", features = ["derive"] }
|
|||
atomicbox = "0.4"
|
||||
stable_deref_trait = "1"
|
||||
itertools = "0.14"
|
||||
sysinfo = "0.39.2"
|
||||
sysinfo = "0.39.3"
|
||||
|
||||
[target.'cfg(windows)'.dependencies]
|
||||
windows = { version = "0.62", features = ["Win32_Storage_FileSystem", "Win32_System_IO", "Win32_NetworkManagement_IpHelper", "Wdk_System_SystemServices", "Win32_System_SystemInformation", "Win32_UI_Shell", "Win32_UI_WindowsAndMessaging"] }
|
||||
|
|
|
|||
|
|
@ -29,7 +29,11 @@ import {
|
|||
} from "@/components/ui/tooltip";
|
||||
import type { TauriProject } from "@/lib/bindings";
|
||||
import { commands } from "@/lib/bindings";
|
||||
import { dateToString, formatDateOffset } from "@/lib/dateToString";
|
||||
import {
|
||||
dateToString,
|
||||
dayToString,
|
||||
formatDateOffset,
|
||||
} from "@/lib/dateToString";
|
||||
import { openSingleDialog } from "@/lib/dialog";
|
||||
import { tc } from "@/lib/i18n";
|
||||
import { toastThrownError } from "@/lib/toast";
|
||||
|
|
@ -45,7 +49,7 @@ export function ProjectGridItem({
|
|||
|
||||
const typeIconClass = "w-5 h-5";
|
||||
|
||||
const { projectTypeKind, displayType, isLegacy, lastModified } =
|
||||
const { projectTypeKind, displayType, isLegacy, createdAt, lastModified } =
|
||||
getProjectDisplayInfo(project);
|
||||
|
||||
const removed = !project.is_exists;
|
||||
|
|
@ -165,22 +169,44 @@ export function ProjectGridItem({
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<div className="text-xs text-muted-foreground">
|
||||
{tc("general:last modified")}:{" "}
|
||||
<Tooltip>
|
||||
<TooltipTrigger>
|
||||
<time dateTime={lastModified.toISOString()}>
|
||||
<time className="font-normal">
|
||||
{formatDateOffset(project.last_modified)}
|
||||
<div className="flex flex-row gap-1">
|
||||
<div className="text-xs text-muted-foreground">
|
||||
{tc("general:created at")}:{" "}
|
||||
<Tooltip>
|
||||
<TooltipTrigger>
|
||||
<time dateTime={createdAt.toISOString()}>
|
||||
<time className="font-normal">
|
||||
{dayToString(project.created_at)}
|
||||
</time>
|
||||
</time>
|
||||
</time>
|
||||
</TooltipTrigger>
|
||||
<TooltipPortal>
|
||||
<TooltipContent>
|
||||
{dateToString(project.last_modified)}
|
||||
</TooltipContent>
|
||||
</TooltipPortal>
|
||||
</Tooltip>
|
||||
</TooltipTrigger>
|
||||
<TooltipPortal>
|
||||
<TooltipContent>
|
||||
{dateToString(project.created_at)}
|
||||
</TooltipContent>
|
||||
</TooltipPortal>
|
||||
</Tooltip>
|
||||
</div>
|
||||
|
||||
<p className="text-xs text-muted-foreground">/</p>
|
||||
|
||||
<div className="text-xs text-muted-foreground">
|
||||
{tc("general:last modified")}:{" "}
|
||||
<Tooltip>
|
||||
<TooltipTrigger>
|
||||
<time dateTime={lastModified.toISOString()}>
|
||||
<time className="font-normal">
|
||||
{formatDateOffset(project.last_modified)}
|
||||
</time>
|
||||
</time>
|
||||
</TooltipTrigger>
|
||||
<TooltipPortal>
|
||||
<TooltipContent>
|
||||
{dateToString(project.last_modified)}
|
||||
</TooltipContent>
|
||||
</TooltipPortal>
|
||||
</Tooltip>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="mt-2 flex flex-wrap gap-2 justify-end compact:gap-1">
|
||||
|
|
|
|||
|
|
@ -29,7 +29,11 @@ import {
|
|||
import { assertNever } from "@/lib/assert-never";
|
||||
import type { TauriProject, TauriProjectType } from "@/lib/bindings";
|
||||
import { commands } from "@/lib/bindings";
|
||||
import { dateToString, formatDateOffset } from "@/lib/dateToString";
|
||||
import {
|
||||
dateToString,
|
||||
dayToString,
|
||||
formatDateOffset,
|
||||
} from "@/lib/dateToString";
|
||||
import { type DialogContext, openSingleDialog, showDialog } from "@/lib/dialog";
|
||||
import { tc, tt } from "@/lib/i18n";
|
||||
import { router } from "@/lib/main";
|
||||
|
|
@ -78,7 +82,7 @@ export function ProjectRow({
|
|||
const noGrowCellClass = `${cellClass} w-1`;
|
||||
const typeIconClass = "w-5 h-5";
|
||||
|
||||
const { projectTypeKind, displayType, isLegacy, lastModified } =
|
||||
const { projectTypeKind, displayType, isLegacy, createdAt, lastModified } =
|
||||
getProjectDisplayInfo(project);
|
||||
|
||||
const openProjectFolder = () =>
|
||||
|
|
@ -105,7 +109,7 @@ export function ProjectRow({
|
|||
<tr
|
||||
className={`group even:bg-secondary/30 ${removed || loading || !(project.is_valid ?? true) ? "opacity-50" : ""}`}
|
||||
>
|
||||
<td className={`${cellClass} w-3`}>
|
||||
<td className={noGrowCellClass}>
|
||||
<div className={"relative flex"}>
|
||||
<FavoriteStarToggleButton
|
||||
favorite={project.favorite}
|
||||
|
|
@ -147,7 +151,7 @@ export function ProjectRow({
|
|||
</TooltipPortal>
|
||||
</Tooltip>
|
||||
</td>
|
||||
<td className={`${cellClass} w-[8em] min-w-[8em]`}>
|
||||
<td className={noGrowCellClass}>
|
||||
<div className="flex flex-row gap-2">
|
||||
<div className="flex items-center">
|
||||
{projectTypeKind === "avatars" ? (
|
||||
|
|
@ -171,6 +175,22 @@ export function ProjectRow({
|
|||
<td className={noGrowCellClass}>
|
||||
<p className="font-normal">{project.unity}</p>
|
||||
</td>
|
||||
<td className={noGrowCellClass}>
|
||||
<Tooltip>
|
||||
<TooltipTrigger>
|
||||
<time dateTime={createdAt.toISOString()}>
|
||||
<time className="font-normal">
|
||||
{dayToString(project.created_at)}
|
||||
</time>
|
||||
</time>
|
||||
</TooltipTrigger>
|
||||
<TooltipPortal>
|
||||
<TooltipContent>
|
||||
{dateToString(project.created_at)}
|
||||
</TooltipContent>
|
||||
</TooltipPortal>
|
||||
</Tooltip>
|
||||
</td>
|
||||
<td className={noGrowCellClass}>
|
||||
<Tooltip>
|
||||
<TooltipTrigger>
|
||||
|
|
@ -501,12 +521,14 @@ export function getProjectDisplayInfo(project: TauriProject) {
|
|||
const projectTypeKind = ProjectDisplayType[project.project_type] ?? "unknown";
|
||||
const displayType = tc(`projects:type:${projectTypeKind}`);
|
||||
const isLegacy = LegacyProjectTypes.includes(project.project_type);
|
||||
const createdAt = new Date(project.created_at);
|
||||
const lastModified = new Date(project.last_modified);
|
||||
|
||||
return {
|
||||
projectTypeKind,
|
||||
displayType,
|
||||
isLegacy,
|
||||
createdAt,
|
||||
lastModified,
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@ const sortingOptions: { key: SimpleSorting; label: string }[] = [
|
|||
{ key: "name", label: "general:name" },
|
||||
{ key: "type", label: "projects:type" },
|
||||
{ key: "unity", label: "projects:unity" },
|
||||
{ key: "createdAt", label: "general:created at" },
|
||||
{ key: "lastModified", label: "general:last modified" },
|
||||
];
|
||||
|
||||
|
|
|
|||
|
|
@ -11,7 +11,13 @@ import { toastThrownError } from "@/lib/toast";
|
|||
import { compareUnityVersionString } from "@/lib/version";
|
||||
import { ProjectRow } from "./-project-row";
|
||||
|
||||
export const sortings = ["lastModified", "name", "unity", "type"] as const;
|
||||
export const sortings = [
|
||||
"createdAt",
|
||||
"lastModified",
|
||||
"name",
|
||||
"unity",
|
||||
"type",
|
||||
] as const;
|
||||
|
||||
type SimpleSorting = (typeof sortings)[number];
|
||||
type Sorting = SimpleSorting | `${SimpleSorting}Reversed`;
|
||||
|
|
@ -158,6 +164,18 @@ export function ProjectsTableCard({
|
|||
</small>
|
||||
</button>
|
||||
</th>
|
||||
<th className={`${thClass} ${headerBg("createdAt")}`}>
|
||||
<button
|
||||
type="button"
|
||||
className={"flex w-full project-table-button"}
|
||||
onClick={() => setSorting("createdAt")}
|
||||
>
|
||||
{icon("createdAt")}
|
||||
<small className="font-normal leading-none">
|
||||
{tc("general:created at")}
|
||||
</small>
|
||||
</button>
|
||||
</th>
|
||||
<th className={`${thClass} ${headerBg("lastModified")}`}>
|
||||
<button
|
||||
type="button"
|
||||
|
|
@ -194,6 +212,12 @@ export function sortSearchProjects(
|
|||
searched.sort((a, b) => b.last_modified - a.last_modified);
|
||||
|
||||
switch (sorting) {
|
||||
case "createdAt":
|
||||
searched.sort((a, b) => b.created_at - a.created_at);
|
||||
break;
|
||||
case "createdAtReversed":
|
||||
searched.sort((a, b) => a.created_at - b.created_at);
|
||||
break;
|
||||
case "lastModified":
|
||||
searched.sort((a, b) => b.last_modified - a.last_modified);
|
||||
break;
|
||||
|
|
|
|||
70
vrc-get-gui/bundle/alcom.spec
Normal file
70
vrc-get-gui/bundle/alcom.spec
Normal file
|
|
@ -0,0 +1,70 @@
|
|||
Name: alcom
|
||||
Version: 1.1.6
|
||||
Release: 1%{?dist}
|
||||
Summary: A short description of my custom application
|
||||
|
||||
%global git_version %(echo "%{version}" | tr '~' '-')
|
||||
|
||||
License: MIT
|
||||
URL: https://vrc-get.anatawa12.com/alcom/
|
||||
Source0: https://github.com/vrc-get/vrc-get/archive/gui-v%{git_version}.tar.gz
|
||||
|
||||
BuildRequires: gcc
|
||||
BuildRequires: nodejs
|
||||
BuildRequires: npm
|
||||
BuildRequires: pkgconfig(gtk+-3.0)
|
||||
BuildRequires: pkgconfig(webkit2gtk-4.1)
|
||||
BuildRequires: pkgconfig(openssl)
|
||||
|
||||
# we download rust toolchain manually when building inside mock container
|
||||
%if ! 0%{?install_rust:1}
|
||||
BuildRequires: cargo
|
||||
%endif
|
||||
|
||||
# disable stripping symbols.
|
||||
%global __os_install_post %{nil}
|
||||
%global debug_package %{nil}
|
||||
|
||||
%description
|
||||
ALCOM - Alternative Creator Companion
|
||||
ALCOM is a fast and open-source alternative VCC (VRChat Creator Companion) written in rust and tauri.
|
||||
|
||||
%prep
|
||||
%setup -q -n vrc-get-gui-v%{git_version}
|
||||
|
||||
%if 0%{?install_rust:1}
|
||||
echo "=== Mock environment detected. Installing isolated Rust toolchain ==="
|
||||
|
||||
export RUSTUP_HOME="$(pwd)/.rustup"
|
||||
export CARGO_HOME="$(pwd)/.cargo"
|
||||
|
||||
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --no-modify-path
|
||||
|
||||
cat << EOF > ./load_rust_env.sh
|
||||
export RUSTUP_HOME="${RUSTUP_HOME}"
|
||||
export CARGO_HOME="${CARGO_HOME}"
|
||||
source "${CARGO_HOME}/env"
|
||||
EOF
|
||||
%endif
|
||||
|
||||
# marker: ci inserts version update here
|
||||
|
||||
%build
|
||||
%{?install_rust: source ./load_rust_env.sh}
|
||||
cargo xtask build-alcom --release
|
||||
|
||||
%install
|
||||
%{?install_rust: source ./load_rust_env.sh}
|
||||
rm -rf %{buildroot}
|
||||
cargo xtask bundle-alcom --release --bundles buildroot --buildroot=%{buildroot}
|
||||
|
||||
%files
|
||||
%license LICENSE
|
||||
# %doc vrc-get-gui/README.md
|
||||
#%doc vrc-get-gui/CHANGELOG.md
|
||||
%{_bindir}/alcom
|
||||
%{_datadir}/applications/alcom.desktop
|
||||
%{_datadir}/icons/hicolor/*/apps/alcom.png
|
||||
|
||||
%changelog
|
||||
* Migrated to native rpm build pipeline with spec file
|
||||
|
|
@ -1,10 +0,0 @@
|
|||
Package: alcom
|
||||
Version: {{version}}-1
|
||||
Architecture: {{arch}}
|
||||
Installed-Size: {{estimated_size}}
|
||||
Maintainer: anatawa12 <i@anatawa12.com>
|
||||
Priority: optional
|
||||
Homepage: https://vrc-get.anatawa12.com/alcom/
|
||||
Depends: libwebkit2gtk-4.1-0, libgtk-3-0, libc6 (>= {{libc_version}}), libc6 (>= {{libgcc_version}})
|
||||
Description: ALCOM - Alternative Creator Companion
|
||||
ALCOM is a fast and open-source alternative VCC (VRChat Creator Companion) written in rust and tauri.
|
||||
7
vrc-get-gui/bundle/debian/.gitignore
vendored
Normal file
7
vrc-get-gui/bundle/debian/.gitignore
vendored
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
/*-build-stamp
|
||||
/*.substvars
|
||||
/.debhelper
|
||||
/files
|
||||
/cargo_home
|
||||
/npm_cache
|
||||
alcom/
|
||||
5
vrc-get-gui/bundle/debian/README.Debian
Normal file
5
vrc-get-gui/bundle/debian/README.Debian
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
alcom for Debian
|
||||
|
||||
ALCOM is a fast and open-source alternative VCC (VRChat Creator Companion) written in rust and tauri.
|
||||
|
||||
-- anatawa12 <i@anatawa12.com> Thu, 11 Jun 2026 14:34:57 +0000
|
||||
20
vrc-get-gui/bundle/debian/README.source
Normal file
20
vrc-get-gui/bundle/debian/README.source
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
alcom for Debian
|
||||
|
||||
This is README for alcom Debian package.
|
||||
|
||||
This Debian package is made to provide one of official distribution of alcom, formaly known as vrc-get-gui.
|
||||
Starting with 1.1.7 or later, alcom maintainer switched from custom .deb toolchain to official .deb toolchain.
|
||||
This directory contains source code of debian package as non-native package.
|
||||
|
||||
This directory is placed at vrc-get-gui/bundles/debian on original source tree, but before building debian package,
|
||||
you must copy vrc-get-gui/bundles/debian to debian.
|
||||
|
||||
Violating best practice of debian package, this package requires network access, to download cargo dependencies on build.
|
||||
In addition, by declaring `INSTALL_RUST` environment variable to `1` with `--set-envvar=INSTALL_RUST=1`, you can let
|
||||
build process to install newest available rust to build on older distribution does not provide new enough rust version.
|
||||
You also install NODEJS on build by declaring `INSTALL_NODEJS=1`.
|
||||
Those options are helpful when building inside sandbox like pbuilder.
|
||||
|
||||
This Debian package is based on package generated by debmake Version 4.5.1.
|
||||
|
||||
-- anatawa12 <i@anatawa12.com> Thu, 11 Jun 2026 14:34:57 +0000
|
||||
5
vrc-get-gui/bundle/debian/changelog
Normal file
5
vrc-get-gui/bundle/debian/changelog
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
alcom (1.1.6-1) UNRELEASED; urgency=low
|
||||
|
||||
* No changelog are provided for this package
|
||||
|
||||
-- root <i@anatawa12.com> Thu, 11 Jun 2026 14:34:57 +0000
|
||||
8
vrc-get-gui/bundle/debian/clean
Normal file
8
vrc-get-gui/bundle/debian/clean
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
target/
|
||||
vrc-get-gui/node_modules/
|
||||
vrc-get-gui/out/
|
||||
vrc-get-gui/gen/
|
||||
debian/cargo_home/
|
||||
debian/npm_cache/
|
||||
debian/rustup_home/
|
||||
debian/nodejs_installed/
|
||||
29
vrc-get-gui/bundle/debian/control
Normal file
29
vrc-get-gui/bundle/debian/control
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
Source: alcom
|
||||
Priority: optional
|
||||
Maintainer: anatawa12 <i@anatawa12.com>
|
||||
Build-Depends:
|
||||
debhelper-compat (= 13),
|
||||
libssl-dev,
|
||||
pkg-config,
|
||||
cargo,
|
||||
nodejs,
|
||||
npm,
|
||||
# curl for rust-install build only
|
||||
curl,
|
||||
libgtk-3-dev,
|
||||
libwebkit2gtk-4.1-dev (>= 2.41),
|
||||
Standards-Version: 4.7.0
|
||||
Homepage: https://vrc-get.anatawa12.com/alcom/
|
||||
Rules-Requires-Root: no
|
||||
|
||||
Package: alcom
|
||||
Architecture: any
|
||||
Multi-Arch: foreign
|
||||
Depends:
|
||||
${misc:Depends},
|
||||
${shlibs:Depends},
|
||||
Description: ALCOM - Alternative Creator Companion
|
||||
ALCOM is a fast and open-source alternative VCC (VRChat Creator Companion) written in rust and tauri.
|
||||
.
|
||||
This package is one of official distribution of ALCOM, released as a part of the updates from ALCOM.
|
||||
No packaging only updates will be provided.
|
||||
41
vrc-get-gui/bundle/debian/copyright
Normal file
41
vrc-get-gui/bundle/debian/copyright
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
|
||||
Upstream-Name: alcom
|
||||
Upstream-Contact: <preferred name and address to reach the upstream project>
|
||||
Source: <url://example.com>
|
||||
|
||||
Files: *
|
||||
Copyright: Copyright (c) 2023 anatawa12 and other contribcmeutors
|
||||
License: MIT
|
||||
MIT License
|
||||
.
|
||||
Copyright (c) 2023 anatawa12 and other contributors
|
||||
.
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
.
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
.
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
.
|
||||
|
||||
Files: vrc-get-gui/third-party/Anton-Regular.ttf
|
||||
vrc-get-gui/third-party/NotoSans-Italic-VariableFont_wdth,wght.ttf
|
||||
vrc-get-gui/third-party/NotoSans-VariableFont_wdth,wght.ttf
|
||||
Copyright: 2020 The Anton Project Authors (https://github.com/googlefonts/AntonFont.git)
|
||||
2022 The Noto Project Authors (https://github.com/notofonts/latin-greek-cyrillic)
|
||||
License: SIL Open Font License 1.1
|
||||
|
||||
Files: vrc-get-gui/icons/*
|
||||
Copyright: 2024 lilxyzw, anatawa12 and other contributors
|
||||
License: CC-BY-4.0
|
||||
39
vrc-get-gui/bundle/debian/rules
Executable file
39
vrc-get-gui/bundle/debian/rules
Executable file
|
|
@ -0,0 +1,39 @@
|
|||
#!/usr/bin/make -f
|
||||
|
||||
export DEB_BUILD_OPTIONS += nostrip
|
||||
|
||||
export CARGO_HOME = $(CURDIR)/debian/cargo_home
|
||||
export NPM_CONFIG_CACHE = $(CURDIR)/debian/npm_cache
|
||||
|
||||
%:
|
||||
dh $@
|
||||
|
||||
# install rust in configure phase when requested
|
||||
ifeq ($(INSTALL_RUST),1)
|
||||
export RUSTUP_HOME = $(CURDIR)/debian/rustup_home
|
||||
export PATH := $(CURDIR)/debian/cargo_home/bin:$(PATH)
|
||||
|
||||
override_dh_auto_configure::
|
||||
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --no-modify-path
|
||||
endif
|
||||
|
||||
ifeq ($(INSTALL_NODEJS),1)
|
||||
export RUSTUP_HOME = $(CURDIR)/debian/rustup_home
|
||||
export PATH := $(CURDIR)/debian/nodejs_installed/bin:$(PATH)
|
||||
|
||||
ifeq ($(DEB_HOST_ARCH),amd64)
|
||||
NODE_ARCH := x64
|
||||
else ifeq ($(DEB_HOST_ARCH),arm64)
|
||||
NODE_ARCH := arm64
|
||||
endif
|
||||
|
||||
override_dh_auto_configure::
|
||||
mkdir -p $(CURDIR)/debian/nodejs_installed
|
||||
curl --proto '=https' --tlsv1.2 -sSf https://nodejs.org/dist/v26.3.0/node-v26.3.0-linux-$(NODE_ARCH).tar.gz | gunzip | tar x --strip-components 1 -C $(CURDIR)/debian/nodejs_installed
|
||||
endif
|
||||
|
||||
override_dh_auto_build:
|
||||
cargo xtask build-alcom --release
|
||||
|
||||
override_dh_auto_install:
|
||||
cargo xtask bundle-alcom --release --bundles buildroot --buildroot=$(CURDIR)/debian/alcom
|
||||
1
vrc-get-gui/bundle/debian/source/format
Normal file
1
vrc-get-gui/bundle/debian/source/format
Normal file
|
|
@ -0,0 +1 @@
|
|||
3.0 (quilt)
|
||||
24
vrc-get-gui/bundle/debian/upstream/metadata
Normal file
24
vrc-get-gui/bundle/debian/upstream/metadata
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
# Metadata about the upstream project.
|
||||
# See https://wiki.debian.org/UpstreamMetadata
|
||||
|
||||
Bug-Database: https://github.com/vrc-get/vrc-get/issues
|
||||
Bug-Submit: https://github.com/vrc-get/vrc-get/issues/new
|
||||
Changelog: https://github.com/vrc-get/vrc-get/blob/master/vrc-get-gui/CHANGELOG.md
|
||||
Documentation: https://vrc-get.anatawa12.com/alcom/
|
||||
Repository-Browse: https://github.com/vrc-get/vrc-get
|
||||
Repository: https://github.com/vrc-get/vrc-get.git
|
||||
#FAQ: https://github.com/<user>/<project>/blob/main/FAQ.md
|
||||
Donation: https://github.com/sponsors/anatawa12
|
||||
#Registration: https://github.com/signup
|
||||
#Archive: PyPI # or CPAN, boost, etc.
|
||||
|
||||
# Uncomment these and fill them out to help users evaluate upstream:
|
||||
#Gallery: https://github.com/<user>/<project>/wiki/pictures-made-with-this-program
|
||||
#Screenshots: # pictures *of* the program, as opposed to pictures *made with* the program
|
||||
# - https://github.com/<user>/<project>/wiki/login-screen.png
|
||||
# - https://github.com/<user>/<project>/wiki/help-menu.png
|
||||
# - ...
|
||||
|
||||
# Uncomment these and fill them out to help resolve security issues:
|
||||
#Security-Contact: <how to send security-related messages>
|
||||
#CPE: <space-separated Common Platform Enumerator values - see https://wiki.debian.org/CPEtagPackagesDep>
|
||||
10
vrc-get-gui/bundle/debian/watch
Normal file
10
vrc-get-gui/bundle/debian/watch
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
# You must remove unused comment lines for the released package.
|
||||
# Compulsory line, this is a version 4 file
|
||||
version=4
|
||||
opts=\
|
||||
filenamemangle=s%.*/@ANY_VERSION@%@PACKAGE@-$1.tar.gz%,\
|
||||
downloadurlmangle=s%(api.github.com/repos/[^/]+/[^/]+)/git/refs/%$1/tarball/refs/%g,\
|
||||
uversionmangle=s/(\d)[-]?((RC|rc|pre|dev|beta|alpha)\.\d*)$/$1~$2/,\
|
||||
searchmode=plain \
|
||||
https://api.github.com/repos/vrc-get/vrc-get/git/matching-refs/tags/gui- \
|
||||
https://api.github.com/repos/[^/]+/[^/]+/git/refs/tags/gui-@ANY_VERSION@
|
||||
|
|
@ -93,6 +93,7 @@ export const commands = {
|
|||
projectSetUnityPath: (projectPath: string, unityPath: string | null) => __TAURI_INVOKE<boolean>("project_set_unity_path", { projectPath, unityPath }),
|
||||
utilOpen: (path: string, ifNotExists: OpenOptions) => __TAURI_INVOKE<null>("util_open", { path, ifNotExists }),
|
||||
utilOpenUrl: (url: string) => __TAURI_INVOKE<null>("util_open_url", { url }),
|
||||
utilOpenUrlNocheck: (url: string) => __TAURI_INVOKE<null>("util_open_url_nocheck", { url }),
|
||||
utilGetLogEntries: () => __TAURI_INVOKE<LogEntry_Serialize[]>("util_get_log_entries"),
|
||||
utilGetVersion: () => __TAURI_INVOKE<string>("util_get_version"),
|
||||
utilCheckForUpdate: () => __TAURI_INVOKE<{
|
||||
|
|
|
|||
|
|
@ -1,6 +1,16 @@
|
|||
import type React from "react";
|
||||
import { tc } from "@/lib/i18n";
|
||||
|
||||
export function dayToString(dateIn: Date | number | string) {
|
||||
const date = typeof dateIn !== "object" ? new Date(dateIn) : dateIn;
|
||||
|
||||
const year = date.getFullYear().toString().padStart(4, "0");
|
||||
const month = (date.getMonth() + 1).toString().padStart(2, "0");
|
||||
const day = date.getDate().toString().padStart(2, "0");
|
||||
|
||||
return `${year}-${month}-${day}`;
|
||||
}
|
||||
|
||||
export function dateToString(dateIn: Date | number | string) {
|
||||
const date = typeof dateIn !== "object" ? new Date(dateIn) : dateIn;
|
||||
|
||||
|
|
|
|||
|
|
@ -149,7 +149,7 @@ function UnityInstallWindow({
|
|||
dialog: DialogContext<void>;
|
||||
}) {
|
||||
const openUnityHub = async () => {
|
||||
await commands.utilOpenUrl(installWithUnityHubLink);
|
||||
await commands.utilOpenUrlNocheck(installWithUnityHubLink);
|
||||
};
|
||||
|
||||
return (
|
||||
|
|
|
|||
|
|
@ -37,6 +37,8 @@
|
|||
"general:error:failed to create dir": "Failed to create directory (missing permission?): {{err}}",
|
||||
"general:error:failed to create dir missing drive": "Failed to create directory. You may forget to connect the drive.",
|
||||
|
||||
"general:created at": "Added",
|
||||
|
||||
"general:last modified": "Last Modified",
|
||||
"general:last modified:moments": "Moments ago",
|
||||
"general:last modified:minutes_one": "{{count}} minute ago",
|
||||
|
|
|
|||
|
|
@ -37,6 +37,8 @@
|
|||
"general:error:failed to create dir": "ディレクトリの作成に失敗しました: {{err}}",
|
||||
"general:error:failed to create dir missing drive": "ディレクトリの作成に失敗しました。保存先のドライブの接続を忘れているかもしれません。",
|
||||
|
||||
"general:created at": "追加日",
|
||||
|
||||
"general:last modified": "最終更新日",
|
||||
"general:last modified:moments": "たった今",
|
||||
"general:last modified:minutes": "{{count}}分前",
|
||||
|
|
|
|||
312
vrc-get-gui/package-lock.json
generated
312
vrc-get-gui/package-lock.json
generated
|
|
@ -25,7 +25,7 @@
|
|||
"@radix-ui/react-slot": "^1",
|
||||
"@radix-ui/react-tooltip": "^1",
|
||||
"@tanstack/react-query": "^5",
|
||||
"@tanstack/react-router": "^1.170.8",
|
||||
"@tanstack/react-router": "^1.170.10",
|
||||
"@tanstack/router-devtools": "^1.167.0",
|
||||
"@tauri-apps/api": "2.11.0",
|
||||
"@uidotdev/usehooks": "^2",
|
||||
|
|
@ -35,26 +35,26 @@
|
|||
"cmdk": "^1",
|
||||
"i18next": "^26",
|
||||
"lucide-react": "^1",
|
||||
"react": "19.2.6",
|
||||
"react-dom": "19.2.6",
|
||||
"react": "19.2.7",
|
||||
"react-dom": "19.2.7",
|
||||
"react-i18next": "^17",
|
||||
"react-toastify": "^11",
|
||||
"tailwind-merge": "^3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@biomejs/biome": "^2",
|
||||
"@rollup/pluginutils": "^5.3.0",
|
||||
"@rollup/pluginutils": "^5.4.0",
|
||||
"@tailwindcss/vite": "^4.3.0",
|
||||
"@tanstack/router-plugin": "^1.168.11",
|
||||
"@tanstack/router-plugin": "^1.168.13",
|
||||
"@tauri-apps/cli": "2.11.2",
|
||||
"@types/node": "^20",
|
||||
"@types/react": "19.2.15",
|
||||
"@types/react": "19.2.16",
|
||||
"@types/react-dom": "19.2.3",
|
||||
"@vitejs/plugin-react": "^6.0.2",
|
||||
"json5": "^2",
|
||||
"tw-animate-css": "^1.4.0",
|
||||
"typescript": "~6.0",
|
||||
"vite": "^8.0.14"
|
||||
"vite": "^8.0.16"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/code-frame": {
|
||||
|
|
@ -349,9 +349,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@biomejs/biome": {
|
||||
"version": "2.4.15",
|
||||
"resolved": "https://registry.npmjs.org/@biomejs/biome/-/biome-2.4.15.tgz",
|
||||
"integrity": "sha512-j5VH3a/h/HXTKBM50MDMxRCzkeLv9S2XJcW2WgnZT1+xyisi+0bISrXR82gCX+8S9lvK0skEvHJRN+3Ktr2hlw==",
|
||||
"version": "2.4.16",
|
||||
"resolved": "https://registry.npmjs.org/@biomejs/biome/-/biome-2.4.16.tgz",
|
||||
"integrity": "sha512-x9ajFh1zChVybCiM3TN6OD4phAqLgtPZjFrZF+aTMYCPjwBO+k529TX7PPsAqtGNLeV4UgzwQnowEgS7bGmzcA==",
|
||||
"dev": true,
|
||||
"license": "MIT OR Apache-2.0",
|
||||
"bin": {
|
||||
|
|
@ -365,20 +365,20 @@
|
|||
"url": "https://opencollective.com/biome"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@biomejs/cli-darwin-arm64": "2.4.15",
|
||||
"@biomejs/cli-darwin-x64": "2.4.15",
|
||||
"@biomejs/cli-linux-arm64": "2.4.15",
|
||||
"@biomejs/cli-linux-arm64-musl": "2.4.15",
|
||||
"@biomejs/cli-linux-x64": "2.4.15",
|
||||
"@biomejs/cli-linux-x64-musl": "2.4.15",
|
||||
"@biomejs/cli-win32-arm64": "2.4.15",
|
||||
"@biomejs/cli-win32-x64": "2.4.15"
|
||||
"@biomejs/cli-darwin-arm64": "2.4.16",
|
||||
"@biomejs/cli-darwin-x64": "2.4.16",
|
||||
"@biomejs/cli-linux-arm64": "2.4.16",
|
||||
"@biomejs/cli-linux-arm64-musl": "2.4.16",
|
||||
"@biomejs/cli-linux-x64": "2.4.16",
|
||||
"@biomejs/cli-linux-x64-musl": "2.4.16",
|
||||
"@biomejs/cli-win32-arm64": "2.4.16",
|
||||
"@biomejs/cli-win32-x64": "2.4.16"
|
||||
}
|
||||
},
|
||||
"node_modules/@biomejs/cli-darwin-arm64": {
|
||||
"version": "2.4.15",
|
||||
"resolved": "https://registry.npmjs.org/@biomejs/cli-darwin-arm64/-/cli-darwin-arm64-2.4.15.tgz",
|
||||
"integrity": "sha512-rF3PPqLq1yoST79zaQbDjVJwsuIeci/O+9bgNmC5QpgOqz6aqYuzA4abyAGx+mgyiDXn4A049xAN8gijbuR1Qg==",
|
||||
"version": "2.4.16",
|
||||
"resolved": "https://registry.npmjs.org/@biomejs/cli-darwin-arm64/-/cli-darwin-arm64-2.4.16.tgz",
|
||||
"integrity": "sha512-wxPvu4XOA85YJk9ixSWUmq/QBHbid85BISbOAqqBM/5xQpPk9ayjk5375tOlSC0BeCwNSbPFafQBm+vBumXq0A==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
|
|
@ -393,9 +393,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@biomejs/cli-darwin-x64": {
|
||||
"version": "2.4.15",
|
||||
"resolved": "https://registry.npmjs.org/@biomejs/cli-darwin-x64/-/cli-darwin-x64-2.4.15.tgz",
|
||||
"integrity": "sha512-/5KHXYMfSJs1fNXiX30xFtI8JcCFV6zaVVLxOa0M2sfqBKHkpQhRTv94yxQWxeTY2lzo2OuTlNvPC+hDQt2wcQ==",
|
||||
"version": "2.4.16",
|
||||
"resolved": "https://registry.npmjs.org/@biomejs/cli-darwin-x64/-/cli-darwin-x64-2.4.16.tgz",
|
||||
"integrity": "sha512-xFCqGPwYusQJp4N4NJLi1XJiZqjwFdjhT+KqtNy+Ug3qgfczqnTa6MSDvxJF6TkuDLoYJItMapz6tAf7kCekFw==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
|
|
@ -410,9 +410,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@biomejs/cli-linux-arm64": {
|
||||
"version": "2.4.15",
|
||||
"resolved": "https://registry.npmjs.org/@biomejs/cli-linux-arm64/-/cli-linux-arm64-2.4.15.tgz",
|
||||
"integrity": "sha512-owaAMZD/T4LrD0ELNCk0Km3qrRHuM0X6EAyVE1FSqGY0rbLoiDLrO4Us2tllm6cAeB2Ioa9C2C08NZPdr8+0Ug==",
|
||||
"version": "2.4.16",
|
||||
"resolved": "https://registry.npmjs.org/@biomejs/cli-linux-arm64/-/cli-linux-arm64-2.4.16.tgz",
|
||||
"integrity": "sha512-2kFb4//jxfZaP6D+Rj5VkHkxgyD9EoRAVBEQb8PKRv+s4NO2zYNJKXFaJmK1CmhufJOWEfpHKaRbOja7qjmdhQ==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
|
|
@ -427,9 +427,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@biomejs/cli-linux-arm64-musl": {
|
||||
"version": "2.4.15",
|
||||
"resolved": "https://registry.npmjs.org/@biomejs/cli-linux-arm64-musl/-/cli-linux-arm64-musl-2.4.15.tgz",
|
||||
"integrity": "sha512-ZPcxznxm0pogHBLZhYntyR3sR+MrZjqJIKEr7ZqVen0Rl+P/4upVmfYXjftizi9RoqZntg33fv/1fbdhbYXpEQ==",
|
||||
"version": "2.4.16",
|
||||
"resolved": "https://registry.npmjs.org/@biomejs/cli-linux-arm64-musl/-/cli-linux-arm64-musl-2.4.16.tgz",
|
||||
"integrity": "sha512-oYxnW0ARfJkr72ezzF2OR8N/rtkgLUQeYtF8cFhVswbknHxtTcmzSsanVJP8yQKnGpGpc2ck6c5zLvHahL6Cbg==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
|
|
@ -444,9 +444,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@biomejs/cli-linux-x64": {
|
||||
"version": "2.4.15",
|
||||
"resolved": "https://registry.npmjs.org/@biomejs/cli-linux-x64/-/cli-linux-x64-2.4.15.tgz",
|
||||
"integrity": "sha512-0jj7THz12GbUOLmMibktK6DZjqz2zV64KFxyBtcFTKPiiOIY0a7vns1elpO1dERvxpsZ5ik0oFfz0oGwFde1+g==",
|
||||
"version": "2.4.16",
|
||||
"resolved": "https://registry.npmjs.org/@biomejs/cli-linux-x64/-/cli-linux-x64-2.4.16.tgz",
|
||||
"integrity": "sha512-NbcBbi/nJqn5baae6wqRXdS7Gadf2uRpehSh6vMSYpG8OhkXl/Xg8aorWrJ+9VWqAT5ml90alLvorkpMW0nBwQ==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
|
|
@ -461,9 +461,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@biomejs/cli-linux-x64-musl": {
|
||||
"version": "2.4.15",
|
||||
"resolved": "https://registry.npmjs.org/@biomejs/cli-linux-x64-musl/-/cli-linux-x64-musl-2.4.15.tgz",
|
||||
"integrity": "sha512-CNq/9W38SYSH023lfcQ4KKU8K0YX8T//FZUhcgtMMRABDojx5XsMV7jlweAvGSl389wJQB29Qo6Zb/a+jdvt+w==",
|
||||
"version": "2.4.16",
|
||||
"resolved": "https://registry.npmjs.org/@biomejs/cli-linux-x64-musl/-/cli-linux-x64-musl-2.4.16.tgz",
|
||||
"integrity": "sha512-iHDS+MCM65DPqWGu+ECC3uoALyj2H7F4nVUPxIPjz/PIl94EUu+EDfGZDzFP+NY1EOPVt9NQvwFqq7HdMmowdg==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
|
|
@ -478,9 +478,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@biomejs/cli-win32-arm64": {
|
||||
"version": "2.4.15",
|
||||
"resolved": "https://registry.npmjs.org/@biomejs/cli-win32-arm64/-/cli-win32-arm64-2.4.15.tgz",
|
||||
"integrity": "sha512-ouhkYdlhp/1GghEJPdWwD/Vi3gQ1nFxuSpMolWsbq3Lsq3QUR4jl6UdhhscdCugKU5vOEuMiJhvKj66O0OCq+w==",
|
||||
"version": "2.4.16",
|
||||
"resolved": "https://registry.npmjs.org/@biomejs/cli-win32-arm64/-/cli-win32-arm64-2.4.16.tgz",
|
||||
"integrity": "sha512-0rgImMsNb5v/chhkIFe3wu7PEFClS6RBAYUijGL9UsYN3PanSaoK24HSSuSJb1pYbYYVjzAyZTl3gtjJ84BM8A==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
|
|
@ -495,9 +495,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@biomejs/cli-win32-x64": {
|
||||
"version": "2.4.15",
|
||||
"resolved": "https://registry.npmjs.org/@biomejs/cli-win32-x64/-/cli-win32-x64-2.4.15.tgz",
|
||||
"integrity": "sha512-zBrGq5mx5wwpnow4+2BxUvleDM+GNd4sLbPaMapsSLQLD0NGRCquqPBTgN+7XkUteHvj7M+BstuI8tmnV7+HgQ==",
|
||||
"version": "2.4.16",
|
||||
"resolved": "https://registry.npmjs.org/@biomejs/cli-win32-x64/-/cli-win32-x64-2.4.16.tgz",
|
||||
"integrity": "sha512-Kp85jgoBHa05gix6UIRjfCDiUV3w/8VIdZ247VyyO2gEjaw12WEVhdIjlxp/AMzXxqxQwbxNTDVZ3Mwd2RG5rw==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
|
|
@ -706,9 +706,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@oxc-project/types": {
|
||||
"version": "0.132.0",
|
||||
"resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.132.0.tgz",
|
||||
"integrity": "sha512-FESMOxil5Se014ui/Eq8fT5uHJo6nIRwH0PfJrZJXs6Gek3ZVFOrpUv3YIZT20m+extU98Hg1Ym72U58rlsxUQ==",
|
||||
"version": "0.133.0",
|
||||
"resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.133.0.tgz",
|
||||
"integrity": "sha512-KzkdCd6Uxqnf6l3HOw1xfatAlUURA0g14cvBYFyJ5SaNOQbOUvBr9PKArcPcrNIeRsBdgcUzOGrhKveVpvOIGA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
|
|
@ -1877,9 +1877,9 @@
|
|||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@rolldown/binding-android-arm64": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.0.2.tgz",
|
||||
"integrity": "sha512-ZS4D1JPGn/MYQN/SYDWftIE/nVsM8j/AFOYEzAoOE2O3NktQOZru+/vYXGbR/qtdLdIfGCP0lcoJiYVzsEz+iQ==",
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.0.3.tgz",
|
||||
"integrity": "sha512-454rs7jHngixp/NMxd5srYD57OnzSlZ/eFTETjORQHLwJG1lRtmNOJcBerZlfu4GjKqeq8aCCIQrMdHyhI51Hw==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
|
|
@ -1894,9 +1894,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@rolldown/binding-darwin-arm64": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.0.2.tgz",
|
||||
"integrity": "sha512-vdFA9+C/rekyGce7WqHs/xoT0ioZEWaOFyZLIV1mEeNFaFDUQrPIo8Vs2GvJ6eetb3rzDUtUBgzto3ExpXJB3w==",
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.0.3.tgz",
|
||||
"integrity": "sha512-PcAhP+ynjURNyy8SKGl5DQP94aGuB/7JrXJb/t7P+hanXvQVMWzUvRRhBAcg/lNRadBhoUPqSoP4xw5tR/KBEA==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
|
|
@ -1911,9 +1911,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@rolldown/binding-darwin-x64": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.0.2.tgz",
|
||||
"integrity": "sha512-BewSOwTHazv77DTYiAZXSqqKZ4KP/KonFisDMVU7PImxoWfB2aepnPhd2E4SWz3zDzYgDNbs6jBmTdgNnF02GA==",
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.0.3.tgz",
|
||||
"integrity": "sha512-9YpfeUvSE2RS7wysJ81uOZkXJz7f7Q55H2Gvp3VEw/EsahqDtrphrZ0EwDLK5vvKOzaCrBsjF8JmnMLcUt78Gg==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
|
|
@ -1928,9 +1928,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@rolldown/binding-freebsd-x64": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.0.2.tgz",
|
||||
"integrity": "sha512-m41o7M0YWtUdqk61Tb+jnKb2rN++iRdIASlExkUoKfIAH30DOHCB8fVLzSUpbWHHU8esmEioY62PxzexE8MBuA==",
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.0.3.tgz",
|
||||
"integrity": "sha512-yB1IlAsSNHncV6SCTL27/MVGR5htvQsoGxIv5KMGXALp+Ll1wYsn+x98M9MW7qa+NdSbvrrY7ANI4wLJ0n1e6g==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
|
|
@ -1945,9 +1945,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@rolldown/binding-linux-arm-gnueabihf": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.0.2.tgz",
|
||||
"integrity": "sha512-jcojB9H7W/jS29pMKWAK1N+fU99vXodHDTatS3b3y/XSOCiHo0kkA74pL3jJmkoQtYpOCxDvaKs1fo2Ij/1X5w==",
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.0.3.tgz",
|
||||
"integrity": "sha512-Yi30IVAAfLUCy2MseFjbB1jAMDl1VMCAas5StnYp8da9+CKvMd2H2cbEjWcw5NPaPqzvYkVIaF1nNUG+b7u/sw==",
|
||||
"cpu": [
|
||||
"arm"
|
||||
],
|
||||
|
|
@ -1962,9 +1962,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@rolldown/binding-linux-arm64-gnu": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.0.2.tgz",
|
||||
"integrity": "sha512-1jn6qDU5iiOgFgygDzKUuKP0maTi0/f1+sBLgvij/76C77Nm3ts6ufz9Bjg5q5dduxiUIxtq86JIoBvo1xQ4Ig==",
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.0.3.tgz",
|
||||
"integrity": "sha512-jsO7R8To+AdlYgUmN5sHSCZbfhtMBkO0WUx8iORQnPcMMdgr7qM2DQmMwgabs3GhNztdmoKkMKQFHD6DTMCIQw==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
|
|
@ -1979,9 +1979,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@rolldown/binding-linux-arm64-musl": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.0.2.tgz",
|
||||
"integrity": "sha512-QVLO/czFMdoMFSqlX3bcswcJNm/23r+qoa/jgtmFc/qEp6/jXmIkDjF/XIo8dPfGaiwy1xfQn8o77L79GeXFgw==",
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.0.3.tgz",
|
||||
"integrity": "sha512-VWkUHwWriDciit80wleYwKILoR/KMvxh/IdwS/paX+ZgpuRpCrKLUdadJbc0NpBEiyhpYawsJ73j9aCvOH+f7Q==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
|
|
@ -1996,9 +1996,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@rolldown/binding-linux-ppc64-gnu": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.0.2.tgz",
|
||||
"integrity": "sha512-hgO5Abm0w5UL6FEa2iFnZqo2KlK7TQ5QhV5x09hujBf7t5KzHQ1VmfPuTpqRy/rNlSxua3eWH374xxiVrP+lcA==",
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.0.3.tgz",
|
||||
"integrity": "sha512-5f1laC0SlIR0yDbFCd8acUhvJIag6N3zC5P7oUPN6wX0aOma+uKJ0wBDH5aq7I1PVI2ttTlhJwzwRIBnLiSGEg==",
|
||||
"cpu": [
|
||||
"ppc64"
|
||||
],
|
||||
|
|
@ -2013,9 +2013,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@rolldown/binding-linux-s390x-gnu": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.0.2.tgz",
|
||||
"integrity": "sha512-fy8rXxuYEu602abC8MUNaPjYLIFzReOaEIEMKMUa0rFEUxNpVXhs15KSSQ4qlqSaM7B6rcj9rDZgADh/IGDzLQ==",
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.0.3.tgz",
|
||||
"integrity": "sha512-Iq4ko0r4XsgbrF/LunNgHtAGLRRVE2kXonAXQ/MV0mC6jQpMOhW1SvtZja2EhC/kd05++bP78dsqBeIQyYJ6Yg==",
|
||||
"cpu": [
|
||||
"s390x"
|
||||
],
|
||||
|
|
@ -2030,9 +2030,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@rolldown/binding-linux-x64-gnu": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.0.2.tgz",
|
||||
"integrity": "sha512-0+bOkiQ779+r1WpoHOWHqncvyySci0vKph+myNDYb+im6meJAzHQXay6oEgnkHuUGouM1LKTZwqKpBow6Kj7CQ==",
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.0.3.tgz",
|
||||
"integrity": "sha512-B8m6tD5+/N5FeNQFbKlLA/2yVq9ycQP1SeedyEYYKWBNR3ZQbkvIUcNnDNM03lO1l5F2roiiFJGgvoLLyZXtSg==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
|
|
@ -2047,9 +2047,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@rolldown/binding-linux-x64-musl": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.0.2.tgz",
|
||||
"integrity": "sha512-mjSkrzZK5Qsl0a9d1JgILOiuZOSDTVdKENcSXBoqbzSrspLR/4/IRVDo5wd2GgZjNss/viBFJdeq+j7qH2nypw==",
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.0.3.tgz",
|
||||
"integrity": "sha512-pSdpdUJHkuCxun9LE7jvgUB9qsRgaiyNNCX7m/AvHTcq67AiT/Yhoxvw5zPfhrM8k/BfP8ce/hMOpthKDpEUow==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
|
|
@ -2064,9 +2064,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@rolldown/binding-openharmony-arm64": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.0.2.tgz",
|
||||
"integrity": "sha512-1v5vHasdfQAZoEHakBV72LIFAC9JjnymsiKxp+GEr/ma3+NJCPSaYK+qavInOovJkgwFrs7GccX2d6IgDA3Z5w==",
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.0.3.tgz",
|
||||
"integrity": "sha512-OXXS3RKJgX2uLwM+gYyuH5omcH8fL1LJs96pZGgtetVCahON57+d4SJHzTgZiOjxgGkSnpXpOsWuPDGAKAigEg==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
|
|
@ -2081,9 +2081,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@rolldown/binding-wasm32-wasi": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-wasm32-wasi/-/binding-wasm32-wasi-1.0.2.tgz",
|
||||
"integrity": "sha512-mb1VobWn6NheziTk5/WEaR6AKVbrwT5sOi6C7zk3gy/pD1qtJfU1j4PgTo2NJnOtbL9Dl3Aeei8w9jJ7qC2jZQ==",
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-wasm32-wasi/-/binding-wasm32-wasi-1.0.3.tgz",
|
||||
"integrity": "sha512-JTtb8BWFynicNSoPrehsCzBtOKjZ6jhMiPFEmOiuXg1Fl8dn2KHQob+GuPSGR0dryQa1PQJbzjF3dqO/whhjLg==",
|
||||
"cpu": [
|
||||
"wasm32"
|
||||
],
|
||||
|
|
@ -2100,9 +2100,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@rolldown/binding-win32-arm64-msvc": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.0.2.tgz",
|
||||
"integrity": "sha512-SqKonF56vA/L2yHwHYcEp2P34URpOZ7d1fS635cTkpDnUtEGdUbhI6NzsPdqeSWvAAeGDrxjWjNmibDIdFf9/A==",
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.0.3.tgz",
|
||||
"integrity": "sha512-gEdFFEN70A/jxb2svrWsN3aDL7OUtmvlOy+6fa2jxG8K0wQ1ZbdeLGnidov6Yu5/733dI5ySfzFlQ/cb0bSz1g==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
|
|
@ -2117,9 +2117,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@rolldown/binding-win32-x64-msvc": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.0.2.tgz",
|
||||
"integrity": "sha512-v7qRI7gXLRINcOGXt+7YmAZ6iFuyZVMIoXAxhd8oP+DR9dLfL9GfNIx7PLMxmhZdvq8waUJBQiWN9EKNy+TRBQ==",
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.0.3.tgz",
|
||||
"integrity": "sha512-eXB7CHuaQdqmJcc3koCNtNPmT/bj2gc999kUFgBxG8Ac0NdgXc4rkCHhqrgrhN3zddvvvrgzj1e90SuSfmyIXA==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
|
|
@ -2141,9 +2141,9 @@
|
|||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@rollup/pluginutils": {
|
||||
"version": "5.3.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.3.0.tgz",
|
||||
"integrity": "sha512-5EdhGZtnu3V88ces7s53hhfK5KSASnJZv8Lulpc04cWO3REESroJXg73DFsOmgbU2BhwV0E20bu2IDZb3VKW4Q==",
|
||||
"version": "5.4.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.4.0.tgz",
|
||||
"integrity": "sha512-MfPp06CjRLfXQ3wY0R8vJDYBy/MvVcc9OulEfR0B8Iv9ko+GCNaRZ+EpJYFl27LhKsZK0o420sYCRHCjfCgeUg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
|
|
@ -2554,14 +2554,14 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@tanstack/react-router": {
|
||||
"version": "1.170.8",
|
||||
"resolved": "https://registry.npmjs.org/@tanstack/react-router/-/react-router-1.170.8.tgz",
|
||||
"integrity": "sha512-Qw2ju6jjnIsMpuW+VrnHZWHuugqs592PWsnI56sG28qNhg14CgRLahOcNajfuJR9P4MxKGP94WVzmFKSYUz/ig==",
|
||||
"version": "1.170.10",
|
||||
"resolved": "https://registry.npmjs.org/@tanstack/react-router/-/react-router-1.170.10.tgz",
|
||||
"integrity": "sha512-gVmWYq0ucWr+OB97Nud0YhKa9NOipB7/QrWI7wRZJJWEL0qUS8WPqAs0vA1f3IBXZpXmf8xxzf/tl5cmo4tlmA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@tanstack/history": "1.162.0",
|
||||
"@tanstack/react-store": "^0.9.3",
|
||||
"@tanstack/router-core": "1.171.6",
|
||||
"@tanstack/router-core": "1.171.8",
|
||||
"isbot": "^5.1.22"
|
||||
},
|
||||
"engines": {
|
||||
|
|
@ -2595,9 +2595,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@tanstack/router-core": {
|
||||
"version": "1.171.6",
|
||||
"resolved": "https://registry.npmjs.org/@tanstack/router-core/-/router-core-1.171.6.tgz",
|
||||
"integrity": "sha512-Ol6DQ+j6rf/rPVELIzo8LHwOQV2KL+zry3b+39kL/GKrt7YId52WJRAFMzuseY4XceSW+PU7sG/Cc1QkwJr0hg==",
|
||||
"version": "1.171.8",
|
||||
"resolved": "https://registry.npmjs.org/@tanstack/router-core/-/router-core-1.171.8.tgz",
|
||||
"integrity": "sha512-PbrTBbofFcacrH3RLgHYILRqTFnAGq+gXrXoA/vo7qUSkJpSO4GWfLtrtCahD4VayzRm19IPwcjPPLEugag6pw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@tanstack/history": "1.162.0",
|
||||
|
|
@ -2696,14 +2696,14 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@tanstack/router-generator": {
|
||||
"version": "1.167.10",
|
||||
"resolved": "https://registry.npmjs.org/@tanstack/router-generator/-/router-generator-1.167.10.tgz",
|
||||
"integrity": "sha512-CjbjWRSo6djLU/C7ncb9IbKUcf4IwpdqhLGngkwKkXaVFXGxEAafA/uhvOCv/UEUVR7NI3tJqqQmxYXGcJPbjw==",
|
||||
"version": "1.167.12",
|
||||
"resolved": "https://registry.npmjs.org/@tanstack/router-generator/-/router-generator-1.167.12.tgz",
|
||||
"integrity": "sha512-FGr7nn6VhjL53TUCTyDgApSkAYRxhId+v0HVQdSu0ADkNuHY+sUnYEMqiF6aN82jYWuXzrSL1xazg6/rfEP82g==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/types": "^7.28.5",
|
||||
"@tanstack/router-core": "1.171.6",
|
||||
"@tanstack/router-core": "1.171.8",
|
||||
"@tanstack/router-utils": "1.162.1",
|
||||
"@tanstack/virtual-file-routes": "1.162.0",
|
||||
"jiti": "^2.7.0",
|
||||
|
|
@ -2720,9 +2720,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@tanstack/router-plugin": {
|
||||
"version": "1.168.11",
|
||||
"resolved": "https://registry.npmjs.org/@tanstack/router-plugin/-/router-plugin-1.168.11.tgz",
|
||||
"integrity": "sha512-b2eom/8xCWL/OiWxKub8kYsr8p+kvmB/eXwYGqCWG8vilcJo+eQCSyp54nKt0AZ5k/ET1+eINc+4mwL3bVeAgg==",
|
||||
"version": "1.168.13",
|
||||
"resolved": "https://registry.npmjs.org/@tanstack/router-plugin/-/router-plugin-1.168.13.tgz",
|
||||
"integrity": "sha512-LnepwDai+TaC4K3aZeXrrKpnGoP8xGGilVGFfa5flGgC3+jCSBysb8SktidRE8eF2/iOzCQC0LIGirtMyZepSA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
|
|
@ -2732,8 +2732,8 @@
|
|||
"@babel/template": "^7.27.2",
|
||||
"@babel/traverse": "^7.28.5",
|
||||
"@babel/types": "^7.28.5",
|
||||
"@tanstack/router-core": "1.171.6",
|
||||
"@tanstack/router-generator": "1.167.10",
|
||||
"@tanstack/router-core": "1.171.8",
|
||||
"@tanstack/router-generator": "1.167.12",
|
||||
"@tanstack/router-utils": "1.162.1",
|
||||
"@tanstack/virtual-file-routes": "1.162.0",
|
||||
"chokidar": "^5.0.0",
|
||||
|
|
@ -2749,7 +2749,7 @@
|
|||
},
|
||||
"peerDependencies": {
|
||||
"@rsbuild/core": ">=1.0.2 || ^2.0.0",
|
||||
"@tanstack/react-router": "^1.170.8",
|
||||
"@tanstack/react-router": "^1.170.10",
|
||||
"vite": ">=5.0.0 || >=6.0.0 || >=7.0.0 || >=8.0.0",
|
||||
"vite-plugin-solid": "^2.11.10 || ^3.0.0-0",
|
||||
"webpack": ">=5.92.0"
|
||||
|
|
@ -3077,9 +3077,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@types/react": {
|
||||
"version": "19.2.15",
|
||||
"resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.15.tgz",
|
||||
"integrity": "sha512-eRwcGNHve+E8qtEQSSRl6urh+rFop4v8gm6O8rGv25CodbvFdLjA1vVQ1KkiFE0w0UPOnb8tDiFKL5lp0rtY5Q==",
|
||||
"version": "19.2.16",
|
||||
"resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.16.tgz",
|
||||
"integrity": "sha512-esJiCAnl0kfpNdE69f3So4WJUXy95dLZydX0KwK46riIHDzHM7O9Vtf9xCHW0PXIqvgqNrswl522kA/5yx+F4w==",
|
||||
"devOptional": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
|
|
@ -3136,9 +3136,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/ansis": {
|
||||
"version": "4.3.0",
|
||||
"resolved": "https://registry.npmjs.org/ansis/-/ansis-4.3.0.tgz",
|
||||
"integrity": "sha512-44mvgtPvohuU/70DdY5Oz2AIrLJ9k6/5x4KmoSvPwO+5Moijo0+N9D0fKbbYZQWP1hNm5CpOf+E01jhxG/r8xg==",
|
||||
"version": "4.3.1",
|
||||
"resolved": "https://registry.npmjs.org/ansis/-/ansis-4.3.1.tgz",
|
||||
"integrity": "sha512-BJ8/l4R5LRE7hW9WdSuGYrLSHi2ynxeFpDFbH0K/CgNeY/tyhk+vO6TYxXC5r5CpUhNVX310xzPsN/H9lCdfOA==",
|
||||
"dev": true,
|
||||
"license": "ISC",
|
||||
"engines": {
|
||||
|
|
@ -3458,9 +3458,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/i18next": {
|
||||
"version": "26.2.0",
|
||||
"resolved": "https://registry.npmjs.org/i18next/-/i18next-26.2.0.tgz",
|
||||
"integrity": "sha512-zwBHldHdTmwN7r6UNc7lC6GWNN+YYg3DrRSeHR5PRRBf5QnJZcYHrQc0uaU26qZeYxR7iFZD+Y315dPnKP47wA==",
|
||||
"version": "26.3.0",
|
||||
"resolved": "https://registry.npmjs.org/i18next/-/i18next-26.3.0.tgz",
|
||||
"integrity": "sha512-gHSgGpUXVmuqE2El1W61DmxeyeTlFfZgdJRWMo9jScAn5pu7TuTuiccb1zh3E2J9hEBVGJ23+96x0ieBhfuIHA==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "individual",
|
||||
|
|
@ -3809,9 +3809,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/lucide-react": {
|
||||
"version": "1.16.0",
|
||||
"resolved": "https://registry.npmjs.org/lucide-react/-/lucide-react-1.16.0.tgz",
|
||||
"integrity": "sha512-dYwyPzb4MEKpGUmNYk3WKWPnMrHs3FKM+q94kAnJrcDIqqn1hq2xY8scaS2ovsOCM5D51ey2gaRG3PBb1vgoYQ==",
|
||||
"version": "1.17.0",
|
||||
"resolved": "https://registry.npmjs.org/lucide-react/-/lucide-react-1.17.0.tgz",
|
||||
"integrity": "sha512-9FA9evdox/JQL5PT57fdA1x/yg8T7knJ98+zjTL3UfKza6pflQUUh3XtaQIHKvnsJw1lmsEyHVlt5jchYxOQ5w==",
|
||||
"license": "ISC",
|
||||
"peerDependencies": {
|
||||
"react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0"
|
||||
|
|
@ -3920,24 +3920,24 @@
|
|||
}
|
||||
},
|
||||
"node_modules/react": {
|
||||
"version": "19.2.6",
|
||||
"resolved": "https://registry.npmjs.org/react/-/react-19.2.6.tgz",
|
||||
"integrity": "sha512-sfWGGfavi0xr8Pg0sVsyHMAOziVYKgPLNrS7ig+ivMNb3wbCBw3KxtflsGBAwD3gYQlE/AEZsTLgToRrSCjb0Q==",
|
||||
"version": "19.2.7",
|
||||
"resolved": "https://registry.npmjs.org/react/-/react-19.2.7.tgz",
|
||||
"integrity": "sha512-HNe9WslTbXmFK8o8cmwgAeJFSBvt1bPdHCVKtaaV+WlAN36mpT4hcRpwbf3fY56ar2oIXzsBpOAiIRHAdY0OlQ==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/react-dom": {
|
||||
"version": "19.2.6",
|
||||
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.6.tgz",
|
||||
"integrity": "sha512-0prMI+hvBbPjsWnxDLxlCGyM8PN6UuWjEUCYmZhO67xIV9Xasa/r/vDnq+Xyq4Lo27g8QSbO5YzARu0D1Sps3g==",
|
||||
"version": "19.2.7",
|
||||
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.7.tgz",
|
||||
"integrity": "sha512-t0BRVXvbiE/o20Hfw669rLbMCDWtYZLvmJigy2f0MxsXF+71pxhR3xOkspmsO8h3ZlNzyibAmtCa3l4lYKk6gQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"scheduler": "^0.27.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": "^19.2.6"
|
||||
"react": "^19.2.7"
|
||||
}
|
||||
},
|
||||
"node_modules/react-i18next": {
|
||||
|
|
@ -4064,13 +4064,13 @@
|
|||
}
|
||||
},
|
||||
"node_modules/rolldown": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.0.2.tgz",
|
||||
"integrity": "sha512-oZx5zVDtVB44AW3eaifgDml1gWRDZGvjcfdxonE4swNPG98PrrXjaO/KrnUjzlMnztCCRVlUueA1kCXhARGk6g==",
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.0.3.tgz",
|
||||
"integrity": "sha512-i00lAJ2ks1BYr7rjNjKC7BcqAS7nVfiT3QX1SI5aY+AFHblCmaUf9OE9dbdzDvW6dJxbi2ZCZiy9v3CcwOiX3g==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@oxc-project/types": "=0.132.0",
|
||||
"@oxc-project/types": "=0.133.0",
|
||||
"@rolldown/pluginutils": "^1.0.0"
|
||||
},
|
||||
"bin": {
|
||||
|
|
@ -4080,21 +4080,21 @@
|
|||
"node": "^20.19.0 || >=22.12.0"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@rolldown/binding-android-arm64": "1.0.2",
|
||||
"@rolldown/binding-darwin-arm64": "1.0.2",
|
||||
"@rolldown/binding-darwin-x64": "1.0.2",
|
||||
"@rolldown/binding-freebsd-x64": "1.0.2",
|
||||
"@rolldown/binding-linux-arm-gnueabihf": "1.0.2",
|
||||
"@rolldown/binding-linux-arm64-gnu": "1.0.2",
|
||||
"@rolldown/binding-linux-arm64-musl": "1.0.2",
|
||||
"@rolldown/binding-linux-ppc64-gnu": "1.0.2",
|
||||
"@rolldown/binding-linux-s390x-gnu": "1.0.2",
|
||||
"@rolldown/binding-linux-x64-gnu": "1.0.2",
|
||||
"@rolldown/binding-linux-x64-musl": "1.0.2",
|
||||
"@rolldown/binding-openharmony-arm64": "1.0.2",
|
||||
"@rolldown/binding-wasm32-wasi": "1.0.2",
|
||||
"@rolldown/binding-win32-arm64-msvc": "1.0.2",
|
||||
"@rolldown/binding-win32-x64-msvc": "1.0.2"
|
||||
"@rolldown/binding-android-arm64": "1.0.3",
|
||||
"@rolldown/binding-darwin-arm64": "1.0.3",
|
||||
"@rolldown/binding-darwin-x64": "1.0.3",
|
||||
"@rolldown/binding-freebsd-x64": "1.0.3",
|
||||
"@rolldown/binding-linux-arm-gnueabihf": "1.0.3",
|
||||
"@rolldown/binding-linux-arm64-gnu": "1.0.3",
|
||||
"@rolldown/binding-linux-arm64-musl": "1.0.3",
|
||||
"@rolldown/binding-linux-ppc64-gnu": "1.0.3",
|
||||
"@rolldown/binding-linux-s390x-gnu": "1.0.3",
|
||||
"@rolldown/binding-linux-x64-gnu": "1.0.3",
|
||||
"@rolldown/binding-linux-x64-musl": "1.0.3",
|
||||
"@rolldown/binding-openharmony-arm64": "1.0.3",
|
||||
"@rolldown/binding-wasm32-wasi": "1.0.3",
|
||||
"@rolldown/binding-win32-arm64-msvc": "1.0.3",
|
||||
"@rolldown/binding-win32-x64-msvc": "1.0.3"
|
||||
}
|
||||
},
|
||||
"node_modules/scheduler": {
|
||||
|
|
@ -4176,9 +4176,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/tinyglobby": {
|
||||
"version": "0.2.16",
|
||||
"resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.16.tgz",
|
||||
"integrity": "sha512-pn99VhoACYR8nFHhxqix+uvsbXineAasWm5ojXoN8xEwK5Kd3/TrhNn1wByuD52UxWRLy8pu+kRMniEi6Eq9Zg==",
|
||||
"version": "0.2.17",
|
||||
"resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.17.tgz",
|
||||
"integrity": "sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
|
|
@ -4372,17 +4372,17 @@
|
|||
}
|
||||
},
|
||||
"node_modules/vite": {
|
||||
"version": "8.0.14",
|
||||
"resolved": "https://registry.npmjs.org/vite/-/vite-8.0.14.tgz",
|
||||
"integrity": "sha512-s4BJJ+5y1pYL6Otw51FHhVJQhPnuRinKig64g/1+EUNaJsd3gCKdD31IPFvswUgW9/60QT9oFHbZHbQK5imcxw==",
|
||||
"version": "8.0.16",
|
||||
"resolved": "https://registry.npmjs.org/vite/-/vite-8.0.16.tgz",
|
||||
"integrity": "sha512-h9bXPmJichP5fLmVQo3PyaGSDE2n3aPuomeAlVRm0JLmt4rY6zmPKd59HYI4LNW8oTK7tlTsuC7l/m7awx9Jcw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"lightningcss": "^1.32.0",
|
||||
"picomatch": "^4.0.4",
|
||||
"postcss": "^8.5.15",
|
||||
"rolldown": "1.0.2",
|
||||
"tinyglobby": "^0.2.16"
|
||||
"rolldown": "1.0.3",
|
||||
"tinyglobby": "^0.2.17"
|
||||
},
|
||||
"bin": {
|
||||
"vite": "bin/vite.js"
|
||||
|
|
|
|||
|
|
@ -9,7 +9,6 @@
|
|||
"dev": "vite",
|
||||
"build": "npm install && npm run build:vite",
|
||||
"build:vite": "vite build",
|
||||
"i18n:to-rust": "node scripts/i18next-to-rust-i18n.mjs",
|
||||
"format": "biome format",
|
||||
"check": "biome check",
|
||||
"lint": "tsc && biome lint"
|
||||
|
|
@ -32,7 +31,7 @@
|
|||
"@radix-ui/react-slot": "^1",
|
||||
"@radix-ui/react-tooltip": "^1",
|
||||
"@tanstack/react-query": "^5",
|
||||
"@tanstack/react-router": "^1.170.8",
|
||||
"@tanstack/react-router": "^1.170.10",
|
||||
"@tanstack/router-devtools": "^1.167.0",
|
||||
"@tauri-apps/api": "2.11.0",
|
||||
"@uidotdev/usehooks": "^2",
|
||||
|
|
@ -42,25 +41,25 @@
|
|||
"cmdk": "^1",
|
||||
"i18next": "^26",
|
||||
"lucide-react": "^1",
|
||||
"react": "19.2.6",
|
||||
"react-dom": "19.2.6",
|
||||
"react": "19.2.7",
|
||||
"react-dom": "19.2.7",
|
||||
"react-i18next": "^17",
|
||||
"react-toastify": "^11",
|
||||
"tailwind-merge": "^3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@biomejs/biome": "^2",
|
||||
"@rollup/pluginutils": "^5.3.0",
|
||||
"@rollup/pluginutils": "^5.4.0",
|
||||
"@tailwindcss/vite": "^4.3.0",
|
||||
"@tanstack/router-plugin": "^1.168.11",
|
||||
"@tanstack/router-plugin": "^1.168.13",
|
||||
"@tauri-apps/cli": "2.11.2",
|
||||
"@types/node": "^20",
|
||||
"@types/react": "19.2.15",
|
||||
"@types/react": "19.2.16",
|
||||
"@types/react-dom": "19.2.3",
|
||||
"@vitejs/plugin-react": "^6.0.2",
|
||||
"json5": "^2",
|
||||
"tw-animate-css": "^1.4.0",
|
||||
"typescript": "~6.0",
|
||||
"vite": "^8.0.14"
|
||||
"vite": "^8.0.16"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,49 +0,0 @@
|
|||
#!/usr/bin/env node
|
||||
|
||||
import { readFile, writeFile } from "node:fs/promises";
|
||||
import path from "node:path";
|
||||
import JSON5 from "json5";
|
||||
|
||||
function toYaml(value, indent = 0) {
|
||||
const pad = " ".repeat(indent);
|
||||
if (typeof value !== "object" || value === null || Array.isArray(value)) {
|
||||
return `${JSON.stringify(String(value))}`;
|
||||
}
|
||||
|
||||
return Object.entries(value)
|
||||
.map(([key, child]) => {
|
||||
const escapedKey = `'${key.replaceAll("'", "''")}'`;
|
||||
if (typeof child === "object" && child !== null && !Array.isArray(child)) {
|
||||
const nested = toYaml(child, indent + 1);
|
||||
return `${pad}${escapedKey}:\n${nested}`;
|
||||
}
|
||||
return `${pad}${escapedKey}: ${JSON.stringify(String(child))}`;
|
||||
})
|
||||
.join("\n");
|
||||
}
|
||||
|
||||
async function main() {
|
||||
const inputPath = process.argv[2] ?? "locales/en.json5";
|
||||
const outputPath =
|
||||
process.argv[3] ??
|
||||
path.join(
|
||||
path.dirname(inputPath),
|
||||
`${path.basename(inputPath, path.extname(inputPath))}.yml`,
|
||||
);
|
||||
|
||||
const source = await readFile(inputPath, "utf8");
|
||||
const parsed = JSON5.parse(source);
|
||||
const translationRoot = parsed.translation ?? parsed;
|
||||
if (typeof translationRoot !== "object" || translationRoot === null) {
|
||||
throw new Error("Expected object at root or translation");
|
||||
}
|
||||
|
||||
const yaml = `${toYaml(translationRoot)}\n`;
|
||||
await writeFile(outputPath, yaml, "utf8");
|
||||
console.log(`Converted ${inputPath} -> ${outputPath}`);
|
||||
}
|
||||
|
||||
main().catch((error) => {
|
||||
console.error(error);
|
||||
process.exitCode = 1;
|
||||
});
|
||||
|
|
@ -148,6 +148,7 @@ pub(crate) fn handlers() -> impl Fn(Invoke) -> bool + Send + Sync + 'static {
|
|||
project::project_set_unity_path,
|
||||
util::util_open,
|
||||
util::util_open_url,
|
||||
util::util_open_url_nocheck,
|
||||
util::util_get_log_entries,
|
||||
util::util_get_version,
|
||||
util::util_check_for_update,
|
||||
|
|
@ -257,6 +258,7 @@ pub(crate) fn export_ts() {
|
|||
project::project_set_unity_path,
|
||||
util::util_open,
|
||||
util::util_open_url,
|
||||
util::util_open_url_nocheck,
|
||||
util::util_get_log_entries,
|
||||
util::util_get_version,
|
||||
util::util_check_for_update,
|
||||
|
|
@ -506,6 +508,10 @@ struct TauriBasePackageInfo {
|
|||
is_yanked: bool,
|
||||
}
|
||||
|
||||
fn safe_url(url: &url::Url) -> bool {
|
||||
matches!(url.scheme(), "http" | "https")
|
||||
}
|
||||
|
||||
impl TauriBasePackageInfo {
|
||||
fn new(package: &PackageManifest) -> Self {
|
||||
Self {
|
||||
|
|
@ -517,8 +523,14 @@ impl TauriBasePackageInfo {
|
|||
.collect(),
|
||||
version: package.version().into(),
|
||||
unity: package.unity().map(|v| (v.major(), v.minor())),
|
||||
changelog_url: package.changelog_url().map(|v| v.to_string()),
|
||||
documentation_url: package.documentation_url().map(|v| v.to_string()),
|
||||
changelog_url: package
|
||||
.changelog_url()
|
||||
.take_if(|x| safe_url(x))
|
||||
.map(|v| v.to_string()),
|
||||
documentation_url: package
|
||||
.documentation_url()
|
||||
.take_if(|x| safe_url(x))
|
||||
.map(|v| v.to_string()),
|
||||
vpm_dependencies: package
|
||||
.vpm_dependencies()
|
||||
.keys()
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ use std::path::Path;
|
|||
use crate::commands::async_command::{AsyncCallResult, With, async_command};
|
||||
use crate::commands::environment::settings::TauriPickProjectDefaultPathResult;
|
||||
use crate::commands::prelude::*;
|
||||
use crate::commands::safe_url;
|
||||
use crate::logging::LogEntry;
|
||||
use crate::os::open_that;
|
||||
use crate::updater::{self, Update};
|
||||
|
|
@ -42,9 +43,19 @@ pub async fn util_open(path: String, if_not_exists: OpenOptions) -> Result<(), R
|
|||
Ok(())
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
#[specta::specta]
|
||||
pub async fn util_open_url_nocheck(url: String) -> Result<(), RustError> {
|
||||
open_that(url)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
#[specta::specta]
|
||||
pub async fn util_open_url(url: String) -> Result<(), RustError> {
|
||||
if !Url::parse(&url).is_ok_and(|x| safe_url(&x)) {
|
||||
return Err(RustError::unrecoverable_str("Bad URL or bad scheme"));
|
||||
}
|
||||
open_that(url)?;
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,8 +22,6 @@ ureq = { version = "3.3.0", features = ["gzip", "native-tls"], default-features
|
|||
flate2 = "1.1.1"
|
||||
tar = { version = "0.4.46", features = [], default-features = false }
|
||||
plist = "1.9.0"
|
||||
rpm = { version = "0.24.0", default-features = false, features = ["gzip-compression", "payload"] }
|
||||
ar = "0.9.0"
|
||||
fs_extra = "1.3.0"
|
||||
base64 = "0.22.1"
|
||||
minisign = "0.9.1"
|
||||
|
|
|
|||
|
|
@ -1,14 +1,12 @@
|
|||
use crate::utils::{self, build_dir, build_target, target_os};
|
||||
use anyhow::{Context, Result};
|
||||
use anyhow::{Context, Result, bail};
|
||||
use std::fs;
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
mod app;
|
||||
mod appimage;
|
||||
mod deb;
|
||||
mod dmg;
|
||||
mod linux;
|
||||
mod rpm;
|
||||
mod setup_exe;
|
||||
|
||||
/// Individual bundle artifact that can be produced.
|
||||
|
|
@ -52,16 +50,18 @@ pub(crate) enum BundleKind {
|
|||
///
|
||||
/// Unlike dmg depends on app, deb/rpm doesn't depend on this bundle.
|
||||
Buildroot,
|
||||
/// Debian package
|
||||
Deb,
|
||||
/// RPM package
|
||||
Rpm,
|
||||
/// Windows setup.exe
|
||||
SetupExe,
|
||||
/// Windows setup.exe in zip (requires setup.exe to already exist in bundle dir)
|
||||
SetupExeZip,
|
||||
/// Windows setup.exe for updater
|
||||
ExeUpdater,
|
||||
|
||||
// deleted
|
||||
#[value(hide = true)]
|
||||
Deb,
|
||||
#[value(hide = true)]
|
||||
Rpm,
|
||||
}
|
||||
|
||||
/// Bundles the ALCOM application for the target platform.
|
||||
|
|
@ -113,6 +113,12 @@ impl crate::Command for Command {
|
|||
|
||||
let bundles = self.bundles.as_slice();
|
||||
|
||||
if bundles.contains(&BundleKind::Deb) || bundles.contains(&BundleKind::Rpm) {
|
||||
bail!(
|
||||
"--bundles deb and --bundles rpm are removed. Please use native packaging configuration at vrc-get-gui/bundles"
|
||||
)
|
||||
}
|
||||
|
||||
if bundles.is_empty() {
|
||||
println!("Note: no bundles are specified");
|
||||
}
|
||||
|
|
@ -141,14 +147,6 @@ impl crate::Command for Command {
|
|||
linux::create_install_build_root(&ctx, self.buildroot.as_deref())?;
|
||||
}
|
||||
|
||||
if bundles.contains(&BundleKind::Deb) {
|
||||
deb::create_deb(&ctx)?;
|
||||
}
|
||||
|
||||
if bundles.contains(&BundleKind::Rpm) {
|
||||
rpm::create_rpm(&ctx)?;
|
||||
}
|
||||
|
||||
if bundles.contains(&BundleKind::SetupExe) {
|
||||
setup_exe::create_setup_exe(&ctx)?;
|
||||
}
|
||||
|
|
@ -214,14 +212,6 @@ impl<'a> BundleContext<'a> {
|
|||
self.version.as_str()
|
||||
}
|
||||
|
||||
pub fn short_description(&self) -> &str {
|
||||
"ALCOM - Alternative Creator Companion"
|
||||
}
|
||||
|
||||
pub fn long_description(&self) -> &str {
|
||||
"ALCOM is a fast and open-source alternative VCC (VRChat Creator Companion) written in rust and tauri."
|
||||
}
|
||||
|
||||
/// Binary name without extension (e.g. `ALCOM`).
|
||||
pub fn binary_name(&self) -> &str {
|
||||
"ALCOM"
|
||||
|
|
|
|||
|
|
@ -1,108 +0,0 @@
|
|||
use crate::bundle_alcom::BundleContext;
|
||||
use crate::bundle_alcom::linux::*;
|
||||
use crate::utils::tar::TarBuilderExt;
|
||||
use crate::utils::{CountingIo, tar, target_arch};
|
||||
use anyhow::{Context, Result, bail};
|
||||
use flate2::Compression;
|
||||
use flate2::write::GzEncoder;
|
||||
use std::io::Write;
|
||||
use std::{fs, io};
|
||||
|
||||
fn deb_arch(triple: &str) -> Result<&str> {
|
||||
match target_arch(triple) {
|
||||
"aarch64" => Ok("arm64"),
|
||||
"x86_64" => Ok("amd64"),
|
||||
_ => {
|
||||
bail!(
|
||||
"unsupported architecture in target triple for deb: {}",
|
||||
triple
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn create_deb(ctx: &BundleContext<'_>) -> Result<()> {
|
||||
let arch = deb_arch(ctx.target_tuple)?;
|
||||
let pkg_name = format!("alcom_{}-1_{arch}", ctx.version());
|
||||
|
||||
let (estimated_size, data_tar_gz) = {
|
||||
let gz = GzEncoder::new(Vec::new(), Compression::default());
|
||||
let mut tar = tar::Builder::new(CountingIo::new(gz));
|
||||
|
||||
create_install_build_root_impl(ctx, &mut tar).context("creating data.tar.gz")?;
|
||||
|
||||
let finished_gz_count = tar.into_inner()?;
|
||||
let estimated_size = finished_gz_count.count();
|
||||
let finished_gz = finished_gz_count.into_inner();
|
||||
let data_tar_gz = finished_gz.finish().context("finishing data.tar.gz")?;
|
||||
|
||||
(estimated_size, data_tar_gz)
|
||||
};
|
||||
|
||||
let library = detect_library_versions(&ctx.binary_path())?;
|
||||
|
||||
// Build control.tar.gz
|
||||
let control_tar_gz = {
|
||||
let mut control_tar_gz = Vec::new();
|
||||
let gz = GzEncoder::new(&mut control_tar_gz, Compression::best());
|
||||
let mut tar = tar::Builder::new(gz);
|
||||
|
||||
let control = {
|
||||
let template_path = ctx.gui_dir.join("bundle/deb-control");
|
||||
fs::read_to_string(&template_path)
|
||||
.with_context(|| format!("reading {}", template_path.display()))?
|
||||
.replace("{{version}}", ctx.version())
|
||||
.replace("{{arch}}", arch)
|
||||
.replace("{{estimated_size}}", &(estimated_size / 1024).to_string())
|
||||
.replace("{{libc_version}}", &library.libc)
|
||||
.replace("{{libgcc_version}}", &library.libgcc)
|
||||
};
|
||||
|
||||
tar.append_file_data(0o644, "control", io::Cursor::new(control.as_bytes()))
|
||||
.context("appending control file")?;
|
||||
|
||||
let gz = tar.into_inner().context("finishing control tar")?;
|
||||
gz.finish().context("finishing control gzip")?;
|
||||
|
||||
control_tar_gz
|
||||
};
|
||||
|
||||
// Assemble .deb as an ar archive.
|
||||
let deb_dir = ctx.bundle_dir.join("deb");
|
||||
fs::create_dir_all(&deb_dir)?;
|
||||
let deb_name = format!("{pkg_name}.deb");
|
||||
let deb_out = deb_dir.join(&deb_name);
|
||||
|
||||
{
|
||||
let deb_file = fs::File::create(&deb_out)
|
||||
.with_context(|| format!("creating {}", deb_out.display()))?;
|
||||
let mut builder = ar::Builder::new(deb_file);
|
||||
|
||||
// debian-binary
|
||||
let debian_binary = b"2.0\n";
|
||||
let mut header = ar::Header::new(b"debian-binary".to_vec(), debian_binary.len() as u64);
|
||||
header.set_mode(0o100644);
|
||||
builder
|
||||
.append(&header, &mut debian_binary.as_slice())
|
||||
.context("appending debian-binary")?;
|
||||
|
||||
// control.tar.gz
|
||||
let mut header = ar::Header::new(b"control.tar.gz".to_vec(), control_tar_gz.len() as u64);
|
||||
header.set_mode(0o100644);
|
||||
builder
|
||||
.append(&header, &mut control_tar_gz.as_slice())
|
||||
.context("appending control.tar.gz")?;
|
||||
|
||||
// data.tar.gz
|
||||
let mut header = ar::Header::new(b"data.tar.gz".to_vec(), data_tar_gz.len() as u64);
|
||||
header.set_mode(0o100644);
|
||||
builder
|
||||
.append(&header, &mut data_tar_gz.as_slice())
|
||||
.context("appending data.tar.gz")?;
|
||||
|
||||
builder.into_inner()?.flush()?;
|
||||
}
|
||||
|
||||
println!("created: {}", deb_out.display());
|
||||
Ok(())
|
||||
}
|
||||
|
|
@ -1,7 +1,5 @@
|
|||
use super::BundleContext;
|
||||
use crate::utils::tar::TarBuilderExt;
|
||||
use anyhow::{Context, Result, bail};
|
||||
use std::collections::HashMap;
|
||||
use anyhow::{Context, Result};
|
||||
use std::path::Path;
|
||||
use std::{fs, io};
|
||||
|
||||
|
|
@ -114,6 +112,7 @@ impl<'a> BuildRootFs for RealBuildRootFs<'a> {
|
|||
}
|
||||
|
||||
fn create_file(&mut self, mode: u32, relative: &str, data: &mut dyn io::Read) -> Result<()> {
|
||||
let _ = mode; // suppress warning on windows
|
||||
let path = &self.0.join(relative);
|
||||
std::io::copy(
|
||||
data,
|
||||
|
|
@ -132,37 +131,6 @@ impl<'a> BuildRootFs for RealBuildRootFs<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<W: io::Write> BuildRootFs for tar::Builder<W> {
|
||||
fn create_dir(&mut self, path: &str) -> Result<()> {
|
||||
self.append_directory(path)
|
||||
}
|
||||
|
||||
fn create_file(&mut self, mode: u32, path: &str, data: &mut dyn io::Read) -> Result<()> {
|
||||
self.append_file_data(mode, path, data)
|
||||
}
|
||||
}
|
||||
|
||||
impl BuildRootFs for rpm::PackageBuilder {
|
||||
fn create_dir(&mut self, path: &str) -> Result<()> {
|
||||
self.with_dir_entry(rpm::FileOptions::dir(format!("/{path}")))
|
||||
.map(|_| ())
|
||||
.with_context(|| format!("creating directory {}", path))
|
||||
}
|
||||
|
||||
fn create_file(&mut self, mode: u32, path: &str, data: &mut dyn io::Read) -> Result<()> {
|
||||
let mut contents = vec![];
|
||||
data.read_to_end(&mut contents)
|
||||
.with_context(|| format!("reading data for {}", path))?;
|
||||
|
||||
self.with_file_contents(
|
||||
contents,
|
||||
rpm::FileOptions::new(format!("/{path}")).permissions(mode as u16),
|
||||
)
|
||||
.map(|_| ())
|
||||
.with_context(|| format!("creating file {}", path))
|
||||
}
|
||||
}
|
||||
|
||||
/// Render the desktop file template from `alcom.desktop`.
|
||||
///
|
||||
/// The template uses `{{key}}` placeholders as in the tauri bundler.
|
||||
|
|
@ -177,134 +145,3 @@ pub fn render_desktop_file(ctx: &BundleContext<'_>, exec: &str) -> Result<String
|
|||
pub static LINUX_ICON_RESOLUTIONS: &[&str] = &["32x32", "64x64", "128x128"];
|
||||
|
||||
pub static LINUX_ICON_NAME: &str = "alcom"; // keep in sync with alcom.desktop template
|
||||
|
||||
pub struct LibraryVersions {
|
||||
pub libc: String,
|
||||
pub libgcc: String,
|
||||
}
|
||||
|
||||
pub fn detect_library_versions(path: &Path) -> Result<LibraryVersions> {
|
||||
use object::read::elf::ElfFile64;
|
||||
use object::{Endianness, Object, ObjectSymbol};
|
||||
|
||||
let binary = fs::read(path).context("Reading binary")?;
|
||||
|
||||
let elf = ElfFile64::<Endianness>::parse(&binary).context("failed to parse binary")?;
|
||||
|
||||
let Some(versions) = elf.elf_section_table().versions(elf.endian(), elf.data())? else {
|
||||
bail!("no version table found");
|
||||
};
|
||||
let versions = elf
|
||||
.dynamic_symbols()
|
||||
.map(|s| versions.version_index(elf.endian(), s.index()))
|
||||
.flat_map(|i| versions.version(i).transpose())
|
||||
.collect::<Result<Vec<_>, _>>()?;
|
||||
|
||||
let mut by_lib = HashMap::new();
|
||||
for version in versions.into_iter() {
|
||||
let lib = version.name().split(|&x| x == b'_').next().unwrap();
|
||||
let version_name = version.name();
|
||||
let version_str = version_name
|
||||
.split(|&x| x == b'_')
|
||||
.nth(1)
|
||||
.unwrap_or(version_name);
|
||||
|
||||
if !matches!(version_str.first(), Some(c) if c.is_ascii_digit()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
let version = VersionNumber::try_from(version_name).with_context(|| {
|
||||
format!(
|
||||
"failed to parse symbol version '{}' in {}",
|
||||
String::from_utf8_lossy(version_name),
|
||||
path.display()
|
||||
)
|
||||
})?;
|
||||
|
||||
let existing = by_lib.entry(lib).or_insert(VersionNumber::MIN);
|
||||
if *existing < version {
|
||||
*existing = version;
|
||||
}
|
||||
}
|
||||
|
||||
//for (lib, version) in &by_lib {
|
||||
// let lib = std::str::from_utf8(lib)?;
|
||||
// println!("{lib}: {version}");
|
||||
//}
|
||||
|
||||
return Ok(LibraryVersions {
|
||||
libc: by_lib
|
||||
.get(&b"GLIBC"[..])
|
||||
.context("no numeric GLIBC version requirement found in dynamic symbols")?
|
||||
.to_string(),
|
||||
libgcc: by_lib
|
||||
.get(&b"GCC"[..])
|
||||
.context("no numeric GCC version requirement found in dynamic symbols")?
|
||||
.to_string(),
|
||||
});
|
||||
|
||||
struct VersionNumber(String, Vec<u32>);
|
||||
|
||||
impl VersionNumber {
|
||||
pub const MIN: VersionNumber = VersionNumber(String::new(), Vec::new());
|
||||
}
|
||||
|
||||
impl<'a> TryFrom<&'a [u8]> for VersionNumber {
|
||||
type Error = anyhow::Error;
|
||||
|
||||
fn try_from(value: &'a [u8]) -> std::result::Result<Self, Self::Error> {
|
||||
let value = if let Some(index) = value.iter().position(|&x| x == b'_') {
|
||||
value.split_at(index + 1).1
|
||||
} else {
|
||||
value
|
||||
};
|
||||
let value = std::str::from_utf8(value)?;
|
||||
let components = value
|
||||
.split(['.', '_'])
|
||||
.map(std::str::FromStr::from_str)
|
||||
.collect::<Result<Vec<_>, _>>()?;
|
||||
Ok(Self(value.to_string(), components))
|
||||
}
|
||||
}
|
||||
|
||||
impl Ord for VersionNumber {
|
||||
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
|
||||
self.1.cmp(&other.1)
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq for VersionNumber {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.cmp(other).is_eq()
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialOrd for VersionNumber {
|
||||
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
|
||||
Some(self.cmp(other))
|
||||
}
|
||||
}
|
||||
|
||||
impl Eq for VersionNumber {}
|
||||
|
||||
impl std::fmt::Display for VersionNumber {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
if f.alternate() {
|
||||
let mut iter = self.1.iter();
|
||||
f.write_fmt(format_args!("{}", iter.next().unwrap()))?;
|
||||
for x in iter {
|
||||
f.write_fmt(format_args!(".{}", x))?;
|
||||
}
|
||||
Ok(())
|
||||
} else {
|
||||
f.write_str(&self.0)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Debug for VersionNumber {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
std::fmt::Display::fmt(self, f)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,63 +0,0 @@
|
|||
use super::BundleContext;
|
||||
use crate::bundle_alcom::linux::*;
|
||||
use anyhow::{Context, Result};
|
||||
use rpm::Dependency;
|
||||
use std::fs;
|
||||
|
||||
pub fn create_rpm(ctx: &BundleContext<'_>) -> Result<()> {
|
||||
let arch = rpm_arch(ctx.target_tuple);
|
||||
let rpm_name = format!("alcom-{}-1.{arch}.rpm", ctx.version());
|
||||
let rpm_dir = ctx.bundle_dir.join("rpm");
|
||||
fs::create_dir_all(&rpm_dir)?;
|
||||
let rpm_out = rpm_dir.join(&rpm_name);
|
||||
|
||||
let library = detect_library_versions(&ctx.binary_path())?;
|
||||
|
||||
let mut builder = rpm::PackageBuilder::new(
|
||||
"alcom",
|
||||
// RPM doesn't support '-' in their version name.
|
||||
// It's recommended to use '~' instead.
|
||||
// https://docs.fedoraproject.org/en-US/packaging-guidelines/Versioning/#_handling_non_sorting_versions_with_tilde_dot_and_caret
|
||||
&ctx.version().replace('-', "~"),
|
||||
"MIT",
|
||||
arch,
|
||||
ctx.short_description(),
|
||||
);
|
||||
builder.release("1").description(ctx.long_description());
|
||||
|
||||
builder.requires(Dependency::any(format!(
|
||||
"libgcc_s.so.1(GCC_{})(64bit)",
|
||||
library.libgcc
|
||||
)));
|
||||
builder.requires(Dependency::any(format!(
|
||||
"libc.so.6(GLIBC_{})(64bit)",
|
||||
library.libc
|
||||
)));
|
||||
builder.requires(Dependency::any("libgtk-3.so.0()(64bit)"));
|
||||
builder.requires(Dependency::any("libwebkit2gtk-4.1.so.0()(64bit)"));
|
||||
|
||||
// Binary.
|
||||
create_install_build_root_impl(ctx, &mut builder).context("adding files to rpm")?;
|
||||
|
||||
let pkg = builder.build().context("building rpm package")?;
|
||||
|
||||
pkg.write_file(&rpm_out)
|
||||
.with_context(|| format!("writing {}", rpm_out.display()))?;
|
||||
|
||||
println!("created: {}", rpm_out.display());
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// RPM architecture string.
|
||||
fn rpm_arch(triple: &str) -> &str {
|
||||
if triple.starts_with("aarch64") {
|
||||
"aarch64"
|
||||
} else if triple.starts_with("x86_64") {
|
||||
"x86_64"
|
||||
} else {
|
||||
panic!(
|
||||
"unsupported architecture in target triple for rpm: {}",
|
||||
triple
|
||||
)
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue