mirror of
https://github.com/Drop-OSS/drop-app.git
synced 2025-11-13 16:22:43 +10:00
Compare commits
7 Commits
cloud-save
...
dev-v0.3.0
| Author | SHA1 | Date | |
|---|---|---|---|
| 7b443818d1 | |||
| fa4a881cc0 | |||
| 4f16a6e6b2 | |||
| 47d9e9949b | |||
| a643d6102b | |||
| a71ff160c2 | |||
| a53a566792 |
68
.github/workflows/release.yml
vendored
Normal file
68
.github/workflows/release.yml
vendored
Normal file
@ -0,0 +1,68 @@
|
||||
name: 'publish'
|
||||
|
||||
on:
|
||||
workflow_dispatch: {}
|
||||
release:
|
||||
types: [published]
|
||||
# This can be used to automatically publish nightlies at UTC nighttime
|
||||
# schedule:
|
||||
# - cron: "0 2 * * *" # run at 2 AM UTC
|
||||
|
||||
# This workflow will trigger on each push to the `release` branch to create or update a GitHub release, build your app, and upload the artifacts to the release.
|
||||
|
||||
jobs:
|
||||
publish-tauri:
|
||||
permissions:
|
||||
contents: write
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- platform: 'macos-latest' # for Arm based macs (M1 and above).
|
||||
args: '--target aarch64-apple-darwin'
|
||||
- platform: 'macos-latest' # for Intel based macs.
|
||||
args: '--target x86_64-apple-darwin'
|
||||
- platform: 'ubuntu-22.04' # for Tauri v1 you could replace this with ubuntu-20.04.
|
||||
args: ''
|
||||
- platform: 'windows-latest'
|
||||
args: ''
|
||||
|
||||
runs-on: ${{ matrix.platform }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: true
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: setup node
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: lts/*
|
||||
|
||||
- name: install Rust nightly
|
||||
uses: dtolnay/rust-toolchain@nightly
|
||||
with:
|
||||
# Those targets are only used on macos runners so it's in an `if` to slightly speed up windows and linux builds.
|
||||
targets: ${{ matrix.platform == 'macos-latest' && 'aarch64-apple-darwin,x86_64-apple-darwin' || '' }}
|
||||
|
||||
- name: install dependencies (ubuntu only)
|
||||
if: matrix.platform == 'ubuntu-22.04' # This must match the platform value defined above.
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y libwebkit2gtk-4.0-dev libwebkit2gtk-4.1-dev libappindicator3-dev librsvg2-dev patchelf
|
||||
# webkitgtk 4.0 is for Tauri v1 - webkitgtk 4.1 is for Tauri v2.
|
||||
# You can remove the one that doesn't apply to your app to speed up the workflow a bit.
|
||||
|
||||
- name: install frontend dependencies
|
||||
run: yarn install # change this to npm, pnpm or bun depending on which one you use.
|
||||
|
||||
- uses: tauri-apps/tauri-action@v0
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
with:
|
||||
tagName: dev-v__VERSION__ # the action automatically replaces \_\_VERSION\_\_ with the app version.
|
||||
releaseName: 'Auto-release v__VERSION__'
|
||||
releaseBody: 'See the assets to download this version and install. This release was created automatically.'
|
||||
releaseDraft: false
|
||||
prerelease: true
|
||||
args: ${{ matrix.args }}
|
||||
@ -99,11 +99,6 @@ function navigate(close: () => any, to: NavigationItem) {
|
||||
}
|
||||
|
||||
const navigation: NavigationItem[] = [
|
||||
{
|
||||
label: "Account settings",
|
||||
route: "/account",
|
||||
prefix: "",
|
||||
},
|
||||
{
|
||||
label: "App settings",
|
||||
route: "/settings",
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "drop-app",
|
||||
"private": true,
|
||||
"version": "0.2.0-beta",
|
||||
"version": "0.3.0-rc-1",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"build": "nuxt build",
|
||||
|
||||
@ -1,72 +0,0 @@
|
||||
<template>
|
||||
<div class="mx-auto max-w-7xl px-8">
|
||||
<div class="border-b border-zinc-700 py-5">
|
||||
<h3 class="text-base font-semibold font-display leading-6 text-zinc-100">
|
||||
Account
|
||||
</h3>
|
||||
</div>
|
||||
|
||||
<div class="mt-5">
|
||||
<div class="divide-y divide-zinc-700">
|
||||
<div class="py-6">
|
||||
<div class="flex flex-col gap-4">
|
||||
<div class="flex flex-row items-center justify-between">
|
||||
<div>
|
||||
<h3 class="text-sm font-medium leading-6 text-zinc-100">Sign out</h3>
|
||||
<p class="mt-1 text-sm leading-6 text-zinc-400">
|
||||
Sign out of your Drop account on this device
|
||||
</p>
|
||||
</div>
|
||||
<button
|
||||
@click="signOut"
|
||||
type="button"
|
||||
class="rounded-md bg-red-600 px-3 py-2 text-sm font-semibold text-white shadow-sm hover:bg-red-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-red-600"
|
||||
>
|
||||
Sign out
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div v-if="error" class="rounded-md bg-red-600/10 p-4">
|
||||
<div class="flex">
|
||||
<div class="flex-shrink-0">
|
||||
<XCircleIcon class="h-5 w-5 text-red-600" aria-hidden="true" />
|
||||
</div>
|
||||
<div class="ml-3">
|
||||
<h3 class="text-sm font-medium text-red-600">
|
||||
{{ error }}
|
||||
</h3>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { invoke } from "@tauri-apps/api/core";
|
||||
import { listen } from '@tauri-apps/api/event'
|
||||
import { useRouter } from '#imports'
|
||||
import { XCircleIcon } from "@heroicons/vue/16/solid";
|
||||
|
||||
const router = useRouter()
|
||||
const error = ref<string | null>(null)
|
||||
|
||||
// Listen for auth events
|
||||
onMounted(async () => {
|
||||
await listen('auth/signedout', () => {
|
||||
router.push('/auth/signedout')
|
||||
})
|
||||
})
|
||||
|
||||
async function signOut() {
|
||||
try {
|
||||
error.value = null
|
||||
await invoke('sign_out')
|
||||
} catch (e) {
|
||||
error.value = `Failed to sign out: ${e}`
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@ -156,9 +156,9 @@
|
||||
<template #default>
|
||||
<div class="sm:flex sm:items-start">
|
||||
<div class="mt-3 text-center sm:mt-0 sm:text-left">
|
||||
<DialogTitle as="h3" class="text-base font-semibold text-zinc-100"
|
||||
<h3 class="text-base font-semibold text-zinc-100"
|
||||
>Install {{ game.mName }}?
|
||||
</DialogTitle>
|
||||
</h3>
|
||||
<div class="mt-2">
|
||||
<p class="text-sm text-zinc-400">
|
||||
Drop will add {{ game.mName }} to the queue to be downloaded.
|
||||
|
||||
@ -45,6 +45,7 @@ import type { Component } from "vue";
|
||||
import type { NavigationItem } from "~/types";
|
||||
import { platform } from '@tauri-apps/plugin-os';
|
||||
import { invoke } from "@tauri-apps/api/core";
|
||||
import { UserIcon } from "@heroicons/vue/20/solid";
|
||||
|
||||
const systemData = await invoke<{
|
||||
clientId: string;
|
||||
@ -101,6 +102,12 @@ const navigation = computed(() => [
|
||||
prefix: "/settings/downloads",
|
||||
icon: ArrowDownTrayIcon,
|
||||
},
|
||||
{
|
||||
label: "Account",
|
||||
route: "/settings/account",
|
||||
prefix: "/settings/account",
|
||||
icon: UserIcon
|
||||
},
|
||||
...(isDebugMode.value ? [{
|
||||
label: "Debug Info",
|
||||
route: "/settings/debug",
|
||||
|
||||
64
pages/settings/account.vue
Normal file
64
pages/settings/account.vue
Normal file
@ -0,0 +1,64 @@
|
||||
<template>
|
||||
<div class="border-b border-zinc-700 py-5">
|
||||
<h3 class="text-base font-semibold font-display leading-6 text-zinc-100">
|
||||
General
|
||||
</h3>
|
||||
</div>
|
||||
|
||||
<div class="mt-5 flex flex-col gap-4">
|
||||
<div class="flex flex-row items-center justify-between">
|
||||
<div>
|
||||
<h3 class="text-sm font-medium leading-6 text-zinc-100">Sign out</h3>
|
||||
<p class="mt-1 text-sm leading-6 text-zinc-400">
|
||||
Sign out of your Drop account on this device
|
||||
</p>
|
||||
</div>
|
||||
<button
|
||||
@click="signOut"
|
||||
type="button"
|
||||
class="rounded-md bg-red-600 px-3 py-2 text-sm font-semibold text-white shadow-sm hover:bg-red-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-red-600"
|
||||
>
|
||||
Sign out
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div v-if="error" class="rounded-md bg-red-600/10 p-4">
|
||||
<div class="flex">
|
||||
<div class="flex-shrink-0">
|
||||
<XCircleIcon class="h-5 w-5 text-red-600" aria-hidden="true" />
|
||||
</div>
|
||||
<div class="ml-3">
|
||||
<h3 class="text-sm font-medium text-red-600">
|
||||
{{ error }}
|
||||
</h3>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { invoke } from "@tauri-apps/api/core";
|
||||
import { listen } from "@tauri-apps/api/event";
|
||||
import { useRouter } from "#imports";
|
||||
import { XCircleIcon } from "@heroicons/vue/16/solid";
|
||||
|
||||
const router = useRouter();
|
||||
const error = ref<string | null>(null);
|
||||
|
||||
// Listen for auth events
|
||||
onMounted(async () => {
|
||||
await listen("auth/signedout", () => {
|
||||
router.push("/auth/signedout");
|
||||
});
|
||||
});
|
||||
|
||||
async function signOut() {
|
||||
try {
|
||||
error.value = null;
|
||||
await invoke("sign_out");
|
||||
} catch (e) {
|
||||
error.value = `Failed to sign out: ${e}`;
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@ -1,8 +1,15 @@
|
||||
<template>
|
||||
<div>
|
||||
<div class="border-b border-zinc-600 py-2 px-1">
|
||||
<div class="border-b border-zinc-700 py-5">
|
||||
<h3 class="text-base font-semibold font-display leading-6 text-zinc-100">
|
||||
Downloads
|
||||
</h3>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="mt-5">
|
||||
<div class="border-b border-zinc-600">
|
||||
<div class="-ml-4 -mt-2 flex flex-wrap items-center justify-between sm:flex-nowrap">
|
||||
<div class="ml-4 mt-2">
|
||||
<div class="ml-4 mt-2 pb-4">
|
||||
<h3 class="text-base font-display font-semibold text-zinc-100">
|
||||
Install directories
|
||||
</h3>
|
||||
|
||||
@ -1,60 +1,59 @@
|
||||
<template>
|
||||
<div class="divide-y divide-zinc-700">
|
||||
<div class="py-6">
|
||||
<h2 class="text-base font-semibold font-display leading-7 text-zinc-100">General</h2>
|
||||
<p class="mt-1 text-sm leading-6 text-zinc-400">
|
||||
Configure basic application settings
|
||||
</p>
|
||||
<div class="border-b border-zinc-700 py-5">
|
||||
<h3 class="text-base font-semibold font-display leading-6 text-zinc-100">
|
||||
General
|
||||
</h3>
|
||||
</div>
|
||||
|
||||
<div class="mt-10 space-y-8">
|
||||
<div class="flex flex-row items-center justify-between">
|
||||
<div>
|
||||
<h3 class="text-sm font-medium leading-6 text-zinc-100">Start with system</h3>
|
||||
<p class="mt-1 text-sm leading-6 text-zinc-400">
|
||||
Drop will automatically start when you log into your computer
|
||||
</p>
|
||||
</div>
|
||||
<Switch
|
||||
v-model="autostartEnabled"
|
||||
:class="[
|
||||
autostartEnabled ? 'bg-blue-600' : 'bg-zinc-700',
|
||||
'relative inline-flex h-6 w-11 flex-shrink-0 cursor-pointer rounded-full border-2 border-transparent transition-colors duration-200 ease-in-out'
|
||||
]"
|
||||
>
|
||||
<span
|
||||
:class="[
|
||||
autostartEnabled ? 'translate-x-5' : 'translate-x-0',
|
||||
'pointer-events-none relative inline-block h-5 w-5 transform rounded-full bg-white shadow ring-0 transition duration-200 ease-in-out'
|
||||
]"
|
||||
/>
|
||||
</Switch>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mt-5 space-y-8">
|
||||
<div class="flex flex-row items-center justify-between">
|
||||
<div>
|
||||
<h3 class="text-sm font-medium leading-6 text-zinc-100">
|
||||
Start with system
|
||||
</h3>
|
||||
<p class="mt-1 text-sm leading-6 text-zinc-400">
|
||||
Drop will automatically start when you log into your computer
|
||||
</p>
|
||||
</div>
|
||||
<Switch
|
||||
v-model="autostartEnabled"
|
||||
:class="[
|
||||
autostartEnabled ? 'bg-blue-600' : 'bg-zinc-700',
|
||||
'relative inline-flex h-6 w-11 flex-shrink-0 cursor-pointer rounded-full border-2 border-transparent transition-colors duration-200 ease-in-out',
|
||||
]"
|
||||
>
|
||||
<span
|
||||
:class="[
|
||||
autostartEnabled ? 'translate-x-5' : 'translate-x-0',
|
||||
'pointer-events-none relative inline-block h-5 w-5 transform rounded-full bg-white shadow ring-0 transition duration-200 ease-in-out',
|
||||
]"
|
||||
/>
|
||||
</Switch>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { Switch } from '@headlessui/vue'
|
||||
import { Switch } from "@headlessui/vue";
|
||||
import { invoke } from "@tauri-apps/api/core";
|
||||
|
||||
defineProps<{}>()
|
||||
defineProps<{}>();
|
||||
|
||||
const autostartEnabled = ref<boolean>(false)
|
||||
const autostartEnabled = ref<boolean>(false);
|
||||
|
||||
// Load initial state
|
||||
invoke('get_autostart_enabled').then((enabled) => {
|
||||
autostartEnabled.value = enabled as boolean
|
||||
})
|
||||
invoke("get_autostart_enabled").then((enabled) => {
|
||||
autostartEnabled.value = enabled as boolean;
|
||||
});
|
||||
|
||||
// Watch for changes and update autostart
|
||||
watch(autostartEnabled, async (newValue: boolean) => {
|
||||
try {
|
||||
await invoke('toggle_autostart', { enabled: newValue })
|
||||
} catch (error) {
|
||||
console.error('Failed to toggle autostart:', error)
|
||||
// Revert the toggle if it failed
|
||||
autostartEnabled.value = !newValue
|
||||
}
|
||||
})
|
||||
</script>
|
||||
try {
|
||||
await invoke("toggle_autostart", { enabled: newValue });
|
||||
} catch (error) {
|
||||
console.error("Failed to toggle autostart:", error);
|
||||
// Revert the toggle if it failed
|
||||
autostartEnabled.value = !newValue;
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
475
src-tauri/Cargo.lock
generated
475
src-tauri/Cargo.lock
generated
@ -569,9 +569,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "bumpalo"
|
||||
version = "3.17.0"
|
||||
version = "3.16.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1628fb46dfa0b37568d12e5edd512553eccf6a22a78e8bde00bb4aed84d5bdbf"
|
||||
checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c"
|
||||
|
||||
[[package]]
|
||||
name = "byte-tools"
|
||||
@ -579,6 +579,12 @@ version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e3b5ca7a04898ad4bcd41c90c5285445ff5b791899bb1b0abdd2a2aa791211d7"
|
||||
|
||||
[[package]]
|
||||
name = "bytecount"
|
||||
version = "0.6.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5ce89b21cab1437276d2650d57e971f9d548a2d9037cc231abdc0562b97498ce"
|
||||
|
||||
[[package]]
|
||||
name = "bytemuck"
|
||||
version = "1.21.0"
|
||||
@ -692,6 +698,19 @@ dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cargo_metadata"
|
||||
version = "0.14.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4acbb09d9ee8e23699b9634375c72795d095bf268439da88562cf9b501f181fa"
|
||||
dependencies = [
|
||||
"camino",
|
||||
"cargo-platform",
|
||||
"semver",
|
||||
"serde",
|
||||
"serde_json",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cargo_metadata"
|
||||
version = "0.18.1"
|
||||
@ -722,8 +741,6 @@ version = "1.2.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1fcb57c740ae1daf453ae85f16e37396f672b039e00d9d866e07ddb24e328e3a"
|
||||
dependencies = [
|
||||
"jobserver",
|
||||
"libc",
|
||||
"shlex",
|
||||
]
|
||||
|
||||
@ -1158,6 +1175,15 @@ dependencies = [
|
||||
"crypto-common",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "directories"
|
||||
version = "5.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9a49173b84e034382284f27f1af4dcbbd231ffa358c0fe316541a7337f376a35"
|
||||
dependencies = [
|
||||
"dirs-sys 0.4.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "dirs"
|
||||
version = "4.0.0"
|
||||
@ -1176,15 +1202,6 @@ dependencies = [
|
||||
"dirs-sys 0.4.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "dirs"
|
||||
version = "6.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c3e8aa94d75141228480295a7d0e7feb620b1a5ad9f12bc40be62411e38cce4e"
|
||||
dependencies = [
|
||||
"dirs-sys 0.5.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "dirs-sys"
|
||||
version = "0.3.7"
|
||||
@ -1192,7 +1209,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1b1d1d91c932ef41c0f2663aa8b0ca0342d444d842c06914aa0a7e352d0bada6"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"redox_users 0.4.6",
|
||||
"redox_users",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
@ -1204,22 +1221,10 @@ checksum = "520f05a5cbd335fae5a99ff7a6ab8627577660ee5cfd6a94a6a929b52ff0321c"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"option-ext",
|
||||
"redox_users 0.4.6",
|
||||
"redox_users",
|
||||
"windows-sys 0.48.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "dirs-sys"
|
||||
version = "0.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e01a3366d27ee9890022452ee61b2b63a67e6f13f58900b651ff5665f0bb1fab"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"option-ext",
|
||||
"redox_users 0.5.0",
|
||||
"windows-sys 0.59.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "dispatch"
|
||||
version = "0.2.0"
|
||||
@ -1278,6 +1283,12 @@ dependencies = [
|
||||
"const-random",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "doc-comment"
|
||||
version = "0.3.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fea41bba32d969b513997752735605054bc0dfa92b4c56bf1189f2e174be7a10"
|
||||
|
||||
[[package]]
|
||||
name = "downcast-rs"
|
||||
version = "1.2.1"
|
||||
@ -1295,7 +1306,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "drop-app"
|
||||
version = "0.2.0-beta-prerelease-1"
|
||||
version = "0.3.0-rc-1"
|
||||
dependencies = [
|
||||
"atomic-instant-full",
|
||||
"bincode",
|
||||
@ -1303,36 +1314,31 @@ dependencies = [
|
||||
"cacache 13.1.0",
|
||||
"chrono",
|
||||
"deranged",
|
||||
"dirs 6.0.0",
|
||||
"directories",
|
||||
"droplet-rs",
|
||||
"dynfmt",
|
||||
"filetime",
|
||||
"gethostname 1.0.1",
|
||||
"hex 0.4.3",
|
||||
"http 1.2.0",
|
||||
"http-serde 2.1.1",
|
||||
"known-folders",
|
||||
"log",
|
||||
"log4rs",
|
||||
"md5",
|
||||
"native_db",
|
||||
"native_model 0.6.1",
|
||||
"parking_lot 0.12.3",
|
||||
"rand 0.9.1",
|
||||
"rayon",
|
||||
"regex",
|
||||
"reqwest 0.12.9",
|
||||
"reqwest-middleware 0.4.0",
|
||||
"reqwest-middleware-cache",
|
||||
"rustbreak",
|
||||
"rustix 0.38.42",
|
||||
"schemars",
|
||||
"serde",
|
||||
"serde-binary",
|
||||
"serde_json",
|
||||
"serde_with",
|
||||
"sha1",
|
||||
"shared_child",
|
||||
"slice-deque",
|
||||
"tar",
|
||||
"tauri",
|
||||
"tauri-build",
|
||||
"tauri-plugin-autostart",
|
||||
@ -1341,17 +1347,13 @@ dependencies = [
|
||||
"tauri-plugin-os",
|
||||
"tauri-plugin-shell",
|
||||
"tauri-plugin-single-instance",
|
||||
"tempfile",
|
||||
"throttle_my_fn",
|
||||
"tokio",
|
||||
"umu-wrapper-lib",
|
||||
"url",
|
||||
"urlencoding",
|
||||
"uuid",
|
||||
"walkdir",
|
||||
"webbrowser",
|
||||
"whoami",
|
||||
"zstd",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -1507,6 +1509,15 @@ dependencies = [
|
||||
"windows-sys 0.59.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "error-chain"
|
||||
version = "0.12.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2d2f06b9cac1506ece98fe3231e3cc9c4410ec3d5b1f24ae1c8946f0742cdefc"
|
||||
dependencies = [
|
||||
"version_check",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "event-listener"
|
||||
version = "2.5.3"
|
||||
@ -1565,18 +1576,6 @@ dependencies = [
|
||||
"rustc_version",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "filetime"
|
||||
version = "0.2.25"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "35c0522e981e68cbfa8c3f978441a5f34b30b96e146b33cd3359176b50fe8586"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"libredox",
|
||||
"windows-sys 0.59.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "flate2"
|
||||
version = "1.0.35"
|
||||
@ -1925,18 +1924,6 @@ dependencies = [
|
||||
"wasi 0.11.0+wasi-snapshot-preview1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "getrandom"
|
||||
version = "0.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "73fea8450eea4bac3940448fb7ae50d91f034f941199fcd9d909a5a07aa455f0"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"r-efi",
|
||||
"wasi 0.14.2+wasi-0.2.4",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gimli"
|
||||
version = "0.31.1"
|
||||
@ -2715,20 +2702,11 @@ version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130"
|
||||
|
||||
[[package]]
|
||||
name = "jobserver"
|
||||
version = "0.1.32"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "48d1dbcbbeb6a7fec7e059840aa538bd62aaccf972c7346c4d9d2059312853d0"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "js-sys"
|
||||
version = "0.3.77"
|
||||
version = "0.3.76"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1cfaf33c695fc6e08064efbc1f72ec937429614f25eef83af942d0e227c3a28f"
|
||||
checksum = "6717b6b5b077764fb5966237269cb3c64edddde4b14ce42647430a78ced9e7b7"
|
||||
dependencies = [
|
||||
"once_cell",
|
||||
"wasm-bindgen",
|
||||
@ -2767,15 +2745,6 @@ dependencies = [
|
||||
"unicode-segmentation",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "known-folders"
|
||||
version = "1.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b7d9a1740cc8b46e259a0eb787d79d855e79ff10b9855a5eba58868d5da7927c"
|
||||
dependencies = [
|
||||
"windows-sys 0.59.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "kuchikiki"
|
||||
version = "0.8.2"
|
||||
@ -2862,7 +2831,6 @@ checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d"
|
||||
dependencies = [
|
||||
"bitflags 2.6.0",
|
||||
"libc",
|
||||
"redox_syscall 0.5.8",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -2895,9 +2863,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "log"
|
||||
version = "0.4.27"
|
||||
version = "0.4.22"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94"
|
||||
checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24"
|
||||
dependencies = [
|
||||
"serde",
|
||||
"value-bag",
|
||||
@ -3124,6 +3092,85 @@ dependencies = [
|
||||
"tempfile",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "native_db"
|
||||
version = "0.8.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "db7c6b50f9889052a3c1bbd3aa70cc33b76ec1761092aeb0ec0e1ac3cfdb881a"
|
||||
dependencies = [
|
||||
"native_db_macro",
|
||||
"native_model 0.4.20",
|
||||
"redb 1.5.1",
|
||||
"redb 2.5.0",
|
||||
"semver",
|
||||
"serde",
|
||||
"skeptic",
|
||||
"thiserror 1.0.69",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "native_db_macro"
|
||||
version = "0.8.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "434acde56fc4485e0b62533bb2fbc08155ee7e47408b1358348acff556c31b3c"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.91",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "native_model"
|
||||
version = "0.4.20"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c10f4542302b7fa69ef18b49d93106e27f20b59d695555121d9ed22fe5d716a8"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"bincode",
|
||||
"native_model_macro 0.4.20",
|
||||
"serde",
|
||||
"skeptic",
|
||||
"thiserror 1.0.69",
|
||||
"zerocopy 0.8.25",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "native_model"
|
||||
version = "0.6.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7050d759e3da6673361dddda4f4a743492279dd2c6484a21fbee0a8278620df0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"bincode",
|
||||
"doc-comment",
|
||||
"native_model_macro 0.6.1",
|
||||
"serde",
|
||||
"thiserror 2.0.9",
|
||||
"zerocopy 0.8.25",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "native_model_macro"
|
||||
version = "0.4.20"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2f385f3d57adaea8d8868e65a0bc821bcb8ba2228bbf87a1c3c6144ac48f3791"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.91",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "native_model_macro"
|
||||
version = "0.6.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1577a0bebf5ed1754e240baf5d9b1845f51e598b20600aa894f55e11cd20cc6c"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.91",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ndk"
|
||||
version = "0.9.0"
|
||||
@ -3944,7 +3991,7 @@ version = "0.2.20"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04"
|
||||
dependencies = [
|
||||
"zerocopy",
|
||||
"zerocopy 0.7.35",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -4012,6 +4059,17 @@ dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pulldown-cmark"
|
||||
version = "0.9.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "57206b407293d2bcd3af849ce869d52068623f19e1b5ff8e8778e3309439682b"
|
||||
dependencies = [
|
||||
"bitflags 2.6.0",
|
||||
"memchr",
|
||||
"unicase",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quick-xml"
|
||||
version = "0.32.0"
|
||||
@ -4039,12 +4097,6 @@ dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "r-efi"
|
||||
version = "5.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "74765f6d916ee2faa39bc8e68e4f3ed8949b48cccdac59983d287a7cb71ce9c5"
|
||||
|
||||
[[package]]
|
||||
name = "rand"
|
||||
version = "0.7.3"
|
||||
@ -4070,16 +4122,6 @@ dependencies = [
|
||||
"rand_core 0.6.4",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand"
|
||||
version = "0.9.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9fbfd9d094a40bf3ae768db9361049ace4c0e04a4fd6b359518bd7b73a73dd97"
|
||||
dependencies = [
|
||||
"rand_chacha 0.9.0",
|
||||
"rand_core 0.9.3",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_chacha"
|
||||
version = "0.2.2"
|
||||
@ -4100,16 +4142,6 @@ dependencies = [
|
||||
"rand_core 0.6.4",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_chacha"
|
||||
version = "0.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb"
|
||||
dependencies = [
|
||||
"ppv-lite86",
|
||||
"rand_core 0.9.3",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_core"
|
||||
version = "0.5.1"
|
||||
@ -4128,15 +4160,6 @@ dependencies = [
|
||||
"getrandom 0.2.15",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_core"
|
||||
version = "0.9.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38"
|
||||
dependencies = [
|
||||
"getrandom 0.3.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_hc"
|
||||
version = "0.2.0"
|
||||
@ -4195,6 +4218,24 @@ dependencies = [
|
||||
"yasna",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "redb"
|
||||
version = "1.5.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fd7f82ecd6ba647a39dd1a7172b8a1cd9453c0adee6da20cb553d83a9a460fa5"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "redb"
|
||||
version = "2.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "34bc6763177194266fc3773e2b2bb3693f7b02fdf461e285aa33202e3164b74e"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "redox_syscall"
|
||||
version = "0.2.16"
|
||||
@ -4224,17 +4265,6 @@ dependencies = [
|
||||
"thiserror 1.0.69",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "redox_users"
|
||||
version = "0.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dd6f9d3d47bdd2ad6945c5015a226ec6155d0bcdfd8f7cd29f86b71f8de99d2b"
|
||||
dependencies = [
|
||||
"getrandom 0.2.15",
|
||||
"libredox",
|
||||
"thiserror 2.0.9",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "reflink-copy"
|
||||
version = "0.1.23"
|
||||
@ -4558,12 +4588,6 @@ dependencies = [
|
||||
"untrusted",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustversion"
|
||||
version = "1.0.20"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "eded382c5f5f786b989652c49544c4877d9f015cc22e145a5ea8ea66c2921cd2"
|
||||
|
||||
[[package]]
|
||||
name = "ryu"
|
||||
version = "1.0.18"
|
||||
@ -4590,9 +4614,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "schemars"
|
||||
version = "0.8.22"
|
||||
version = "0.8.21"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3fbf2ae1b8bc8e02df939598064d22402220cd5bbcca1c76f7d6a310974d5615"
|
||||
checksum = "09c024468a378b7e36765cd36702b7a90cc3cba11654f6685c8f233408e89e92"
|
||||
dependencies = [
|
||||
"dyn-clone",
|
||||
"indexmap 1.9.3",
|
||||
@ -4605,9 +4629,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "schemars_derive"
|
||||
version = "0.8.22"
|
||||
version = "0.8.21"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "32e265784ad618884abaea0600a9adf15393368d840e0222d101a072f3f7534d"
|
||||
checksum = "b1eee588578aff73f856ab961cd2f79e36bc45d7ded33a7562adba4667aecc0e"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@ -4981,6 +5005,21 @@ version = "0.3.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d"
|
||||
|
||||
[[package]]
|
||||
name = "skeptic"
|
||||
version = "0.13.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "16d23b015676c90a0f01c197bfdc786c20342c73a0afdda9025adb0bc42940a8"
|
||||
dependencies = [
|
||||
"bytecount",
|
||||
"cargo_metadata 0.14.2",
|
||||
"error-chain",
|
||||
"glob",
|
||||
"pulldown-cmark",
|
||||
"tempfile",
|
||||
"walkdir",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "slab"
|
||||
version = "0.4.9"
|
||||
@ -5320,17 +5359,6 @@ dependencies = [
|
||||
"syn 2.0.91",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tar"
|
||||
version = "0.4.44"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1d863878d212c87a19c1a610eb53bb01fe12951c0501cf5a0d65f724914a667a"
|
||||
dependencies = [
|
||||
"filetime",
|
||||
"libc",
|
||||
"xattr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "target-lexicon"
|
||||
version = "0.12.16"
|
||||
@ -5658,7 +5686,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9271a88f99b4adea0dc71d0baca4505475a0bbd139fb135f62958721aaa8fe54"
|
||||
dependencies = [
|
||||
"brotli",
|
||||
"cargo_metadata",
|
||||
"cargo_metadata 0.18.1",
|
||||
"ctor",
|
||||
"dunce",
|
||||
"glob",
|
||||
@ -5700,14 +5728,14 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tempfile"
|
||||
version = "3.19.1"
|
||||
version = "3.14.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7437ac7763b9b123ccf33c338a5cc1bac6f69b45a136c19bdd8a65e3916435bf"
|
||||
checksum = "28cce251fcbc87fac86a866eeb0d6c2d536fc16d06f184bb61aeae11aa4cee0c"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"fastrand",
|
||||
"getrandom 0.3.2",
|
||||
"once_cell",
|
||||
"rustix 1.0.5",
|
||||
"rustix 0.38.42",
|
||||
"windows-sys 0.59.0",
|
||||
]
|
||||
|
||||
@ -6301,38 +6329,22 @@ version = "0.11.0+wasi-snapshot-preview1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
|
||||
|
||||
[[package]]
|
||||
name = "wasi"
|
||||
version = "0.14.2+wasi-0.2.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9683f9a5a998d873c0d21fcbe3c083009670149a8fab228644b8bd36b2c48cb3"
|
||||
dependencies = [
|
||||
"wit-bindgen-rt",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasite"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b8dad83b4f25e74f184f64c43b150b91efe7647395b42289f38e50566d82855b"
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen"
|
||||
version = "0.2.100"
|
||||
version = "0.2.99"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5"
|
||||
checksum = "a474f6281d1d70c17ae7aa6a613c87fce69a127e2624002df63dcb39d6cf6396"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"once_cell",
|
||||
"rustversion",
|
||||
"wasm-bindgen-macro",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-backend"
|
||||
version = "0.2.100"
|
||||
version = "0.2.99"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2f0a0651a5c2bc21487bde11ee802ccaf4c51935d0d3d42a6101f98161700bc6"
|
||||
checksum = "5f89bb38646b4f81674e8f5c3fb81b562be1fd936d84320f3264486418519c79"
|
||||
dependencies = [
|
||||
"bumpalo",
|
||||
"log",
|
||||
@ -6344,9 +6356,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-futures"
|
||||
version = "0.4.50"
|
||||
version = "0.4.49"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "555d470ec0bc3bb57890405e5d4322cc9ea83cebb085523ced7be4144dac1e61"
|
||||
checksum = "38176d9b44ea84e9184eff0bc34cc167ed044f816accfe5922e54d84cf48eca2"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"js-sys",
|
||||
@ -6357,9 +6369,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-macro"
|
||||
version = "0.2.100"
|
||||
version = "0.2.99"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7fe63fc6d09ed3792bd0897b314f53de8e16568c2b3f7982f468c0bf9bd0b407"
|
||||
checksum = "2cc6181fd9a7492eef6fef1f33961e3695e4579b9872a6f7c83aee556666d4fe"
|
||||
dependencies = [
|
||||
"quote",
|
||||
"wasm-bindgen-macro-support",
|
||||
@ -6367,9 +6379,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-macro-support"
|
||||
version = "0.2.100"
|
||||
version = "0.2.99"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de"
|
||||
checksum = "30d7a95b763d3c45903ed6c81f156801839e5ee968bb07e534c44df0fcd330c2"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@ -6380,12 +6392,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-shared"
|
||||
version = "0.2.100"
|
||||
version = "0.2.99"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1a05d73b933a847d6cccdda8f838a22ff101ad9bf93e33684f39c1f5f0eece3d"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
checksum = "943aab3fdaaa029a6e0271b35ea10b72b943135afe9bffca82384098ad0e06a6"
|
||||
|
||||
[[package]]
|
||||
name = "wasm-streams"
|
||||
@ -6462,9 +6471,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "web-sys"
|
||||
version = "0.3.77"
|
||||
version = "0.3.76"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "33b6dd2ef9186f1f2072e409e99cd22a975331a6b3591b12c764e0e55c60d5d2"
|
||||
checksum = "04dd7223427d52553d3702c004d3b2fe07c148165faa56313cb00211e31c12bc"
|
||||
dependencies = [
|
||||
"js-sys",
|
||||
"wasm-bindgen",
|
||||
@ -6578,17 +6587,6 @@ dependencies = [
|
||||
"windows-core 0.58.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "whoami"
|
||||
version = "1.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6994d13118ab492c3c80c1f81928718159254c53c472bf9ce36f8dae4add02a7"
|
||||
dependencies = [
|
||||
"redox_syscall 0.5.8",
|
||||
"wasite",
|
||||
"web-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winapi"
|
||||
version = "0.3.9"
|
||||
@ -7126,15 +7124,6 @@ dependencies = [
|
||||
"windows-sys 0.48.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wit-bindgen-rt"
|
||||
version = "0.39.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6f42320e61fe2cfd34354ecb597f86f413484a798ba44a8ca1165c58d42da6c1"
|
||||
dependencies = [
|
||||
"bitflags 2.6.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "write16"
|
||||
version = "1.0.0"
|
||||
@ -7247,16 +7236,6 @@ dependencies = [
|
||||
"time",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "xattr"
|
||||
version = "1.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0d65cbf2f12c15564212d48f4e3dfb87923d25d611f2aed18f4cb23f0413d89e"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"rustix 1.0.5",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "xdg-home"
|
||||
version = "1.3.0"
|
||||
@ -7378,7 +7357,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0"
|
||||
dependencies = [
|
||||
"byteorder",
|
||||
"zerocopy-derive",
|
||||
"zerocopy-derive 0.7.35",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zerocopy"
|
||||
version = "0.8.25"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a1702d9583232ddb9174e01bb7c15a2ab8fb1bc6f227aa1233858c351a3ba0cb"
|
||||
dependencies = [
|
||||
"zerocopy-derive 0.8.25",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -7392,6 +7380,17 @@ dependencies = [
|
||||
"syn 2.0.91",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zerocopy-derive"
|
||||
version = "0.8.25"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "28a6e20d751156648aa063f3800b706ee209a32c0b4d9f24be3d980b01be55ef"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.91",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zerofrom"
|
||||
version = "0.1.5"
|
||||
@ -7441,34 +7440,6 @@ dependencies = [
|
||||
"syn 2.0.91",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zstd"
|
||||
version = "0.13.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e91ee311a569c327171651566e07972200e76fcfe2242a4fa446149a3881c08a"
|
||||
dependencies = [
|
||||
"zstd-safe",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zstd-safe"
|
||||
version = "7.2.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8f49c4d5f0abb602a93fb8736af2a4f4dd9512e36f7f570d66e65ff867ed3b9d"
|
||||
dependencies = [
|
||||
"zstd-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zstd-sys"
|
||||
version = "2.0.15+zstd.1.5.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "eb81183ddd97d0c74cedf1d50d85c8d08c1b8b68ee863bdee9e706eedba1a237"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"pkg-config",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zvariant"
|
||||
version = "4.0.0"
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "drop-app"
|
||||
version = "0.2.0-beta-prerelease-1"
|
||||
version = "0.3.0-rc-1"
|
||||
description = "The client application for the open-source, self-hosted game distribution platform Drop"
|
||||
authors = ["Drop OSS"]
|
||||
edition = "2021"
|
||||
@ -29,6 +29,7 @@ tauri-plugin-shell = "2.2.1"
|
||||
serde_json = "1"
|
||||
serde-binary = "0.5.0"
|
||||
rayon = "1.10.0"
|
||||
directories = "5.0.1"
|
||||
webbrowser = "1.0.2"
|
||||
url = "2.5.2"
|
||||
tauri-plugin-deep-link = "2"
|
||||
@ -57,18 +58,8 @@ reqwest-middleware-cache = "0.1.1"
|
||||
deranged = "=0.4.0"
|
||||
droplet-rs = "0.7.3"
|
||||
gethostname = "1.0.1"
|
||||
zstd = "0.13.3"
|
||||
tar = "0.4.44"
|
||||
rand = "0.9.1"
|
||||
regex = "1.11.1"
|
||||
tempfile = "3.19.1"
|
||||
schemars = "0.8.22"
|
||||
sha1 = "0.10.6"
|
||||
dirs = "6.0.0"
|
||||
whoami = "1.6.0"
|
||||
filetime = "0.2.25"
|
||||
walkdir = "2.5.0"
|
||||
known-folders = "1.2.0"
|
||||
native_db = "0.8.1"
|
||||
native_model = "0.6.1"
|
||||
|
||||
[dependencies.dynfmt]
|
||||
version = "0.1.5"
|
||||
@ -92,7 +83,11 @@ features = ["fs"]
|
||||
|
||||
[dependencies.uuid]
|
||||
version = "1.10.0"
|
||||
features = ["v4", "fast-rng", "macro-diagnostics"]
|
||||
features = [
|
||||
"v4", # Lets you generate random UUIDs
|
||||
"fast-rng", # Use a faster (but still sufficiently random) RNG
|
||||
"macro-diagnostics", # Enable better diagnostics for compile-time UUIDs
|
||||
]
|
||||
|
||||
[dependencies.rustbreak]
|
||||
version = "2"
|
||||
|
||||
@ -1,102 +0,0 @@
|
||||
use std::{collections::HashMap, path::PathBuf, str::FromStr};
|
||||
|
||||
use log::warn;
|
||||
|
||||
use crate::{database::db::{GameVersion, DATA_ROOT_DIR}, error::backup_error::BackupError, process::process_manager::Platform};
|
||||
|
||||
use super::path::CommonPath;
|
||||
|
||||
pub struct BackupManager<'a> {
|
||||
pub current_platform: Platform,
|
||||
pub sources: HashMap<(Platform, Platform), &'a (dyn BackupHandler + Sync + Send)>,
|
||||
}
|
||||
|
||||
impl BackupManager<'_> {
|
||||
pub fn new() -> Self {
|
||||
BackupManager {
|
||||
#[cfg(target_os = "windows")]
|
||||
current_platform: Platform::Windows,
|
||||
|
||||
#[cfg(target_os = "macos")]
|
||||
current_platform: Platform::MacOs,
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
current_platform: Platform::Linux,
|
||||
|
||||
sources: HashMap::from([
|
||||
// Current platform to target platform
|
||||
(
|
||||
(Platform::Windows, Platform::Windows),
|
||||
&WindowsBackupManager {} as &(dyn BackupHandler + Sync + Send),
|
||||
),
|
||||
(
|
||||
(Platform::Linux, Platform::Linux),
|
||||
&LinuxBackupManager {} as &(dyn BackupHandler + Sync + Send),
|
||||
),
|
||||
(
|
||||
(Platform::MacOs, Platform::MacOs),
|
||||
&MacBackupManager {} as &(dyn BackupHandler + Sync + Send),
|
||||
),
|
||||
|
||||
]),
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
pub trait BackupHandler: Send + Sync {
|
||||
fn root_translate(&self, _path: &PathBuf, _game: &GameVersion) -> Result<PathBuf, BackupError> { Ok(DATA_ROOT_DIR.lock().unwrap().join("games")) }
|
||||
fn game_translate(&self, _path: &PathBuf, game: &GameVersion) -> Result<PathBuf, BackupError> { Ok(PathBuf::from_str(&game.game_id).unwrap()) }
|
||||
fn base_translate(&self, path: &PathBuf, game: &GameVersion) -> Result<PathBuf, BackupError> { Ok(self.root_translate(path, game)?.join(self.game_translate(path, game)?)) }
|
||||
fn home_translate(&self, _path: &PathBuf, _game: &GameVersion) -> Result<PathBuf, BackupError> { let c = CommonPath::Home.get().ok_or(BackupError::NotFound); println!("{:?}", c); c }
|
||||
fn store_user_id_translate(&self, _path: &PathBuf, game: &GameVersion) -> Result<PathBuf, BackupError> { PathBuf::from_str(&game.game_id).map_err(|_| BackupError::ParseError) }
|
||||
fn os_user_name_translate(&self, _path: &PathBuf, _game: &GameVersion) -> Result<PathBuf, BackupError> { Ok(PathBuf::from_str(&whoami::username()).unwrap()) }
|
||||
fn win_app_data_translate(&self, _path: &PathBuf, _game: &GameVersion) -> Result<PathBuf, BackupError> { warn!("Unexpected Windows Reference in Backup <winAppData>"); Err(BackupError::InvalidSystem) }
|
||||
fn win_local_app_data_translate(&self, _path: &PathBuf, _game: &GameVersion) -> Result<PathBuf, BackupError> { warn!("Unexpected Windows Reference in Backup <winLocalAppData>"); Err(BackupError::InvalidSystem) }
|
||||
fn win_local_app_data_low_translate(&self, _path: &PathBuf, _game: &GameVersion) -> Result<PathBuf, BackupError> { warn!("Unexpected Windows Reference in Backup <winLocalAppDataLow>"); Err(BackupError::InvalidSystem) }
|
||||
fn win_documents_translate(&self, _path: &PathBuf, _game: &GameVersion) -> Result<PathBuf, BackupError> { warn!("Unexpected Windows Reference in Backup <winDocuments>"); Err(BackupError::InvalidSystem) }
|
||||
fn win_public_translate(&self, _path: &PathBuf, _game: &GameVersion) -> Result<PathBuf, BackupError> { warn!("Unexpected Windows Reference in Backup <winPublic>"); Err(BackupError::InvalidSystem) }
|
||||
fn win_program_data_translate(&self, _path: &PathBuf, _game: &GameVersion) -> Result<PathBuf, BackupError> { warn!("Unexpected Windows Reference in Backup <winProgramData>"); Err(BackupError::InvalidSystem) }
|
||||
fn win_dir_translate(&self, _path: &PathBuf,_game: &GameVersion) -> Result<PathBuf, BackupError> { warn!("Unexpected Windows Reference in Backup <winDir>"); Err(BackupError::InvalidSystem) }
|
||||
fn xdg_data_translate(&self, _path: &PathBuf,_game: &GameVersion) -> Result<PathBuf, BackupError> { warn!("Unexpected XDG Reference in Backup <xdgData>"); Err(BackupError::InvalidSystem) }
|
||||
fn xdg_config_translate(&self, _path: &PathBuf,_game: &GameVersion) -> Result<PathBuf, BackupError> { warn!("Unexpected XDG Reference in Backup <xdgConfig>"); Err(BackupError::InvalidSystem) }
|
||||
fn skip_translate(&self, _path: &PathBuf, _game: &GameVersion) -> Result<PathBuf, BackupError> { Ok(PathBuf::new()) }
|
||||
}
|
||||
|
||||
pub struct LinuxBackupManager {}
|
||||
impl BackupHandler for LinuxBackupManager {
|
||||
fn xdg_config_translate(&self, _path: &PathBuf,_game: &GameVersion) -> Result<PathBuf, BackupError> {
|
||||
Ok(CommonPath::Data.get().ok_or(BackupError::NotFound)?)
|
||||
}
|
||||
fn xdg_data_translate(&self, _path: &PathBuf,_game: &GameVersion) -> Result<PathBuf, BackupError> {
|
||||
Ok(CommonPath::Config.get().ok_or(BackupError::NotFound)?)
|
||||
}
|
||||
}
|
||||
pub struct WindowsBackupManager {}
|
||||
impl BackupHandler for WindowsBackupManager {
|
||||
fn win_app_data_translate(&self, _path: &PathBuf, _game: &GameVersion) -> Result<PathBuf, BackupError> {
|
||||
Ok(CommonPath::Config.get().ok_or(BackupError::NotFound)?)
|
||||
}
|
||||
fn win_local_app_data_translate(&self, _path: &PathBuf, _game: &GameVersion) -> Result<PathBuf, BackupError> {
|
||||
Ok(CommonPath::DataLocal.get().ok_or(BackupError::NotFound)?)
|
||||
}
|
||||
fn win_local_app_data_low_translate(&self, _path: &PathBuf, _game: &GameVersion) -> Result<PathBuf, BackupError> {
|
||||
Ok(CommonPath::DataLocalLow.get().ok_or(BackupError::NotFound)?)
|
||||
}
|
||||
fn win_dir_translate(&self, _path: &PathBuf,_game: &GameVersion) -> Result<PathBuf, BackupError> {
|
||||
Ok(PathBuf::from_str("C:/Windows").unwrap())
|
||||
}
|
||||
fn win_documents_translate(&self, _path: &PathBuf, _game: &GameVersion) -> Result<PathBuf, BackupError> {
|
||||
Ok(CommonPath::Document.get().ok_or(BackupError::NotFound)?)
|
||||
|
||||
}
|
||||
fn win_program_data_translate(&self, _path: &PathBuf, _game: &GameVersion) -> Result<PathBuf, BackupError> {
|
||||
Ok(PathBuf::from_str("C:/ProgramData").unwrap())
|
||||
}
|
||||
fn win_public_translate(&self, _path: &PathBuf, _game: &GameVersion) -> Result<PathBuf, BackupError> {
|
||||
Ok(CommonPath::Public.get().ok_or(BackupError::NotFound)?)
|
||||
|
||||
}
|
||||
}
|
||||
pub struct MacBackupManager {}
|
||||
impl BackupHandler for MacBackupManager {}
|
||||
@ -1,6 +0,0 @@
|
||||
use crate::process::process_manager::Platform;
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
|
||||
pub enum Condition {
|
||||
Os(Platform)
|
||||
}
|
||||
@ -1,35 +0,0 @@
|
||||
use crate::database::db::GameVersion;
|
||||
|
||||
use super::conditions::{Condition};
|
||||
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
|
||||
pub struct CloudSaveMetadata {
|
||||
pub files: Vec<GameFile>,
|
||||
pub game_version: GameVersion,
|
||||
pub save_id: String,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
|
||||
pub struct GameFile {
|
||||
pub path: String,
|
||||
pub id: Option<String>,
|
||||
pub data_type: DataType,
|
||||
pub tags: Vec<Tag>,
|
||||
pub conditions: Vec<Condition>
|
||||
}
|
||||
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, serde::Serialize, serde::Deserialize)]
|
||||
pub enum DataType {
|
||||
Registry,
|
||||
File,
|
||||
Other
|
||||
}
|
||||
#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, serde::Serialize, serde::Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub enum Tag {
|
||||
Config,
|
||||
Save,
|
||||
#[default]
|
||||
#[serde(other)]
|
||||
Other,
|
||||
}
|
||||
@ -1,7 +0,0 @@
|
||||
pub mod conditions;
|
||||
pub mod metadata;
|
||||
pub mod resolver;
|
||||
pub mod placeholder;
|
||||
pub mod normalise;
|
||||
pub mod path;
|
||||
pub mod backup_manager;
|
||||
@ -1,162 +0,0 @@
|
||||
use std::sync::LazyLock;
|
||||
|
||||
use regex::Regex;
|
||||
use crate::process::process_manager::Platform;
|
||||
|
||||
use super::placeholder::*;
|
||||
|
||||
|
||||
pub fn normalize(path: &str, os: Platform) -> String {
|
||||
let mut path = path.trim().trim_end_matches(['/', '\\']).replace('\\', "/");
|
||||
|
||||
if path == "~" || path.starts_with("~/") {
|
||||
path = path.replacen('~', HOME, 1);
|
||||
}
|
||||
|
||||
static CONSECUTIVE_SLASHES: LazyLock<Regex> = LazyLock::new(|| Regex::new(r"/{2,}").unwrap());
|
||||
static UNNECESSARY_DOUBLE_STAR_1: LazyLock<Regex> = LazyLock::new(|| Regex::new(r"([^/*])\*{2,}").unwrap());
|
||||
static UNNECESSARY_DOUBLE_STAR_2: LazyLock<Regex> = LazyLock::new(|| Regex::new(r"\*{2,}([^/*])").unwrap());
|
||||
static ENDING_WILDCARD: LazyLock<Regex> = LazyLock::new(|| Regex::new(r"(/\*)+$").unwrap());
|
||||
static ENDING_DOT: LazyLock<Regex> = LazyLock::new(|| Regex::new(r"(/\.)$").unwrap());
|
||||
static INTERMEDIATE_DOT: LazyLock<Regex> = LazyLock::new(|| Regex::new(r"(/\./)").unwrap());
|
||||
static BLANK_SEGMENT: LazyLock<Regex> = LazyLock::new(|| Regex::new(r"(/\s+/)").unwrap());
|
||||
static APP_DATA: LazyLock<Regex> = LazyLock::new(|| Regex::new(r"(?i)%appdata%").unwrap());
|
||||
static APP_DATA_ROAMING: LazyLock<Regex> = LazyLock::new(|| Regex::new(r"(?i)%userprofile%/AppData/Roaming").unwrap());
|
||||
static APP_DATA_LOCAL: LazyLock<Regex> = LazyLock::new(|| Regex::new(r"(?i)%localappdata%").unwrap());
|
||||
static APP_DATA_LOCAL_2: LazyLock<Regex> = LazyLock::new(|| Regex::new(r"(?i)%userprofile%/AppData/Local/").unwrap());
|
||||
static USER_PROFILE: LazyLock<Regex> = LazyLock::new(|| Regex::new(r"(?i)%userprofile%").unwrap());
|
||||
static DOCUMENTS: LazyLock<Regex> = LazyLock::new(|| Regex::new(r"(?i)%userprofile%/Documents").unwrap());
|
||||
|
||||
for (pattern, replacement) in [
|
||||
(&CONSECUTIVE_SLASHES, "/"),
|
||||
(&UNNECESSARY_DOUBLE_STAR_1, "${1}*"),
|
||||
(&UNNECESSARY_DOUBLE_STAR_2, "*${1}"),
|
||||
(&ENDING_WILDCARD, ""),
|
||||
(&ENDING_DOT, ""),
|
||||
(&INTERMEDIATE_DOT, "/"),
|
||||
(&BLANK_SEGMENT, "/"),
|
||||
(&APP_DATA, WIN_APP_DATA),
|
||||
(&APP_DATA_ROAMING, WIN_APP_DATA),
|
||||
(&APP_DATA_LOCAL, WIN_LOCAL_APP_DATA),
|
||||
(&APP_DATA_LOCAL_2, &format!("{}/", WIN_LOCAL_APP_DATA)),
|
||||
(&USER_PROFILE, HOME),
|
||||
(&DOCUMENTS, WIN_DOCUMENTS),
|
||||
] {
|
||||
path = pattern.replace_all(&path, replacement).to_string();
|
||||
}
|
||||
|
||||
if os == Platform::Windows {
|
||||
let documents_2: Regex = Regex::new(r"(?i)<home>/Documents").unwrap();
|
||||
|
||||
#[allow(clippy::single_element_loop)]
|
||||
for (pattern, replacement) in [(&documents_2, WIN_DOCUMENTS)] {
|
||||
path = pattern.replace_all(&path, replacement).to_string();
|
||||
}
|
||||
}
|
||||
|
||||
for (pattern, replacement) in [
|
||||
("{64BitSteamID}", STORE_USER_ID),
|
||||
("{Steam3AccountID}", STORE_USER_ID),
|
||||
] {
|
||||
path = path.replace(pattern, replacement);
|
||||
}
|
||||
|
||||
path
|
||||
}
|
||||
|
||||
fn too_broad(path: &str) -> bool {
|
||||
println!("Path: {}", path);
|
||||
use {BASE, HOME, ROOT, STORE_USER_ID, WIN_APP_DATA, WIN_DIR, WIN_DOCUMENTS, XDG_CONFIG, XDG_DATA};
|
||||
|
||||
let path_lower = path.to_lowercase();
|
||||
|
||||
for item in ALL {
|
||||
if path == *item {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
for item in AVOID_WILDCARDS {
|
||||
if path.starts_with(&format!("{}/*", item)) || path.starts_with(&format!("{}/{}", item, STORE_USER_ID)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// These paths are present whether or not the game is installed.
|
||||
// If possible, they should be narrowed down on the wiki.
|
||||
for item in [
|
||||
format!("{}/{}", BASE, STORE_USER_ID), // because `<storeUserId>` is handled as `*`
|
||||
format!("{}/Documents", HOME),
|
||||
format!("{}/Saved Games", HOME),
|
||||
format!("{}/AppData", HOME),
|
||||
format!("{}/AppData/Local", HOME),
|
||||
format!("{}/AppData/Local/Packages", HOME),
|
||||
format!("{}/AppData/LocalLow", HOME),
|
||||
format!("{}/AppData/Roaming", HOME),
|
||||
format!("{}/Documents/My Games", HOME),
|
||||
format!("{}/Library/Application Support", HOME),
|
||||
format!("{}/Library/Application Support/UserData", HOME),
|
||||
format!("{}/Library/Preferences", HOME),
|
||||
format!("{}/.renpy", HOME),
|
||||
format!("{}/.renpy/persistent", HOME),
|
||||
format!("{}/Library", HOME),
|
||||
format!("{}/Library/RenPy", HOME),
|
||||
format!("{}/Telltale Games", HOME),
|
||||
format!("{}/config", ROOT),
|
||||
format!("{}/MMFApplications", WIN_APP_DATA),
|
||||
format!("{}/RenPy", WIN_APP_DATA),
|
||||
format!("{}/RenPy/persistent", WIN_APP_DATA),
|
||||
format!("{}/win.ini", WIN_DIR),
|
||||
format!("{}/SysWOW64", WIN_DIR),
|
||||
format!("{}/My Games", WIN_DOCUMENTS),
|
||||
format!("{}/Telltale Games", WIN_DOCUMENTS),
|
||||
format!("{}/unity3d", XDG_CONFIG),
|
||||
format!("{}/unity3d", XDG_DATA),
|
||||
"C:/Program Files".to_string(),
|
||||
"C:/Program Files (x86)".to_string(),
|
||||
] {
|
||||
let item = item.to_lowercase();
|
||||
if path_lower == item
|
||||
|| path_lower.starts_with(&format!("{}/*", item))
|
||||
|| path_lower.starts_with(&format!("{}/{}", item, STORE_USER_ID.to_lowercase()))
|
||||
|| path_lower.starts_with(&format!("{}/savesdir", item))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Drive letters:
|
||||
let drives: Regex = Regex::new(r"^[a-zA-Z]:$").unwrap();
|
||||
if drives.is_match(path) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Colon not for a drive letter
|
||||
if path.get(2..).is_some_and(|path| path.contains(':')) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Root:
|
||||
if path == "/" {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Relative path wildcard:
|
||||
if path.starts_with('*') {
|
||||
return true;
|
||||
}
|
||||
|
||||
false
|
||||
}
|
||||
|
||||
pub fn usable(path: &str) -> bool {
|
||||
let unprintable: Regex = Regex::new(r"(\p{Cc}|\p{Cf})").unwrap();
|
||||
|
||||
!path.is_empty()
|
||||
&& !path.contains("{{")
|
||||
&& !path.starts_with("./")
|
||||
&& !path.starts_with("../")
|
||||
&& !too_broad(path)
|
||||
&& !unprintable.is_match(path)
|
||||
}
|
||||
@ -1,48 +0,0 @@
|
||||
use std::{path::PathBuf, sync::LazyLock};
|
||||
|
||||
pub enum CommonPath {
|
||||
Config,
|
||||
Data,
|
||||
DataLocal,
|
||||
DataLocalLow,
|
||||
Document,
|
||||
Home,
|
||||
Public,
|
||||
SavedGames,
|
||||
}
|
||||
|
||||
impl CommonPath {
|
||||
pub fn get(&self) -> Option<PathBuf> {
|
||||
static CONFIG: LazyLock<Option<PathBuf>> = LazyLock::new(|| dirs::config_dir());
|
||||
static DATA: LazyLock<Option<PathBuf>> = LazyLock::new(|| dirs::data_dir());
|
||||
static DATA_LOCAL: LazyLock<Option<PathBuf>> = LazyLock::new(|| dirs::data_local_dir());
|
||||
static DOCUMENT: LazyLock<Option<PathBuf>> = LazyLock::new(|| dirs::document_dir());
|
||||
static HOME: LazyLock<Option<PathBuf>> = LazyLock::new(|| dirs::home_dir());
|
||||
static PUBLIC: LazyLock<Option<PathBuf>> = LazyLock::new(|| dirs::public_dir());
|
||||
|
||||
#[cfg(windows)]
|
||||
static DATA_LOCAL_LOW: LazyLock<Option<PathBuf>> = LazyLock::new(|| {
|
||||
known_folders::get_known_folder_path(known_folders::KnownFolder::LocalAppDataLow)
|
||||
});
|
||||
#[cfg(not(windows))]
|
||||
static DATA_LOCAL_LOW: Option<PathBuf> = None;
|
||||
|
||||
#[cfg(windows)]
|
||||
static SAVED_GAMES: LazyLock<Option<PathBuf>> = LazyLock::new(|| {
|
||||
known_folders::get_known_folder_path(known_folders::KnownFolder::SavedGames)
|
||||
});
|
||||
#[cfg(not(windows))]
|
||||
static SAVED_GAMES: Option<PathBuf> = None;
|
||||
|
||||
match self {
|
||||
Self::Config => CONFIG.clone(),
|
||||
Self::Data => DATA.clone(),
|
||||
Self::DataLocal => DATA_LOCAL.clone(),
|
||||
Self::DataLocalLow => DATA_LOCAL_LOW.clone(),
|
||||
Self::Document => DOCUMENT.clone(),
|
||||
Self::Home => HOME.clone(),
|
||||
Self::Public => PUBLIC.clone(),
|
||||
Self::SavedGames => SAVED_GAMES.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,51 +0,0 @@
|
||||
use std::sync::LazyLock;
|
||||
|
||||
pub const ALL: &[&str] = &[
|
||||
ROOT,
|
||||
GAME,
|
||||
BASE,
|
||||
HOME,
|
||||
STORE_USER_ID,
|
||||
OS_USER_NAME,
|
||||
WIN_APP_DATA,
|
||||
WIN_LOCAL_APP_DATA,
|
||||
WIN_DOCUMENTS,
|
||||
WIN_PUBLIC,
|
||||
WIN_PROGRAM_DATA,
|
||||
WIN_DIR,
|
||||
XDG_DATA,
|
||||
XDG_CONFIG,
|
||||
];
|
||||
|
||||
/// These are paths where `<placeholder>/*/` is suspicious.
|
||||
pub const AVOID_WILDCARDS: &[&str] = &[
|
||||
ROOT,
|
||||
HOME,
|
||||
WIN_APP_DATA,
|
||||
WIN_LOCAL_APP_DATA,
|
||||
WIN_DOCUMENTS,
|
||||
WIN_PUBLIC,
|
||||
WIN_PROGRAM_DATA,
|
||||
WIN_DIR,
|
||||
XDG_DATA,
|
||||
XDG_CONFIG,
|
||||
];
|
||||
|
||||
pub const ROOT: &str = "<root>"; // a directory where games are installed (configured in backup tool)
|
||||
pub const GAME: &str = "<game>"; // an installDir (if defined) or the game's canonical name in the manifest
|
||||
pub const BASE: &str = "<base>"; // shorthand for <root>/<game> (unless overridden by store-specific rules)
|
||||
pub const HOME: &str = "<home>"; // current user's home directory in the OS (~)
|
||||
pub const STORE_USER_ID: &str = "<storeUserId>"; // a store-specific id from the manifest, corresponding to the root's store type
|
||||
pub const OS_USER_NAME: &str = "<osUserName>"; // current user's ID in the game store
|
||||
pub const WIN_APP_DATA: &str = "<winAppData>"; // current user's name in the OS
|
||||
pub const WIN_LOCAL_APP_DATA: &str = "<winLocalAppData>"; // %APPDATA% on Windows
|
||||
pub const WIN_LOCAL_APP_DATA_LOW: &str = "<winLocalAppDataLow>"; // %LOCALAPPDATA% on Windows
|
||||
pub const WIN_DOCUMENTS: &str = "<winDocuments>"; // <home>/AppData/LocalLow on Windows
|
||||
pub const WIN_PUBLIC: &str = "<winPublic>"; // <home>/Documents (f.k.a. <home>/My Documents) or a localized equivalent on Windows
|
||||
pub const WIN_PROGRAM_DATA: &str = "<winProgramData>"; // %PUBLIC% on Windows
|
||||
pub const WIN_DIR: &str = "<winDir>"; // %PROGRAMDATA% on Windows
|
||||
pub const XDG_DATA: &str = "<xdgData>"; // %WINDIR% on Windows
|
||||
pub const XDG_CONFIG: &str = "<xdgConfig>"; // $XDG_DATA_HOME on Linux
|
||||
pub const SKIP: &str = "<skip>"; // $XDG_CONFIG_HOME on Linux
|
||||
|
||||
pub static OS_USERNAME: LazyLock<String> = LazyLock::new(|| whoami::username());
|
||||
@ -1,255 +0,0 @@
|
||||
use std::{
|
||||
fs::{self, create_dir_all, File},
|
||||
io::{self, ErrorKind, Read, Write},
|
||||
path::{Path, PathBuf}, thread::sleep, time::Duration,
|
||||
};
|
||||
|
||||
use super::{
|
||||
backup_manager::BackupHandler, conditions::Condition, metadata::GameFile, placeholder::*,
|
||||
};
|
||||
use log::{debug, warn};
|
||||
use rustix::path::Arg;
|
||||
use tempfile::tempfile;
|
||||
|
||||
use crate::{
|
||||
database::db::GameVersion, error::backup_error::BackupError, process::process_manager::Platform,
|
||||
};
|
||||
|
||||
use super::{backup_manager::BackupManager, metadata::CloudSaveMetadata, normalise::normalize};
|
||||
|
||||
pub fn resolve(meta: &mut CloudSaveMetadata) -> File {
|
||||
let f = File::create_new("save").unwrap();
|
||||
let compressor = zstd::Encoder::new(f, 22).unwrap();
|
||||
let mut tarball = tar::Builder::new(compressor);
|
||||
let manager = BackupManager::new();
|
||||
for file in meta.files.iter_mut() {
|
||||
let id = uuid::Uuid::new_v4().to_string();
|
||||
let os = match file
|
||||
.conditions
|
||||
.iter()
|
||||
.find_map(|p| match p {
|
||||
super::conditions::Condition::Os(os) => Some(os),
|
||||
_ => None,
|
||||
})
|
||||
.cloned()
|
||||
{
|
||||
Some(os) => os,
|
||||
None => {
|
||||
warn!(
|
||||
"File {:?} could not be backed up because it did not provide an OS",
|
||||
&file
|
||||
);
|
||||
continue;
|
||||
}
|
||||
};
|
||||
let handler = match manager.sources.get(&(manager.current_platform, os)) {
|
||||
Some(h) => *h,
|
||||
None => continue,
|
||||
};
|
||||
let t_path = PathBuf::from(normalize(&file.path, os));
|
||||
println!("{:?}", &t_path);
|
||||
let path = parse_path(t_path, handler, &meta.game_version).unwrap();
|
||||
let f = std::fs::metadata(&path).unwrap(); // TODO: Fix unwrap here
|
||||
if f.is_dir() {
|
||||
tarball.append_dir_all(&id, path).unwrap();
|
||||
} else if f.is_file() {
|
||||
tarball
|
||||
.append_file(&id, &mut File::open(path).unwrap())
|
||||
.unwrap();
|
||||
}
|
||||
file.id = Some(id);
|
||||
}
|
||||
let binding = serde_json::to_string(meta).unwrap();
|
||||
println!("Binding: {}", &binding);
|
||||
let serialized = binding.as_bytes();
|
||||
let mut file = tempfile().unwrap();
|
||||
file.write(serialized).unwrap();
|
||||
tarball.append_file("metadata", &mut file).unwrap();
|
||||
tarball.into_inner().unwrap().finish().unwrap()
|
||||
}
|
||||
|
||||
pub fn extract(file: PathBuf) -> Result<(), BackupError> {
|
||||
let tmpdir = tempfile::tempdir().unwrap();
|
||||
|
||||
// Reopen the file for reading
|
||||
let file = File::open(file).unwrap();
|
||||
|
||||
let decompressor = zstd::Decoder::new(file).unwrap();
|
||||
let mut f = tar::Archive::new(decompressor);
|
||||
f.unpack(tmpdir.path()).unwrap();
|
||||
|
||||
let path = tmpdir.path();
|
||||
|
||||
let mut manifest = File::open(path.join("metadata")).unwrap();
|
||||
|
||||
let mut manifest_slice = Vec::new();
|
||||
manifest.read_to_end(&mut manifest_slice).unwrap();
|
||||
|
||||
let manifest: CloudSaveMetadata = serde_json::from_slice(&manifest_slice).unwrap();
|
||||
|
||||
for file in manifest.files {
|
||||
let current_path = path.join(file.id.as_ref().unwrap());
|
||||
|
||||
let manager = BackupManager::new();
|
||||
let os = match file
|
||||
.conditions
|
||||
.iter()
|
||||
.find_map(|p| match p {
|
||||
super::conditions::Condition::Os(os) => Some(os),
|
||||
_ => None,
|
||||
})
|
||||
.cloned()
|
||||
{
|
||||
Some(os) => os,
|
||||
None => {
|
||||
warn!(
|
||||
"File {:?} could not be replaced up because it did not provide an OS",
|
||||
&file
|
||||
);
|
||||
continue;
|
||||
}
|
||||
};
|
||||
let handler = match manager.sources.get(&(manager.current_platform, os)) {
|
||||
Some(h) => *h,
|
||||
None => continue,
|
||||
};
|
||||
|
||||
let new_path = parse_path(file.path.into(), handler, &manifest.game_version)?;
|
||||
create_dir_all(&new_path.parent().unwrap()).unwrap();
|
||||
|
||||
println!("Current path {:?} copying to {:?}", ¤t_path, &new_path);
|
||||
|
||||
|
||||
copy_item(current_path, new_path).unwrap();
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn copy_item<P: AsRef<Path>>(src: P, dest: P) -> io::Result<()> {
|
||||
let src_path = src.as_ref();
|
||||
let dest_path = dest.as_ref();
|
||||
|
||||
let metadata = fs::metadata(&src_path)?;
|
||||
|
||||
if metadata.is_file() {
|
||||
// Ensure the parent directory of the destination exists for a file copy
|
||||
if let Some(parent) = dest_path.parent() {
|
||||
fs::create_dir_all(parent)?;
|
||||
}
|
||||
fs::copy(&src_path, &dest_path)?;
|
||||
} else if metadata.is_dir() {
|
||||
// For directories, we call the recursive helper function.
|
||||
// The destination for the recursive copy is the `dest_path` itself.
|
||||
copy_dir_recursive(&src_path, &dest_path)?;
|
||||
} else {
|
||||
// Handle other file types like symlinks if necessary,
|
||||
// for now, return an error or skip.
|
||||
return Err(io::Error::new(
|
||||
io::ErrorKind::Other,
|
||||
format!("Source {:?} is neither a file nor a directory", src_path),
|
||||
));
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn copy_dir_recursive(src: &Path, dest: &Path) -> io::Result<()> {
|
||||
fs::create_dir_all(&dest)?;
|
||||
|
||||
for entry in fs::read_dir(src)? {
|
||||
let entry = entry?;
|
||||
let entry_path = entry.path();
|
||||
let entry_file_name = match entry_path.file_name() {
|
||||
Some(name) => name,
|
||||
None => continue, // Skip if somehow there's no file name
|
||||
};
|
||||
let dest_entry_path = dest.join(entry_file_name);
|
||||
let metadata = entry.metadata()?;
|
||||
|
||||
if metadata.is_file() {
|
||||
debug!("Writing file {} to {}", entry_path.display(), dest_entry_path.display());
|
||||
fs::copy(&entry_path, &dest_entry_path)?;
|
||||
} else if metadata.is_dir() {
|
||||
copy_dir_recursive(&entry_path, &dest_entry_path)?;
|
||||
}
|
||||
// Ignore other types like symlinks for this basic implementation
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn parse_path(
|
||||
path: PathBuf,
|
||||
backup_handler: &dyn BackupHandler,
|
||||
game: &GameVersion,
|
||||
) -> Result<PathBuf, BackupError> {
|
||||
println!("Parsing: {:?}", &path);
|
||||
let mut s = PathBuf::new();
|
||||
for component in path.components() {
|
||||
match component.as_str().unwrap() {
|
||||
ROOT => s.push(backup_handler.root_translate(&path, game)?),
|
||||
GAME => s.push(backup_handler.game_translate(&path, game)?),
|
||||
BASE => s.push(backup_handler.base_translate(&path, game)?),
|
||||
HOME => s.push(backup_handler.home_translate(&path, game)?),
|
||||
STORE_USER_ID => s.push(backup_handler.store_user_id_translate(&path, game)?),
|
||||
OS_USER_NAME => s.push(backup_handler.os_user_name_translate(&path, game)?),
|
||||
WIN_APP_DATA => s.push(backup_handler.win_app_data_translate(&path, game)?),
|
||||
WIN_LOCAL_APP_DATA => s.push(backup_handler.win_local_app_data_translate(&path, game)?),
|
||||
WIN_LOCAL_APP_DATA_LOW => {
|
||||
s.push(backup_handler.win_local_app_data_low_translate(&path, game)?)
|
||||
}
|
||||
WIN_DOCUMENTS => s.push(backup_handler.win_documents_translate(&path, game)?),
|
||||
WIN_PUBLIC => s.push(backup_handler.win_public_translate(&path, game)?),
|
||||
WIN_PROGRAM_DATA => s.push(backup_handler.win_program_data_translate(&path, game)?),
|
||||
WIN_DIR => s.push(backup_handler.win_dir_translate(&path, game)?),
|
||||
XDG_DATA => s.push(backup_handler.xdg_data_translate(&path, game)?),
|
||||
XDG_CONFIG => s.push(backup_handler.xdg_config_translate(&path, game)?),
|
||||
SKIP => s.push(backup_handler.skip_translate(&path, game)?),
|
||||
_ => s.push(PathBuf::from(component.as_os_str())),
|
||||
}
|
||||
}
|
||||
|
||||
println!("Final line: {:?}", &s);
|
||||
Ok(s)
|
||||
}
|
||||
|
||||
pub fn test() {
|
||||
let mut meta = CloudSaveMetadata {
|
||||
files: vec![
|
||||
GameFile {
|
||||
path: String::from("<home>/favicon.png"),
|
||||
id: None,
|
||||
data_type: super::metadata::DataType::File,
|
||||
tags: Vec::new(),
|
||||
conditions: vec![Condition::Os(Platform::Linux)],
|
||||
},
|
||||
GameFile {
|
||||
path: String::from("<home>/Documents/Pixel Art"),
|
||||
id: None,
|
||||
data_type: super::metadata::DataType::File,
|
||||
tags: Vec::new(),
|
||||
conditions: vec![Condition::Os(Platform::Linux)],
|
||||
},
|
||||
],
|
||||
game_version: GameVersion {
|
||||
game_id: String::new(),
|
||||
version_name: String::new(),
|
||||
platform: Platform::Linux,
|
||||
launch_command: String::new(),
|
||||
launch_args: Vec::new(),
|
||||
launch_command_template: String::new(),
|
||||
setup_command: String::new(),
|
||||
setup_args: Vec::new(),
|
||||
setup_command_template: String::new(),
|
||||
only_setup: true,
|
||||
version_index: 0,
|
||||
delta: false,
|
||||
umu_id_override: None,
|
||||
},
|
||||
save_id: String::from("aaaaaaa"),
|
||||
};
|
||||
//resolve(&mut meta);
|
||||
|
||||
extract("save".into()).unwrap();
|
||||
}
|
||||
@ -7,6 +7,7 @@ use std::{
|
||||
};
|
||||
|
||||
use chrono::Utc;
|
||||
use directories::BaseDirs;
|
||||
use log::{debug, error, info};
|
||||
use rustbreak::{DeSerError, DeSerializer, PathDatabase, RustbreakError};
|
||||
use serde::{de::DeserializeOwned, Deserialize, Serialize};
|
||||
@ -58,7 +59,7 @@ fn default_template() -> String {
|
||||
"{}".to_owned()
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq)]
|
||||
#[derive(Serialize, Deserialize, Clone, Debug)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct GameVersion {
|
||||
pub game_id: String,
|
||||
@ -131,8 +132,7 @@ impl Database {
|
||||
}
|
||||
}
|
||||
pub static DATA_ROOT_DIR: LazyLock<Mutex<PathBuf>> =
|
||||
LazyLock::new(|| Mutex::new(dirs::data_dir().unwrap().join("drop")));
|
||||
|
||||
LazyLock::new(|| Mutex::new(BaseDirs::new().unwrap().data_dir().join("drop")));
|
||||
|
||||
// Custom JSON serializer to support everything we need
|
||||
#[derive(Debug, Default, Clone)]
|
||||
|
||||
@ -1,21 +0,0 @@
|
||||
use std::fmt::Display;
|
||||
|
||||
use serde_with::SerializeDisplay;
|
||||
|
||||
#[derive(Debug, SerializeDisplay, Clone, Copy)]
|
||||
pub enum BackupError {
|
||||
InvalidSystem,
|
||||
NotFound,
|
||||
ParseError
|
||||
}
|
||||
|
||||
impl Display for BackupError {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
let s = match self {
|
||||
BackupError::InvalidSystem => "Attempted to generate path for invalid system",
|
||||
BackupError::NotFound => "Could not generate or find path",
|
||||
BackupError::ParseError => "Failed to parse path",
|
||||
};
|
||||
write!(f, "{}", s)
|
||||
}
|
||||
}
|
||||
@ -4,4 +4,3 @@ pub mod library_error;
|
||||
pub mod process_error;
|
||||
pub mod remote_access_error;
|
||||
pub mod setup_error;
|
||||
pub mod backup_error;
|
||||
@ -3,7 +3,6 @@ mod games;
|
||||
|
||||
mod autostart;
|
||||
mod cleanup;
|
||||
mod cloud_saves;
|
||||
mod commands;
|
||||
mod download_manager;
|
||||
mod error;
|
||||
@ -13,7 +12,6 @@ mod remote;
|
||||
use crate::database::db::DatabaseImpls;
|
||||
use autostart::{get_autostart_enabled, toggle_autostart};
|
||||
use cleanup::{cleanup_and_exit, quit};
|
||||
use cloud_saves::resolver::test;
|
||||
use commands::fetch_state;
|
||||
use database::commands::{
|
||||
add_download_dir, delete_download_dir, fetch_download_dir_stats, fetch_settings,
|
||||
@ -106,7 +104,6 @@ pub struct AppState<'a> {
|
||||
}
|
||||
|
||||
fn setup(handle: AppHandle) -> AppState<'static> {
|
||||
test();
|
||||
let logfile = FileAppender::builder()
|
||||
.encoder(Box::new(PatternEncoder::new(
|
||||
"{d} | {l} | {f}:{L} - {m}{n}",
|
||||
|
||||
@ -47,7 +47,7 @@ impl ProcessManager<'_> {
|
||||
current_platform: Platform::Windows,
|
||||
|
||||
#[cfg(target_os = "macos")]
|
||||
current_platform: Platform::MacOs,
|
||||
current_platform: Platform::macOS,
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
current_platform: Platform::Linux,
|
||||
@ -66,7 +66,7 @@ impl ProcessManager<'_> {
|
||||
&NativeGameLauncher {} as &(dyn ProcessHandler + Sync + Send + 'static),
|
||||
),
|
||||
(
|
||||
(Platform::MacOs, Platform::MacOs),
|
||||
(Platform::macOS, Platform::macOS),
|
||||
&NativeGameLauncher {} as &(dyn ProcessHandler + Sync + Send + 'static),
|
||||
),
|
||||
(
|
||||
@ -324,54 +324,11 @@ impl ProcessManager<'_> {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Eq, Hash, PartialEq, Serialize, Deserialize, Clone, Copy, Debug)]
|
||||
#[derive(Eq, Hash, PartialEq, Serialize, Deserialize, Clone, Debug)]
|
||||
pub enum Platform {
|
||||
Windows,
|
||||
Linux,
|
||||
MacOs,
|
||||
}
|
||||
|
||||
impl Platform {
|
||||
const WINDOWS: bool = cfg!(target_os = "windows");
|
||||
const MAC: bool = cfg!(target_os = "macos");
|
||||
const LINUX: bool = cfg!(target_os = "linux");
|
||||
#[cfg(target_os = "windows")]
|
||||
pub const HOST: Platform = Self::Windows;
|
||||
#[cfg(target_os = "macos")]
|
||||
pub const HOST: Platform = Self::MacOs;
|
||||
#[cfg(target_os = "linux")]
|
||||
pub const HOST: Platform = Self::Linux;
|
||||
|
||||
|
||||
|
||||
pub fn is_case_sensitive(&self) -> bool {
|
||||
match self {
|
||||
Self::Windows | Self::MacOs => false,
|
||||
Self::Linux => true,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&str> for Platform {
|
||||
fn from(value: &str) -> Self {
|
||||
match value.to_lowercase().trim() {
|
||||
"windows" => Self::Windows,
|
||||
"linux" => Self::Linux,
|
||||
"mac" | "macos" => Self::MacOs,
|
||||
_ => unimplemented!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<whoami::Platform> for Platform {
|
||||
fn from(value: whoami::Platform) -> Self {
|
||||
match value {
|
||||
whoami::Platform::Windows => Platform::Windows,
|
||||
whoami::Platform::Linux => Platform::Linux,
|
||||
whoami::Platform::MacOS => Platform::MacOs,
|
||||
_ => unimplemented!()
|
||||
}
|
||||
}
|
||||
macOS,
|
||||
}
|
||||
|
||||
pub trait ProcessHandler: Send + 'static {
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
{
|
||||
"$schema": "https://schema.tauri.app/config/2.0.0",
|
||||
"productName": "Drop Desktop Client",
|
||||
"version": "0.2.0-beta",
|
||||
"version": "0.3.0-rc-1",
|
||||
"identifier": "dev.drop.app",
|
||||
"build": {
|
||||
"beforeDevCommand": "yarn dev --port 1432",
|
||||
|
||||
Reference in New Issue
Block a user