Compare commits

..

1 commit

Author SHA1 Message Date
dependabot[bot]
5348afd33a
chore(deps): bump yoke from 0.8.2 to 0.8.3
Bumps [yoke](https://github.com/unicode-org/icu4x) from 0.8.2 to 0.8.3.
- [Release notes](https://github.com/unicode-org/icu4x/releases)
- [Changelog](https://github.com/unicode-org/icu4x/blob/main/CHANGELOG.md)
- [Commits](https://github.com/unicode-org/icu4x/commits/ind/yoke@0.8.3)

---
updated-dependencies:
- dependency-name: yoke
  dependency-version: 0.8.3
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-06-08 07:43:24 +00:00
29 changed files with 604 additions and 740 deletions

View file

@ -16,7 +16,7 @@ jobs:
include:
- triple: x86_64-unknown-linux-gnu
on: ubuntu-22.04
bundles: appimage,appimage-updater
bundles: appimage,appimage-updater,deb,rpm
setup: |
sudo apt update && sudo apt install -y lld
ld.lld --version
@ -122,195 +122,6 @@ 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() }}

View file

@ -67,21 +67,6 @@ 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-*"
@ -96,7 +81,7 @@ jobs:
;;
esac
gh-export-variable GUI_VERSION "${GUI_VERSION}"
gh-export-variable GUI_VERSION "$(get-version -t gui)"
env:
RELEASE_KIND_IN: ${{ inputs.release_kind }}
DRY_RUN: ${{ inputs.dry-run }}
@ -167,6 +152,21 @@ 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,6 +196,8 @@ 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
@ -309,149 +311,6 @@ 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 ]
@ -488,7 +347,7 @@ jobs:
permissions:
contents: write
runs-on: ubuntu-latest
needs: [ pre-build, build-rust, build-rpm, build-deb, build-updater-json ]
needs: [ pre-build, build-rust, build-updater-json ]
env:
GUI_VERSION: ${{ needs.pre-build.outputs.gui-version }}
steps:

View file

@ -8,7 +8,6 @@ The format is based on [Keep a Changelog].
## [Unreleased]
### Added
- Implement project sorting by creation date `#2941`
### Changed

197
Cargo.lock generated
View file

@ -112,6 +112,12 @@ version = "1.0.102"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7f202df86484c868dbad7eaa557ef785d5c66295e41b460ef922eca0723b842c"
[[package]]
name = "ar"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d67af77d68a931ecd5cbd8a3b5987d63a1d1d1278f7f6a60ae33db485cdebb69"
[[package]]
name = "arc-swap"
version = "1.9.1"
@ -764,7 +770,7 @@ version = "0.3.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "692186b5ebe54007e45a59aea47ece9eb4108e141326c304cdc91699a7118a22"
dependencies = [
"nom",
"nom 7.1.3",
"proc-macro2",
"quote",
"syn 2.0.117",
@ -1349,6 +1355,17 @@ version = "1.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "66b7e2430c6dff6a955451e2cfc438f09cea1965a9d6f87f7e3b90decc014099"
[[package]]
name = "enum-display-derive"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f16ef37b2a9b242295d61a154ee91ae884afff6b8b933b486b12481cc58310ca"
dependencies = [
"proc-macro2",
"quote",
"syn 1.0.109",
]
[[package]]
name = "enum-map"
version = "2.7.3"
@ -1369,6 +1386,17 @@ dependencies = [
"syn 2.0.117",
]
[[package]]
name = "enum-primitive-derive"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ba7795da175654fe16979af73f81f26a8ea27638d8d9823d317016888a63dc4c"
dependencies = [
"num-traits",
"quote",
"syn 2.0.117",
]
[[package]]
name = "enumflags2"
version = "0.7.12"
@ -1511,6 +1539,7 @@ checksum = "843fba2746e448b37e26a819579957415c8cef339bf08564fe8b7ddbd959573c"
dependencies = [
"crc32fast",
"miniz_oxide",
"zlib-rs",
]
[[package]]
@ -2634,6 +2663,15 @@ dependencies = [
"serde_json",
]
[[package]]
name = "keccak"
version = "0.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cb26cec98cce3a3d96cbb7bced3c4b16e3d13f27ec56dbd62cbc8f39cfb9d653"
dependencies = [
"cpufeatures 0.2.17",
]
[[package]]
name = "keyboard-types"
version = "0.7.0"
@ -2983,6 +3021,15 @@ dependencies = [
"minimal-lexical",
]
[[package]]
name = "nom"
version = "8.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "df9761775871bdef83bee530e60050f7e54b1105350d6884eb0fb4f46c2f9405"
dependencies = [
"memchr",
]
[[package]]
name = "ntapi"
version = "0.4.3"
@ -2992,12 +3039,87 @@ dependencies = [
"winapi",
]
[[package]]
name = "num"
version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "35bd024e8b2ff75562e5f34e7f4905839deb4b22955ef5e73d2fea1b9813cb23"
dependencies = [
"num-bigint",
"num-complex",
"num-integer",
"num-iter",
"num-rational",
"num-traits",
]
[[package]]
name = "num-bigint"
version = "0.4.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9"
dependencies = [
"num-integer",
"num-traits",
]
[[package]]
name = "num-complex"
version = "0.4.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "73f88a1307638156682bada9d7604135552957b7818057dcef22705b4d509495"
dependencies = [
"num-traits",
]
[[package]]
name = "num-conv"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c6673768db2d862beb9b39a78fdcb1a69439615d5794a1be50caa9bc92c81967"
[[package]]
name = "num-derive"
version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ed3955f1a9c7c0c15e092f9c887db08b1fc683305fdf6eb6684f22555355e202"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.117",
]
[[package]]
name = "num-integer"
version = "0.1.46"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f"
dependencies = [
"num-traits",
]
[[package]]
name = "num-iter"
version = "0.1.45"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1429034a0490724d0075ebb2bc9e875d6503c3cf69e235a8941aa757d83ef5bf"
dependencies = [
"autocfg",
"num-integer",
"num-traits",
]
[[package]]
name = "num-rational"
version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f83d14da390562dca69fc84082e73e548e1ad308d24accdedd2720017cb37824"
dependencies = [
"num-bigint",
"num-integer",
"num-traits",
]
[[package]]
name = "num-traits"
version = "0.2.19"
@ -4286,6 +4408,40 @@ dependencies = [
"windows-sys 0.61.2",
]
[[package]]
name = "rpm"
version = "0.24.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a5f8c4a1267cbbad96d1e7bf080ca20c669df79f638ef4e6c5e05a38b5d32c96"
dependencies = [
"base64 0.22.1",
"bitflags 2.11.1",
"digest 0.10.7",
"enum-display-derive",
"enum-primitive-derive",
"flate2",
"hex",
"itertools",
"log",
"memchr",
"nom 8.0.0",
"num",
"num-derive",
"num-traits",
"rpm-version",
"sha1 0.10.6",
"sha2 0.10.9",
"sha3",
"thiserror 2.0.18",
"zeroize",
]
[[package]]
name = "rpm-version"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e9274efa3f2ce8fe60fd8ea005a49955f92ddd81643eb38084b8e2c6c507018f"
[[package]]
name = "rtoolbox"
version = "0.0.5"
@ -4766,6 +4922,17 @@ dependencies = [
"stable_deref_trait",
]
[[package]]
name = "sha1"
version = "0.10.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba"
dependencies = [
"cfg-if",
"cpufeatures 0.2.17",
"digest 0.10.7",
]
[[package]]
name = "sha1"
version = "0.11.0"
@ -4799,6 +4966,16 @@ dependencies = [
"digest 0.11.2",
]
[[package]]
name = "sha3"
version = "0.10.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "75872d278a8f37ef87fa0ddbda7802605cb18344497949862c0d4dcb291eba60"
dependencies = [
"digest 0.10.7",
"keccak",
]
[[package]]
name = "shlex"
version = "1.3.0"
@ -6152,9 +6329,9 @@ checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
[[package]]
name = "uuid"
version = "1.23.3"
version = "1.23.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "144d6b123cef80b301b8f72a9e2ca4370ddec21950d0a103dd22c437006d2db7"
checksum = "d258b83ceec21034727ecee8c382cfa6c3e133699b0742c64571814fb420c9f7"
dependencies = [
"getrandom 0.4.2",
"js-sys",
@ -6309,7 +6486,7 @@ dependencies = [
"serde_json",
"serde_path_to_error",
"serde_repr",
"sha1",
"sha1 0.11.0",
"sha2 0.11.0",
"tokio",
"tokio-util",
@ -7486,6 +7663,7 @@ name = "xtask"
version = "0.1.0"
dependencies = [
"anyhow",
"ar",
"base64 0.22.1",
"cargo_metadata 0.23.1",
"chrono",
@ -7497,6 +7675,7 @@ dependencies = [
"minisign",
"object 0.39.1",
"plist",
"rpm",
"serde",
"serde_json",
"tar",
@ -7506,9 +7685,9 @@ dependencies = [
[[package]]
name = "yoke"
version = "0.8.2"
version = "0.8.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "abe8c5fda708d9ca3df187cae8bfb9ceda00dd96231bed36e445a1a48e66f9ca"
checksum = "709fe23a0424b6a435d82152b1bd3fdfb0833487d5fa90d05d42762a9891fef5"
dependencies = [
"stable_deref_trait",
"yoke-derive",
@ -7681,6 +7860,12 @@ dependencies = [
"typed-path",
]
[[package]]
name = "zlib-rs"
version = "0.6.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3be3d40e40a133f9c916ee3f9f4fa2d9d63435b5fbe1bfc6d9dae0aa0ada1513"
[[package]]
name = "zmij"
version = "1.0.21"

View file

@ -29,11 +29,7 @@ import {
} from "@/components/ui/tooltip";
import type { TauriProject } from "@/lib/bindings";
import { commands } from "@/lib/bindings";
import {
dateToString,
dayToString,
formatDateOffset,
} from "@/lib/dateToString";
import { dateToString, formatDateOffset } from "@/lib/dateToString";
import { openSingleDialog } from "@/lib/dialog";
import { tc } from "@/lib/i18n";
import { toastThrownError } from "@/lib/toast";
@ -49,7 +45,7 @@ export function ProjectGridItem({
const typeIconClass = "w-5 h-5";
const { projectTypeKind, displayType, isLegacy, createdAt, lastModified } =
const { projectTypeKind, displayType, isLegacy, lastModified } =
getProjectDisplayInfo(project);
const removed = !project.is_exists;
@ -169,44 +165,22 @@ export function ProjectGridItem({
</div>
</div>
<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>
<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>
</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>
</time>
</TooltipTrigger>
<TooltipPortal>
<TooltipContent>
{dateToString(project.last_modified)}
</TooltipContent>
</TooltipPortal>
</Tooltip>
</div>
<div className="mt-2 flex flex-wrap gap-2 justify-end compact:gap-1">

View file

@ -29,11 +29,7 @@ import {
import { assertNever } from "@/lib/assert-never";
import type { TauriProject, TauriProjectType } from "@/lib/bindings";
import { commands } from "@/lib/bindings";
import {
dateToString,
dayToString,
formatDateOffset,
} from "@/lib/dateToString";
import { dateToString, formatDateOffset } from "@/lib/dateToString";
import { type DialogContext, openSingleDialog, showDialog } from "@/lib/dialog";
import { tc, tt } from "@/lib/i18n";
import { router } from "@/lib/main";
@ -82,7 +78,7 @@ export function ProjectRow({
const noGrowCellClass = `${cellClass} w-1`;
const typeIconClass = "w-5 h-5";
const { projectTypeKind, displayType, isLegacy, createdAt, lastModified } =
const { projectTypeKind, displayType, isLegacy, lastModified } =
getProjectDisplayInfo(project);
const openProjectFolder = () =>
@ -109,7 +105,7 @@ export function ProjectRow({
<tr
className={`group even:bg-secondary/30 ${removed || loading || !(project.is_valid ?? true) ? "opacity-50" : ""}`}
>
<td className={noGrowCellClass}>
<td className={`${cellClass} w-3`}>
<div className={"relative flex"}>
<FavoriteStarToggleButton
favorite={project.favorite}
@ -151,7 +147,7 @@ export function ProjectRow({
</TooltipPortal>
</Tooltip>
</td>
<td className={noGrowCellClass}>
<td className={`${cellClass} w-[8em] min-w-[8em]`}>
<div className="flex flex-row gap-2">
<div className="flex items-center">
{projectTypeKind === "avatars" ? (
@ -175,22 +171,6 @@ 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>
@ -521,14 +501,12 @@ 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,
};
}

View file

@ -30,7 +30,6 @@ 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" },
];

View file

@ -11,13 +11,7 @@ import { toastThrownError } from "@/lib/toast";
import { compareUnityVersionString } from "@/lib/version";
import { ProjectRow } from "./-project-row";
export const sortings = [
"createdAt",
"lastModified",
"name",
"unity",
"type",
] as const;
export const sortings = ["lastModified", "name", "unity", "type"] as const;
type SimpleSorting = (typeof sortings)[number];
type Sorting = SimpleSorting | `${SimpleSorting}Reversed`;
@ -164,18 +158,6 @@ 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"
@ -212,12 +194,6 @@ 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;

View file

@ -1,70 +0,0 @@
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

View file

@ -0,0 +1,10 @@
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.

View file

@ -1,7 +0,0 @@
/*-build-stamp
/*.substvars
/.debhelper
/files
/cargo_home
/npm_cache
alcom/

View file

@ -1,5 +0,0 @@
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

View file

@ -1,20 +0,0 @@
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

View file

@ -1,5 +0,0 @@
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

View file

@ -1,8 +0,0 @@
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/

View file

@ -1,29 +0,0 @@
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.

View file

@ -1,41 +0,0 @@
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

View file

@ -1,39 +0,0 @@
#!/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

View file

@ -1 +0,0 @@
3.0 (quilt)

View file

@ -1,24 +0,0 @@
# 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>

View file

@ -1,10 +0,0 @@
# 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@

View file

@ -1,16 +1,6 @@
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;

View file

@ -37,8 +37,6 @@
"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",

View file

@ -37,8 +37,6 @@
"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}}分前",

View file

@ -22,6 +22,8 @@ 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"

View file

@ -1,12 +1,14 @@
use crate::utils::{self, build_dir, build_target, target_os};
use anyhow::{Context, Result, bail};
use anyhow::{Context, Result};
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.
@ -50,18 +52,16 @@ 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,12 +113,6 @@ 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");
}
@ -147,6 +141,14 @@ 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)?;
}
@ -212,6 +214,14 @@ 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"

View file

@ -0,0 +1,108 @@
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(())
}

View file

@ -1,5 +1,7 @@
use super::BundleContext;
use anyhow::{Context, Result};
use crate::utils::tar::TarBuilderExt;
use anyhow::{Context, Result, bail};
use std::collections::HashMap;
use std::path::Path;
use std::{fs, io};
@ -112,7 +114,6 @@ 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,
@ -131,6 +132,37 @@ 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.
@ -145,3 +177,134 @@ 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)
}
}
}

View file

@ -0,0 +1,63 @@
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
)
}
}