mirror of
https://github.com/mountain-loop/yaak.git
synced 2026-04-23 17:28:29 +02:00
Ability to open workspace from directory, WorkspaceMeta, and many sync improvements
This commit is contained in:
@@ -20,4 +20,4 @@ export type SyncModel = { "type": "workspace" } & Workspace | { "type": "environ
|
||||
|
||||
export type SyncState = { model: "sync_state", id: string, workspaceId: string, createdAt: string, updatedAt: string, flushedAt: string, modelId: string, checksum: string, relPath: string, syncDir: string, };
|
||||
|
||||
export type Workspace = { model: "workspace", id: string, createdAt: string, updatedAt: string, name: string, description: string, settingValidateCertificates: boolean, settingFollowRedirects: boolean, settingRequestTimeout: number, settingSyncDir: string | null, };
|
||||
export type Workspace = { model: "workspace", id: string, createdAt: string, updatedAt: string, name: string, description: string, settingValidateCertificates: boolean, settingFollowRedirects: boolean, settingRequestTimeout: number, };
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
const COMMANDS: &[&str] = &["calculate", "apply", "watch"];
|
||||
const COMMANDS: &[&str] = &["calculate", "calculate_fs", "apply", "watch"];
|
||||
|
||||
fn main() {
|
||||
tauri_plugin::Builder::new(COMMANDS).build();
|
||||
|
||||
@@ -1,48 +1,46 @@
|
||||
import { Channel, invoke } from '@tauri-apps/api/core';
|
||||
import { emit } from '@tauri-apps/api/event';
|
||||
import { Workspace } from '@yaakapp-internal/models';
|
||||
import { useEffect } from 'react';
|
||||
import { SyncOp } from './bindings/sync';
|
||||
import { WatchEvent, WatchResult } from './bindings/watch';
|
||||
|
||||
export async function calculateSync(workspace: Workspace) {
|
||||
if (!workspace.settingSyncDir) return;
|
||||
|
||||
export async function calculateSync(workspaceId: string, syncDir: string) {
|
||||
return invoke<SyncOp[]>('plugin:yaak-sync|calculate', {
|
||||
workspaceId: workspace.id,
|
||||
dir: workspace.settingSyncDir,
|
||||
workspaceId,
|
||||
syncDir,
|
||||
});
|
||||
}
|
||||
|
||||
export async function applySync(workspace: Workspace, syncOps: SyncOp[]) {
|
||||
if (!workspace.settingSyncDir) return;
|
||||
export async function calculateSyncFsOnly(dir: string) {
|
||||
return invoke<SyncOp[]>('plugin:yaak-sync|calculate_fs', { dir });
|
||||
}
|
||||
|
||||
export async function applySync(workspaceId: string, syncDir: string, syncOps: SyncOp[]) {
|
||||
return invoke<void>('plugin:yaak-sync|apply', {
|
||||
workspaceId: workspace.id,
|
||||
dir: workspace.settingSyncDir,
|
||||
workspaceId,
|
||||
syncDir,
|
||||
syncOps: syncOps,
|
||||
});
|
||||
}
|
||||
|
||||
export function useWatchWorkspace(workspace: Workspace | null, callback: (e: WatchEvent) => void) {
|
||||
useEffect(() => {
|
||||
if (workspace == null) return;
|
||||
if (!workspace.settingSyncDir) return;
|
||||
export function watchWorkspaceFiles(
|
||||
workspaceId: string,
|
||||
syncDir: string,
|
||||
callback: (e: WatchEvent) => void,
|
||||
) {
|
||||
const channel = new Channel<WatchEvent>();
|
||||
channel.onmessage = callback;
|
||||
const promise = invoke<WatchResult>('plugin:yaak-sync|watch', {
|
||||
workspaceId,
|
||||
syncDir,
|
||||
channel,
|
||||
});
|
||||
|
||||
const channel = new Channel<WatchEvent>();
|
||||
channel.onmessage = callback;
|
||||
const promise = invoke<WatchResult>('plugin:yaak-sync|watch', {
|
||||
workspaceId: workspace.id,
|
||||
channel,
|
||||
});
|
||||
|
||||
return () => {
|
||||
promise
|
||||
.then(({ unlistenEvent }) => {
|
||||
console.log('Cancelling workspace watch', workspace.id, unlistenEvent);
|
||||
return emit(unlistenEvent);
|
||||
})
|
||||
.catch(console.error);
|
||||
};
|
||||
}, [workspace]);
|
||||
return () => {
|
||||
promise
|
||||
.then(({ unlistenEvent }) => {
|
||||
console.log('Cancelling workspace watch', workspaceId, unlistenEvent);
|
||||
return emit(unlistenEvent);
|
||||
})
|
||||
.catch(console.error);
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,13 +0,0 @@
|
||||
# Automatically generated - DO NOT EDIT!
|
||||
|
||||
"$schema" = "../../schemas/schema.json"
|
||||
|
||||
[[permission]]
|
||||
identifier = "allow-activate"
|
||||
description = "Enables the activate command without any pre-configured scope."
|
||||
commands.allow = ["activate"]
|
||||
|
||||
[[permission]]
|
||||
identifier = "deny-activate"
|
||||
description = "Denies the activate command without any pre-configured scope."
|
||||
commands.deny = ["activate"]
|
||||
@@ -1,13 +0,0 @@
|
||||
# Automatically generated - DO NOT EDIT!
|
||||
|
||||
"$schema" = "../../schemas/schema.json"
|
||||
|
||||
[[permission]]
|
||||
identifier = "allow-add"
|
||||
description = "Enables the add command without any pre-configured scope."
|
||||
commands.allow = ["add"]
|
||||
|
||||
[[permission]]
|
||||
identifier = "deny-add"
|
||||
description = "Denies the add command without any pre-configured scope."
|
||||
commands.deny = ["add"]
|
||||
@@ -0,0 +1,13 @@
|
||||
# Automatically generated - DO NOT EDIT!
|
||||
|
||||
"$schema" = "../../schemas/schema.json"
|
||||
|
||||
[[permission]]
|
||||
identifier = "allow-calculate-fs"
|
||||
description = "Enables the calculate_fs command without any pre-configured scope."
|
||||
commands.allow = ["calculate_fs"]
|
||||
|
||||
[[permission]]
|
||||
identifier = "deny-calculate-fs"
|
||||
description = "Denies the calculate_fs command without any pre-configured scope."
|
||||
commands.deny = ["calculate_fs"]
|
||||
@@ -1,13 +0,0 @@
|
||||
# Automatically generated - DO NOT EDIT!
|
||||
|
||||
"$schema" = "../../schemas/schema.json"
|
||||
|
||||
[[permission]]
|
||||
identifier = "allow-check"
|
||||
description = "Enables the check command without any pre-configured scope."
|
||||
commands.allow = ["check"]
|
||||
|
||||
[[permission]]
|
||||
identifier = "deny-check"
|
||||
description = "Denies the check command without any pre-configured scope."
|
||||
commands.deny = ["check"]
|
||||
@@ -1,13 +0,0 @@
|
||||
# Automatically generated - DO NOT EDIT!
|
||||
|
||||
"$schema" = "../../schemas/schema.json"
|
||||
|
||||
[[permission]]
|
||||
identifier = "allow-checkout"
|
||||
description = "Enables the checkout command without any pre-configured scope."
|
||||
commands.allow = ["checkout"]
|
||||
|
||||
[[permission]]
|
||||
identifier = "deny-checkout"
|
||||
description = "Denies the checkout command without any pre-configured scope."
|
||||
commands.deny = ["checkout"]
|
||||
@@ -1,13 +0,0 @@
|
||||
# Automatically generated - DO NOT EDIT!
|
||||
|
||||
"$schema" = "../../schemas/schema.json"
|
||||
|
||||
[[permission]]
|
||||
identifier = "allow-cmd-add"
|
||||
description = "Enables the cmd_add command without any pre-configured scope."
|
||||
commands.allow = ["cmd_add"]
|
||||
|
||||
[[permission]]
|
||||
identifier = "deny-cmd-add"
|
||||
description = "Denies the cmd_add command without any pre-configured scope."
|
||||
commands.deny = ["cmd_add"]
|
||||
@@ -1,13 +0,0 @@
|
||||
# Automatically generated - DO NOT EDIT!
|
||||
|
||||
"$schema" = "../../schemas/schema.json"
|
||||
|
||||
[[permission]]
|
||||
identifier = "allow-cmd-checkout"
|
||||
description = "Enables the cmd_checkout command without any pre-configured scope."
|
||||
commands.allow = ["cmd_checkout"]
|
||||
|
||||
[[permission]]
|
||||
identifier = "deny-cmd-checkout"
|
||||
description = "Denies the cmd_checkout command without any pre-configured scope."
|
||||
commands.deny = ["cmd_checkout"]
|
||||
@@ -1,13 +0,0 @@
|
||||
# Automatically generated - DO NOT EDIT!
|
||||
|
||||
"$schema" = "../../schemas/schema.json"
|
||||
|
||||
[[permission]]
|
||||
identifier = "allow-cmd-commit"
|
||||
description = "Enables the cmd_commit command without any pre-configured scope."
|
||||
commands.allow = ["cmd_commit"]
|
||||
|
||||
[[permission]]
|
||||
identifier = "deny-cmd-commit"
|
||||
description = "Denies the cmd_commit command without any pre-configured scope."
|
||||
commands.deny = ["cmd_commit"]
|
||||
@@ -1,13 +0,0 @@
|
||||
# Automatically generated - DO NOT EDIT!
|
||||
|
||||
"$schema" = "../../schemas/schema.json"
|
||||
|
||||
[[permission]]
|
||||
identifier = "allow-cmd-init"
|
||||
description = "Enables the cmd_init command without any pre-configured scope."
|
||||
commands.allow = ["cmd_init"]
|
||||
|
||||
[[permission]]
|
||||
identifier = "deny-cmd-init"
|
||||
description = "Denies the cmd_init command without any pre-configured scope."
|
||||
commands.deny = ["cmd_init"]
|
||||
@@ -1,13 +0,0 @@
|
||||
# Automatically generated - DO NOT EDIT!
|
||||
|
||||
"$schema" = "../../schemas/schema.json"
|
||||
|
||||
[[permission]]
|
||||
identifier = "allow-cmd-log"
|
||||
description = "Enables the cmd_log command without any pre-configured scope."
|
||||
commands.allow = ["cmd_log"]
|
||||
|
||||
[[permission]]
|
||||
identifier = "deny-cmd-log"
|
||||
description = "Denies the cmd_log command without any pre-configured scope."
|
||||
commands.deny = ["cmd_log"]
|
||||
@@ -1,13 +0,0 @@
|
||||
# Automatically generated - DO NOT EDIT!
|
||||
|
||||
"$schema" = "../../schemas/schema.json"
|
||||
|
||||
[[permission]]
|
||||
identifier = "allow-cmd-status"
|
||||
description = "Enables the cmd_status command without any pre-configured scope."
|
||||
commands.allow = ["cmd_status"]
|
||||
|
||||
[[permission]]
|
||||
identifier = "deny-cmd-status"
|
||||
description = "Denies the cmd_status command without any pre-configured scope."
|
||||
commands.deny = ["cmd_status"]
|
||||
@@ -1,13 +0,0 @@
|
||||
# Automatically generated - DO NOT EDIT!
|
||||
|
||||
"$schema" = "../../schemas/schema.json"
|
||||
|
||||
[[permission]]
|
||||
identifier = "allow-commit"
|
||||
description = "Enables the commit command without any pre-configured scope."
|
||||
commands.allow = ["commit"]
|
||||
|
||||
[[permission]]
|
||||
identifier = "deny-commit"
|
||||
description = "Denies the commit command without any pre-configured scope."
|
||||
commands.deny = ["commit"]
|
||||
@@ -1,13 +0,0 @@
|
||||
# Automatically generated - DO NOT EDIT!
|
||||
|
||||
"$schema" = "../../schemas/schema.json"
|
||||
|
||||
[[permission]]
|
||||
identifier = "allow-init"
|
||||
description = "Enables the init command without any pre-configured scope."
|
||||
commands.allow = ["init"]
|
||||
|
||||
[[permission]]
|
||||
identifier = "deny-init"
|
||||
description = "Denies the init command without any pre-configured scope."
|
||||
commands.deny = ["init"]
|
||||
@@ -1,13 +0,0 @@
|
||||
# Automatically generated - DO NOT EDIT!
|
||||
|
||||
"$schema" = "../../schemas/schema.json"
|
||||
|
||||
[[permission]]
|
||||
identifier = "allow-init-repo"
|
||||
description = "Enables the init_repo command without any pre-configured scope."
|
||||
commands.allow = ["init_repo"]
|
||||
|
||||
[[permission]]
|
||||
identifier = "deny-init-repo"
|
||||
description = "Denies the init_repo command without any pre-configured scope."
|
||||
commands.deny = ["init_repo"]
|
||||
@@ -1,13 +0,0 @@
|
||||
# Automatically generated - DO NOT EDIT!
|
||||
|
||||
"$schema" = "../../schemas/schema.json"
|
||||
|
||||
[[permission]]
|
||||
identifier = "allow-initialize"
|
||||
description = "Enables the initialize command without any pre-configured scope."
|
||||
commands.allow = ["initialize"]
|
||||
|
||||
[[permission]]
|
||||
identifier = "deny-initialize"
|
||||
description = "Denies the initialize command without any pre-configured scope."
|
||||
commands.deny = ["initialize"]
|
||||
@@ -1,13 +0,0 @@
|
||||
# Automatically generated - DO NOT EDIT!
|
||||
|
||||
"$schema" = "../../schemas/schema.json"
|
||||
|
||||
[[permission]]
|
||||
identifier = "allow-log"
|
||||
description = "Enables the log command without any pre-configured scope."
|
||||
commands.allow = ["log"]
|
||||
|
||||
[[permission]]
|
||||
identifier = "deny-log"
|
||||
description = "Denies the log command without any pre-configured scope."
|
||||
commands.deny = ["log"]
|
||||
@@ -1,13 +0,0 @@
|
||||
# Automatically generated - DO NOT EDIT!
|
||||
|
||||
"$schema" = "../../schemas/schema.json"
|
||||
|
||||
[[permission]]
|
||||
identifier = "allow-status"
|
||||
description = "Enables the status command without any pre-configured scope."
|
||||
commands.allow = ["status"]
|
||||
|
||||
[[permission]]
|
||||
identifier = "deny-status"
|
||||
description = "Denies the status command without any pre-configured scope."
|
||||
commands.deny = ["status"]
|
||||
@@ -1,13 +0,0 @@
|
||||
# Automatically generated - DO NOT EDIT!
|
||||
|
||||
"$schema" = "../../schemas/schema.json"
|
||||
|
||||
[[permission]]
|
||||
identifier = "allow-sync"
|
||||
description = "Enables the sync command without any pre-configured scope."
|
||||
commands.allow = ["sync"]
|
||||
|
||||
[[permission]]
|
||||
identifier = "deny-sync"
|
||||
description = "Denies the sync command without any pre-configured scope."
|
||||
commands.deny = ["sync"]
|
||||
@@ -1,13 +0,0 @@
|
||||
# Automatically generated - DO NOT EDIT!
|
||||
|
||||
"$schema" = "../../schemas/schema.json"
|
||||
|
||||
[[permission]]
|
||||
identifier = "allow-sync-fs"
|
||||
description = "Enables the sync_fs command without any pre-configured scope."
|
||||
commands.allow = ["sync_fs"]
|
||||
|
||||
[[permission]]
|
||||
identifier = "deny-sync-fs"
|
||||
description = "Denies the sync_fs command without any pre-configured scope."
|
||||
commands.deny = ["sync_fs"]
|
||||
@@ -1,13 +0,0 @@
|
||||
# Automatically generated - DO NOT EDIT!
|
||||
|
||||
"$schema" = "../../schemas/schema.json"
|
||||
|
||||
[[permission]]
|
||||
identifier = "allow-unstage"
|
||||
description = "Enables the unstage command without any pre-configured scope."
|
||||
commands.allow = ["unstage"]
|
||||
|
||||
[[permission]]
|
||||
identifier = "deny-unstage"
|
||||
description = "Denies the unstage command without any pre-configured scope."
|
||||
commands.deny = ["unstage"]
|
||||
@@ -3,6 +3,7 @@
|
||||
Default permissions for the plugin
|
||||
|
||||
- `allow-calculate`
|
||||
- `allow-calculate-fs`
|
||||
- `allow-apply`
|
||||
- `allow-watch`
|
||||
|
||||
@@ -15,58 +16,6 @@ Default permissions for the plugin
|
||||
</tr>
|
||||
|
||||
|
||||
<tr>
|
||||
<td>
|
||||
|
||||
`yaak-sync:allow-activate`
|
||||
|
||||
</td>
|
||||
<td>
|
||||
|
||||
Enables the activate command without any pre-configured scope.
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>
|
||||
|
||||
`yaak-sync:deny-activate`
|
||||
|
||||
</td>
|
||||
<td>
|
||||
|
||||
Denies the activate command without any pre-configured scope.
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>
|
||||
|
||||
`yaak-sync:allow-add`
|
||||
|
||||
</td>
|
||||
<td>
|
||||
|
||||
Enables the add command without any pre-configured scope.
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>
|
||||
|
||||
`yaak-sync:deny-add`
|
||||
|
||||
</td>
|
||||
<td>
|
||||
|
||||
Denies the add command without any pre-configured scope.
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>
|
||||
|
||||
@@ -122,12 +71,12 @@ Denies the calculate command without any pre-configured scope.
|
||||
<tr>
|
||||
<td>
|
||||
|
||||
`yaak-sync:allow-check`
|
||||
`yaak-sync:allow-calculate-fs`
|
||||
|
||||
</td>
|
||||
<td>
|
||||
|
||||
Enables the check command without any pre-configured scope.
|
||||
Enables the calculate_fs command without any pre-configured scope.
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
@@ -135,428 +84,12 @@ Enables the check command without any pre-configured scope.
|
||||
<tr>
|
||||
<td>
|
||||
|
||||
`yaak-sync:deny-check`
|
||||
`yaak-sync:deny-calculate-fs`
|
||||
|
||||
</td>
|
||||
<td>
|
||||
|
||||
Denies the check command without any pre-configured scope.
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>
|
||||
|
||||
`yaak-sync:allow-checkout`
|
||||
|
||||
</td>
|
||||
<td>
|
||||
|
||||
Enables the checkout command without any pre-configured scope.
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>
|
||||
|
||||
`yaak-sync:deny-checkout`
|
||||
|
||||
</td>
|
||||
<td>
|
||||
|
||||
Denies the checkout command without any pre-configured scope.
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>
|
||||
|
||||
`yaak-sync:allow-cmd-add`
|
||||
|
||||
</td>
|
||||
<td>
|
||||
|
||||
Enables the cmd_add command without any pre-configured scope.
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>
|
||||
|
||||
`yaak-sync:deny-cmd-add`
|
||||
|
||||
</td>
|
||||
<td>
|
||||
|
||||
Denies the cmd_add command without any pre-configured scope.
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>
|
||||
|
||||
`yaak-sync:allow-cmd-checkout`
|
||||
|
||||
</td>
|
||||
<td>
|
||||
|
||||
Enables the cmd_checkout command without any pre-configured scope.
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>
|
||||
|
||||
`yaak-sync:deny-cmd-checkout`
|
||||
|
||||
</td>
|
||||
<td>
|
||||
|
||||
Denies the cmd_checkout command without any pre-configured scope.
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>
|
||||
|
||||
`yaak-sync:allow-cmd-commit`
|
||||
|
||||
</td>
|
||||
<td>
|
||||
|
||||
Enables the cmd_commit command without any pre-configured scope.
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>
|
||||
|
||||
`yaak-sync:deny-cmd-commit`
|
||||
|
||||
</td>
|
||||
<td>
|
||||
|
||||
Denies the cmd_commit command without any pre-configured scope.
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>
|
||||
|
||||
`yaak-sync:allow-cmd-init`
|
||||
|
||||
</td>
|
||||
<td>
|
||||
|
||||
Enables the cmd_init command without any pre-configured scope.
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>
|
||||
|
||||
`yaak-sync:deny-cmd-init`
|
||||
|
||||
</td>
|
||||
<td>
|
||||
|
||||
Denies the cmd_init command without any pre-configured scope.
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>
|
||||
|
||||
`yaak-sync:allow-cmd-log`
|
||||
|
||||
</td>
|
||||
<td>
|
||||
|
||||
Enables the cmd_log command without any pre-configured scope.
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>
|
||||
|
||||
`yaak-sync:deny-cmd-log`
|
||||
|
||||
</td>
|
||||
<td>
|
||||
|
||||
Denies the cmd_log command without any pre-configured scope.
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>
|
||||
|
||||
`yaak-sync:allow-cmd-status`
|
||||
|
||||
</td>
|
||||
<td>
|
||||
|
||||
Enables the cmd_status command without any pre-configured scope.
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>
|
||||
|
||||
`yaak-sync:deny-cmd-status`
|
||||
|
||||
</td>
|
||||
<td>
|
||||
|
||||
Denies the cmd_status command without any pre-configured scope.
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>
|
||||
|
||||
`yaak-sync:allow-commit`
|
||||
|
||||
</td>
|
||||
<td>
|
||||
|
||||
Enables the commit command without any pre-configured scope.
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>
|
||||
|
||||
`yaak-sync:deny-commit`
|
||||
|
||||
</td>
|
||||
<td>
|
||||
|
||||
Denies the commit command without any pre-configured scope.
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>
|
||||
|
||||
`yaak-sync:allow-init`
|
||||
|
||||
</td>
|
||||
<td>
|
||||
|
||||
Enables the init command without any pre-configured scope.
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>
|
||||
|
||||
`yaak-sync:deny-init`
|
||||
|
||||
</td>
|
||||
<td>
|
||||
|
||||
Denies the init command without any pre-configured scope.
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>
|
||||
|
||||
`yaak-sync:allow-init-repo`
|
||||
|
||||
</td>
|
||||
<td>
|
||||
|
||||
Enables the init_repo command without any pre-configured scope.
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>
|
||||
|
||||
`yaak-sync:deny-init-repo`
|
||||
|
||||
</td>
|
||||
<td>
|
||||
|
||||
Denies the init_repo command without any pre-configured scope.
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>
|
||||
|
||||
`yaak-sync:allow-initialize`
|
||||
|
||||
</td>
|
||||
<td>
|
||||
|
||||
Enables the initialize command without any pre-configured scope.
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>
|
||||
|
||||
`yaak-sync:deny-initialize`
|
||||
|
||||
</td>
|
||||
<td>
|
||||
|
||||
Denies the initialize command without any pre-configured scope.
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>
|
||||
|
||||
`yaak-sync:allow-log`
|
||||
|
||||
</td>
|
||||
<td>
|
||||
|
||||
Enables the log command without any pre-configured scope.
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>
|
||||
|
||||
`yaak-sync:deny-log`
|
||||
|
||||
</td>
|
||||
<td>
|
||||
|
||||
Denies the log command without any pre-configured scope.
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>
|
||||
|
||||
`yaak-sync:allow-status`
|
||||
|
||||
</td>
|
||||
<td>
|
||||
|
||||
Enables the status command without any pre-configured scope.
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>
|
||||
|
||||
`yaak-sync:deny-status`
|
||||
|
||||
</td>
|
||||
<td>
|
||||
|
||||
Denies the status command without any pre-configured scope.
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>
|
||||
|
||||
`yaak-sync:allow-sync`
|
||||
|
||||
</td>
|
||||
<td>
|
||||
|
||||
Enables the sync command without any pre-configured scope.
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>
|
||||
|
||||
`yaak-sync:deny-sync`
|
||||
|
||||
</td>
|
||||
<td>
|
||||
|
||||
Denies the sync command without any pre-configured scope.
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>
|
||||
|
||||
`yaak-sync:allow-sync-fs`
|
||||
|
||||
</td>
|
||||
<td>
|
||||
|
||||
Enables the sync_fs command without any pre-configured scope.
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>
|
||||
|
||||
`yaak-sync:deny-sync-fs`
|
||||
|
||||
</td>
|
||||
<td>
|
||||
|
||||
Denies the sync_fs command without any pre-configured scope.
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>
|
||||
|
||||
`yaak-sync:allow-unstage`
|
||||
|
||||
</td>
|
||||
<td>
|
||||
|
||||
Enables the unstage command without any pre-configured scope.
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>
|
||||
|
||||
`yaak-sync:deny-unstage`
|
||||
|
||||
</td>
|
||||
<td>
|
||||
|
||||
Denies the unstage command without any pre-configured scope.
|
||||
Denies the calculate_fs command without any pre-configured scope.
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
description = "Default permissions for the plugin"
|
||||
permissions = [
|
||||
"allow-calculate",
|
||||
"allow-calculate-fs",
|
||||
"allow-apply",
|
||||
"allow-watch",
|
||||
]
|
||||
|
||||
@@ -294,26 +294,6 @@
|
||||
"PermissionKind": {
|
||||
"type": "string",
|
||||
"oneOf": [
|
||||
{
|
||||
"description": "Enables the activate command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
"const": "allow-activate"
|
||||
},
|
||||
{
|
||||
"description": "Denies the activate command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
"const": "deny-activate"
|
||||
},
|
||||
{
|
||||
"description": "Enables the add command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
"const": "allow-add"
|
||||
},
|
||||
{
|
||||
"description": "Denies the add command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
"const": "deny-add"
|
||||
},
|
||||
{
|
||||
"description": "Enables the apply command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
@@ -335,174 +315,14 @@
|
||||
"const": "deny-calculate"
|
||||
},
|
||||
{
|
||||
"description": "Enables the check command without any pre-configured scope.",
|
||||
"description": "Enables the calculate_fs command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
"const": "allow-check"
|
||||
"const": "allow-calculate-fs"
|
||||
},
|
||||
{
|
||||
"description": "Denies the check command without any pre-configured scope.",
|
||||
"description": "Denies the calculate_fs command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
"const": "deny-check"
|
||||
},
|
||||
{
|
||||
"description": "Enables the checkout command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
"const": "allow-checkout"
|
||||
},
|
||||
{
|
||||
"description": "Denies the checkout command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
"const": "deny-checkout"
|
||||
},
|
||||
{
|
||||
"description": "Enables the cmd_add command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
"const": "allow-cmd-add"
|
||||
},
|
||||
{
|
||||
"description": "Denies the cmd_add command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
"const": "deny-cmd-add"
|
||||
},
|
||||
{
|
||||
"description": "Enables the cmd_checkout command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
"const": "allow-cmd-checkout"
|
||||
},
|
||||
{
|
||||
"description": "Denies the cmd_checkout command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
"const": "deny-cmd-checkout"
|
||||
},
|
||||
{
|
||||
"description": "Enables the cmd_commit command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
"const": "allow-cmd-commit"
|
||||
},
|
||||
{
|
||||
"description": "Denies the cmd_commit command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
"const": "deny-cmd-commit"
|
||||
},
|
||||
{
|
||||
"description": "Enables the cmd_init command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
"const": "allow-cmd-init"
|
||||
},
|
||||
{
|
||||
"description": "Denies the cmd_init command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
"const": "deny-cmd-init"
|
||||
},
|
||||
{
|
||||
"description": "Enables the cmd_log command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
"const": "allow-cmd-log"
|
||||
},
|
||||
{
|
||||
"description": "Denies the cmd_log command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
"const": "deny-cmd-log"
|
||||
},
|
||||
{
|
||||
"description": "Enables the cmd_status command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
"const": "allow-cmd-status"
|
||||
},
|
||||
{
|
||||
"description": "Denies the cmd_status command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
"const": "deny-cmd-status"
|
||||
},
|
||||
{
|
||||
"description": "Enables the commit command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
"const": "allow-commit"
|
||||
},
|
||||
{
|
||||
"description": "Denies the commit command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
"const": "deny-commit"
|
||||
},
|
||||
{
|
||||
"description": "Enables the init command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
"const": "allow-init"
|
||||
},
|
||||
{
|
||||
"description": "Denies the init command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
"const": "deny-init"
|
||||
},
|
||||
{
|
||||
"description": "Enables the init_repo command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
"const": "allow-init-repo"
|
||||
},
|
||||
{
|
||||
"description": "Denies the init_repo command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
"const": "deny-init-repo"
|
||||
},
|
||||
{
|
||||
"description": "Enables the initialize command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
"const": "allow-initialize"
|
||||
},
|
||||
{
|
||||
"description": "Denies the initialize command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
"const": "deny-initialize"
|
||||
},
|
||||
{
|
||||
"description": "Enables the log command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
"const": "allow-log"
|
||||
},
|
||||
{
|
||||
"description": "Denies the log command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
"const": "deny-log"
|
||||
},
|
||||
{
|
||||
"description": "Enables the status command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
"const": "allow-status"
|
||||
},
|
||||
{
|
||||
"description": "Denies the status command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
"const": "deny-status"
|
||||
},
|
||||
{
|
||||
"description": "Enables the sync command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
"const": "allow-sync"
|
||||
},
|
||||
{
|
||||
"description": "Denies the sync command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
"const": "deny-sync"
|
||||
},
|
||||
{
|
||||
"description": "Enables the sync_fs command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
"const": "allow-sync-fs"
|
||||
},
|
||||
{
|
||||
"description": "Denies the sync_fs command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
"const": "deny-sync-fs"
|
||||
},
|
||||
{
|
||||
"description": "Enables the unstage command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
"const": "allow-unstage"
|
||||
},
|
||||
{
|
||||
"description": "Denies the unstage command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
"const": "deny-unstage"
|
||||
"const": "deny-calculate-fs"
|
||||
},
|
||||
{
|
||||
"description": "Enables the watch command without any pre-configured scope.",
|
||||
|
||||
@@ -1,26 +1,38 @@
|
||||
use crate::error::Result;
|
||||
use crate::sync::{
|
||||
apply_sync_ops, apply_sync_state_ops, compute_sync_ops, get_db_candidates, get_fs_candidates,
|
||||
get_workspace_sync_dir, SyncOp,
|
||||
SyncOp,
|
||||
};
|
||||
use crate::watch::{watch_directory, WatchEvent};
|
||||
use chrono::Utc;
|
||||
use log::warn;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::path::Path;
|
||||
use tauri::ipc::Channel;
|
||||
use tauri::{command, Listener, Runtime, WebviewWindow};
|
||||
use tokio::sync::watch;
|
||||
use ts_rs::TS;
|
||||
use yaak_models::queries::get_workspace;
|
||||
|
||||
#[command]
|
||||
pub async fn calculate<R: Runtime>(
|
||||
window: WebviewWindow<R>,
|
||||
workspace_id: &str,
|
||||
sync_dir: &Path,
|
||||
) -> Result<Vec<SyncOp>> {
|
||||
let workspace = get_workspace(&window, workspace_id).await?;
|
||||
let db_candidates = get_db_candidates(&window, &workspace).await?;
|
||||
let fs_candidates = get_fs_candidates(&workspace).await?;
|
||||
let db_candidates = get_db_candidates(&window, workspace_id, sync_dir).await?;
|
||||
let fs_candidates = get_fs_candidates(sync_dir)
|
||||
.await?
|
||||
.into_iter()
|
||||
// Strip out any non-workspace candidates
|
||||
.filter(|fs| fs.model.workspace_id() == workspace_id)
|
||||
.collect();
|
||||
Ok(compute_sync_ops(db_candidates, fs_candidates))
|
||||
}
|
||||
|
||||
#[command]
|
||||
pub async fn calculate_fs(dir: &Path) -> Result<Vec<SyncOp>> {
|
||||
let db_candidates = Vec::new();
|
||||
let fs_candidates = get_fs_candidates(Path::new(&dir)).await?;
|
||||
Ok(compute_sync_ops(db_candidates, fs_candidates))
|
||||
}
|
||||
|
||||
@@ -28,11 +40,11 @@ pub async fn calculate<R: Runtime>(
|
||||
pub async fn apply<R: Runtime>(
|
||||
window: WebviewWindow<R>,
|
||||
sync_ops: Vec<SyncOp>,
|
||||
sync_dir: &Path,
|
||||
workspace_id: &str,
|
||||
) -> Result<()> {
|
||||
let workspace = get_workspace(&window, workspace_id).await?;
|
||||
let sync_state_ops = apply_sync_ops(&window, &workspace, sync_ops).await?;
|
||||
apply_sync_state_ops(&window, &workspace, sync_state_ops).await
|
||||
let sync_state_ops = apply_sync_ops(&window, &workspace_id, sync_dir, sync_ops).await?;
|
||||
apply_sync_state_ops(&window, workspace_id, sync_dir, sync_state_ops).await
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, TS)]
|
||||
@@ -45,11 +57,10 @@ pub(crate) struct WatchResult {
|
||||
#[command]
|
||||
pub async fn watch<R: Runtime>(
|
||||
window: WebviewWindow<R>,
|
||||
sync_dir: &Path,
|
||||
workspace_id: &str,
|
||||
channel: Channel<WatchEvent>,
|
||||
) -> Result<WatchResult> {
|
||||
let workspace = get_workspace(&window, workspace_id).await?;
|
||||
let sync_dir = get_workspace_sync_dir(&workspace)?;
|
||||
let (cancel_tx, cancel_rx) = watch::channel(());
|
||||
|
||||
watch_directory(&sync_dir, channel, cancel_rx).await?;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
use crate::commands::{apply, calculate, watch};
|
||||
use crate::commands::{apply, calculate, calculate_fs, watch};
|
||||
use tauri::{
|
||||
generate_handler,
|
||||
plugin::{Builder, TauriPlugin},
|
||||
@@ -12,5 +12,7 @@ mod sync;
|
||||
mod watch;
|
||||
|
||||
pub fn init<R: Runtime>() -> TauriPlugin<R> {
|
||||
Builder::new("yaak-sync").invoke_handler(generate_handler![calculate, apply, watch]).build()
|
||||
Builder::new("yaak-sync")
|
||||
.invoke_handler(generate_handler![calculate, calculate_fs, apply, watch])
|
||||
.build()
|
||||
}
|
||||
|
||||
@@ -96,6 +96,7 @@ impl TryFrom<AnyModel> for SyncModel {
|
||||
AnyModel::GrpcRequest(m) => SyncModel::GrpcRequest(m),
|
||||
AnyModel::HttpRequest(m) => SyncModel::HttpRequest(m),
|
||||
AnyModel::Workspace(m) => SyncModel::Workspace(m),
|
||||
AnyModel::WorkspaceMeta(m) => return Err(UnknownModel(m.model)),
|
||||
AnyModel::CookieJar(m) => return Err(UnknownModel(m.model)),
|
||||
AnyModel::GrpcConnection(m) => return Err(UnknownModel(m.model)),
|
||||
AnyModel::GrpcEvent(m) => return Err(UnknownModel(m.model)),
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
use crate::error::Error::{InvalidSyncFile, WorkspaceSyncNotConfigured};
|
||||
use crate::error::Error::InvalidSyncFile;
|
||||
use crate::error::Result;
|
||||
use crate::models::SyncModel;
|
||||
use chrono::Utc;
|
||||
@@ -12,12 +12,11 @@ use tokio::fs;
|
||||
use tokio::fs::File;
|
||||
use tokio::io::AsyncWriteExt;
|
||||
use ts_rs::TS;
|
||||
use yaak_models::models::{SyncState, Workspace};
|
||||
use yaak_models::models::{SyncState, WorkspaceMeta};
|
||||
use yaak_models::queries::{
|
||||
delete_environment, delete_folder, delete_grpc_request, delete_http_request, delete_sync_state,
|
||||
delete_workspace, get_workspace_export_resources, list_sync_states_for_workspace,
|
||||
upsert_environment, upsert_folder, upsert_grpc_request, upsert_http_request, upsert_sync_state,
|
||||
upsert_workspace, UpdateSource,
|
||||
batch_upsert, delete_environment, delete_folder, delete_grpc_request, delete_http_request,
|
||||
delete_sync_state, delete_workspace, get_workspace_export_resources, get_workspace_meta,
|
||||
list_sync_states_for_workspace, upsert_sync_state, upsert_workspace_meta, UpdateSource,
|
||||
};
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, TS)]
|
||||
@@ -48,6 +47,19 @@ pub(crate) enum SyncOp {
|
||||
},
|
||||
}
|
||||
|
||||
impl SyncOp {
|
||||
fn workspace_id(&self) -> String {
|
||||
match self {
|
||||
SyncOp::FsCreate { model } => model.workspace_id(),
|
||||
SyncOp::FsUpdate { state, .. } => state.workspace_id.clone(),
|
||||
SyncOp::FsDelete { state, .. } => state.workspace_id.clone(),
|
||||
SyncOp::DbCreate { fs } => fs.model.workspace_id(),
|
||||
SyncOp::DbUpdate { state, .. } => state.workspace_id.clone(),
|
||||
SyncOp::DbDelete { model, .. } => model.workspace_id(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for SyncOp {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||
f.write_str(
|
||||
@@ -87,24 +99,23 @@ impl DbCandidate {
|
||||
#[serde(rename_all = "camelCase", tag = "type")]
|
||||
#[ts(export, export_to = "sync.ts")]
|
||||
pub(crate) struct FsCandidate {
|
||||
model: SyncModel,
|
||||
rel_path: PathBuf,
|
||||
checksum: String,
|
||||
pub(crate) model: SyncModel,
|
||||
pub(crate) rel_path: PathBuf,
|
||||
pub(crate) checksum: String,
|
||||
}
|
||||
|
||||
pub(crate) async fn get_db_candidates<R: Runtime>(
|
||||
mgr: &impl Manager<R>,
|
||||
workspace: &Workspace,
|
||||
workspace_id: &str,
|
||||
sync_dir: &Path,
|
||||
) -> Result<Vec<DbCandidate>> {
|
||||
let sync_dir = get_workspace_sync_dir(workspace)?;
|
||||
let models: HashMap<_, _> =
|
||||
workspace_models(mgr, workspace).await.into_iter().map(|m| (m.id(), m)).collect();
|
||||
let sync_states: HashMap<_, _> =
|
||||
list_sync_states_for_workspace(mgr, workspace.id.as_str(), sync_dir)
|
||||
.await?
|
||||
.into_iter()
|
||||
.map(|s| (s.model_id.clone(), s))
|
||||
.collect();
|
||||
workspace_models(mgr, workspace_id).await.into_iter().map(|m| (m.id(), m)).collect();
|
||||
let sync_states: HashMap<_, _> = list_sync_states_for_workspace(mgr, workspace_id, sync_dir)
|
||||
.await?
|
||||
.into_iter()
|
||||
.map(|s| (s.model_id.clone(), s))
|
||||
.collect();
|
||||
|
||||
// 1. Add candidates for models (created/modified/unmodified)
|
||||
let mut candidates: Vec<DbCandidate> = models
|
||||
@@ -139,14 +150,9 @@ pub(crate) async fn get_db_candidates<R: Runtime>(
|
||||
Ok(candidates)
|
||||
}
|
||||
|
||||
pub(crate) async fn get_fs_candidates(workspace: &Workspace) -> Result<Vec<FsCandidate>> {
|
||||
let dir = match workspace.setting_sync_dir.clone() {
|
||||
None => return Ok(Vec::new()),
|
||||
Some(d) => d,
|
||||
};
|
||||
|
||||
pub(crate) async fn get_fs_candidates(dir: &Path) -> Result<Vec<FsCandidate>> {
|
||||
// Ensure the root directory exists
|
||||
fs::create_dir_all(dir.clone()).await?;
|
||||
fs::create_dir_all(dir).await?;
|
||||
|
||||
let mut candidates = Vec::new();
|
||||
let mut entries = fs::read_dir(dir).await?;
|
||||
@@ -166,12 +172,6 @@ pub(crate) async fn get_fs_candidates(workspace: &Workspace) -> Result<Vec<FsCan
|
||||
}
|
||||
};
|
||||
|
||||
// Skip models belonging to different workspace
|
||||
if model.workspace_id() != workspace.id.as_str() {
|
||||
debug!("Skipping non-workspace file");
|
||||
continue;
|
||||
}
|
||||
|
||||
let rel_path = Path::new(&dir_entry.file_name()).to_path_buf();
|
||||
candidates.push(FsCandidate {
|
||||
rel_path,
|
||||
@@ -254,7 +254,7 @@ pub(crate) fn compute_sync_ops(
|
||||
}
|
||||
}
|
||||
(Some(DbCandidate::Added(model)), Some(_)) => {
|
||||
// This would be super rare, so let's follow the user's intention
|
||||
// This would be super rare (impossible?), so let's follow the user's intention
|
||||
SyncOp::FsCreate {
|
||||
model: model.to_owned(),
|
||||
}
|
||||
@@ -269,14 +269,17 @@ pub(crate) fn compute_sync_ops(
|
||||
.collect()
|
||||
}
|
||||
|
||||
async fn workspace_models<R: Runtime>(
|
||||
mgr: &impl Manager<R>,
|
||||
workspace: &Workspace,
|
||||
) -> Vec<SyncModel> {
|
||||
let workspace_id = workspace.id.as_str();
|
||||
async fn workspace_models<R: Runtime>(mgr: &impl Manager<R>, workspace_id: &str) -> Vec<SyncModel> {
|
||||
let resources = get_workspace_export_resources(mgr, vec![workspace_id]).await.resources;
|
||||
let workspace = resources.workspaces.iter().find(|w| w.id == workspace_id);
|
||||
|
||||
let workspace = match workspace {
|
||||
None => return Vec::new(),
|
||||
Some(w) => w,
|
||||
};
|
||||
|
||||
let mut sync_models = vec![SyncModel::Workspace(workspace.to_owned())];
|
||||
|
||||
for m in resources.environments {
|
||||
sync_models.push(SyncModel::Environment(m));
|
||||
}
|
||||
@@ -295,7 +298,8 @@ async fn workspace_models<R: Runtime>(
|
||||
|
||||
pub(crate) async fn apply_sync_ops<R: Runtime>(
|
||||
window: &WebviewWindow<R>,
|
||||
workspace: &Workspace,
|
||||
workspace_id: &str,
|
||||
sync_dir: &Path,
|
||||
sync_ops: Vec<SyncOp>,
|
||||
) -> Result<Vec<SyncStateOp>> {
|
||||
if sync_ops.is_empty() {
|
||||
@@ -307,10 +311,145 @@ pub(crate) async fn apply_sync_ops<R: Runtime>(
|
||||
sync_ops.iter().map(|op| op.to_string()).collect::<Vec<String>>().join(", ")
|
||||
);
|
||||
let mut sync_state_ops = Vec::new();
|
||||
let mut workspaces_to_upsert = Vec::new();
|
||||
let mut environments_to_upsert = Vec::new();
|
||||
let mut folders_to_upsert = Vec::new();
|
||||
let mut http_requests_to_upsert = Vec::new();
|
||||
let mut grpc_requests_to_upsert = Vec::new();
|
||||
|
||||
for op in sync_ops {
|
||||
let op = apply_sync_op(window, workspace, &op).await?;
|
||||
sync_state_ops.push(op);
|
||||
// Only apply things if workspace ID matches
|
||||
if op.workspace_id() != workspace_id {
|
||||
continue;
|
||||
}
|
||||
|
||||
sync_state_ops.push(match op {
|
||||
SyncOp::FsCreate { model } => {
|
||||
let rel_path = derive_model_filename(&model);
|
||||
let abs_path = sync_dir.join(rel_path.clone());
|
||||
let (content, checksum) = model.to_file_contents(&rel_path)?;
|
||||
let mut f = File::create(&abs_path).await?;
|
||||
f.write_all(&content).await?;
|
||||
SyncStateOp::Create {
|
||||
model_id: model.id(),
|
||||
checksum,
|
||||
rel_path,
|
||||
}
|
||||
}
|
||||
SyncOp::FsUpdate { model, state } => {
|
||||
// Always write the existing path
|
||||
let rel_path = Path::new(&state.rel_path);
|
||||
let abs_path = Path::new(&state.sync_dir).join(&rel_path);
|
||||
let (content, checksum) = model.to_file_contents(&rel_path)?;
|
||||
let mut f = File::create(&abs_path).await?;
|
||||
f.write_all(&content).await?;
|
||||
SyncStateOp::Update {
|
||||
state: state.to_owned(),
|
||||
checksum,
|
||||
rel_path: rel_path.to_owned(),
|
||||
}
|
||||
}
|
||||
SyncOp::FsDelete {
|
||||
state,
|
||||
fs: fs_candidate,
|
||||
} => match fs_candidate {
|
||||
None => SyncStateOp::Delete {
|
||||
state: state.to_owned(),
|
||||
},
|
||||
Some(_) => {
|
||||
// Always delete the existing path
|
||||
let rel_path = Path::new(&state.rel_path);
|
||||
let abs_path = Path::new(&state.sync_dir).join(&rel_path);
|
||||
fs::remove_file(&abs_path).await?;
|
||||
SyncStateOp::Delete {
|
||||
state: state.to_owned(),
|
||||
}
|
||||
}
|
||||
},
|
||||
SyncOp::DbCreate { fs } => {
|
||||
let model_id = fs.model.id();
|
||||
|
||||
// Push updates to arrays so we can do them all in a single
|
||||
// batch upsert to make foreign keys happy
|
||||
match fs.model {
|
||||
SyncModel::Workspace(m) => workspaces_to_upsert.push(m),
|
||||
SyncModel::Environment(m) => environments_to_upsert.push(m),
|
||||
SyncModel::Folder(m) => folders_to_upsert.push(m),
|
||||
SyncModel::HttpRequest(m) => http_requests_to_upsert.push(m),
|
||||
SyncModel::GrpcRequest(m) => grpc_requests_to_upsert.push(m),
|
||||
};
|
||||
SyncStateOp::Create {
|
||||
model_id,
|
||||
checksum: fs.checksum.to_owned(),
|
||||
rel_path: fs.rel_path.to_owned(),
|
||||
}
|
||||
}
|
||||
SyncOp::DbUpdate { state, fs } => {
|
||||
// Push updates to arrays so we can do them all in a single
|
||||
// batch upsert to make foreign keys happy
|
||||
match fs.model {
|
||||
SyncModel::Workspace(m) => workspaces_to_upsert.push(m),
|
||||
SyncModel::Environment(m) => environments_to_upsert.push(m),
|
||||
SyncModel::Folder(m) => folders_to_upsert.push(m),
|
||||
SyncModel::HttpRequest(m) => http_requests_to_upsert.push(m),
|
||||
SyncModel::GrpcRequest(m) => grpc_requests_to_upsert.push(m),
|
||||
}
|
||||
SyncStateOp::Update {
|
||||
state: state.to_owned(),
|
||||
checksum: fs.checksum.to_owned(),
|
||||
rel_path: fs.rel_path.to_owned(),
|
||||
}
|
||||
}
|
||||
SyncOp::DbDelete { model, state } => {
|
||||
delete_model(window, &model).await?;
|
||||
SyncStateOp::Delete {
|
||||
state: state.to_owned(),
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
let upserted_models = batch_upsert(
|
||||
window,
|
||||
workspaces_to_upsert,
|
||||
environments_to_upsert,
|
||||
folders_to_upsert,
|
||||
http_requests_to_upsert,
|
||||
grpc_requests_to_upsert,
|
||||
)
|
||||
.await?;
|
||||
|
||||
// Ensure we creat WorkspaceMeta models for each new workspace, with the appropriate sync dir
|
||||
let sync_dir_string = sync_dir.to_string_lossy().to_string();
|
||||
for workspace in upserted_models.workspaces {
|
||||
let r = match get_workspace_meta(window, &workspace).await {
|
||||
Ok(Some(m)) => {
|
||||
if m.setting_sync_dir == Some(sync_dir_string.clone()) {
|
||||
// We don't need to update if unchanged
|
||||
continue;
|
||||
}
|
||||
let wm = WorkspaceMeta {
|
||||
setting_sync_dir: Some(sync_dir.to_string_lossy().to_string()),
|
||||
..m
|
||||
};
|
||||
upsert_workspace_meta(window, wm, &UpdateSource::Sync).await
|
||||
}
|
||||
Ok(None) => {
|
||||
let wm = WorkspaceMeta {
|
||||
workspace_id: workspace_id.to_string(),
|
||||
setting_sync_dir: Some(sync_dir.to_string_lossy().to_string()),
|
||||
..Default::default()
|
||||
};
|
||||
upsert_workspace_meta(window, wm, &UpdateSource::Sync).await
|
||||
}
|
||||
Err(e) => Err(e),
|
||||
};
|
||||
|
||||
if let Err(e) = r {
|
||||
warn!("Failed to upsert workspace meta for synced workspace {e:?}");
|
||||
}
|
||||
}
|
||||
|
||||
Ok(sync_state_ops)
|
||||
}
|
||||
|
||||
@@ -331,178 +470,55 @@ pub(crate) enum SyncStateOp {
|
||||
},
|
||||
}
|
||||
|
||||
/// Flush a DB model to the filesystem
|
||||
async fn apply_sync_op<R: Runtime>(
|
||||
window: &WebviewWindow<R>,
|
||||
workspace: &Workspace,
|
||||
op: &SyncOp,
|
||||
) -> Result<SyncStateOp> {
|
||||
let sync_state_op = match op {
|
||||
SyncOp::FsCreate { model } => {
|
||||
let rel_path = derive_model_filename(&model);
|
||||
let abs_path = derive_full_model_path(workspace, &model)?;
|
||||
let (content, checksum) = model.to_file_contents(&rel_path)?;
|
||||
let mut f = File::create(&abs_path).await?;
|
||||
f.write_all(&content).await?;
|
||||
SyncStateOp::Create {
|
||||
model_id: model.id(),
|
||||
checksum,
|
||||
rel_path,
|
||||
}
|
||||
}
|
||||
SyncOp::FsUpdate { model, state } => {
|
||||
// Always write the existing path
|
||||
let rel_path = Path::new(&state.rel_path);
|
||||
let abs_path = Path::new(&state.sync_dir).join(&rel_path);
|
||||
let (content, checksum) = model.to_file_contents(&rel_path)?;
|
||||
let mut f = File::create(&abs_path).await?;
|
||||
f.write_all(&content).await?;
|
||||
SyncStateOp::Update {
|
||||
state: state.to_owned(),
|
||||
checksum,
|
||||
rel_path: rel_path.to_owned(),
|
||||
}
|
||||
}
|
||||
SyncOp::FsDelete {
|
||||
state,
|
||||
fs: fs_candidate,
|
||||
} => match fs_candidate {
|
||||
None => SyncStateOp::Delete {
|
||||
state: state.to_owned(),
|
||||
},
|
||||
Some(_) => {
|
||||
// Always delete the existing path
|
||||
let rel_path = Path::new(&state.rel_path);
|
||||
let abs_path = Path::new(&state.sync_dir).join(&rel_path);
|
||||
fs::remove_file(&abs_path).await?;
|
||||
SyncStateOp::Delete {
|
||||
state: state.to_owned(),
|
||||
}
|
||||
}
|
||||
},
|
||||
SyncOp::DbCreate { fs } => {
|
||||
upsert_model(window, &fs.model).await?;
|
||||
SyncStateOp::Create {
|
||||
model_id: fs.model.id(),
|
||||
checksum: fs.checksum.to_owned(),
|
||||
rel_path: fs.rel_path.to_owned(),
|
||||
}
|
||||
}
|
||||
SyncOp::DbUpdate { state, fs } => {
|
||||
upsert_model(window, &fs.model).await?;
|
||||
SyncStateOp::Update {
|
||||
state: state.to_owned(),
|
||||
checksum: fs.checksum.to_owned(),
|
||||
rel_path: fs.rel_path.to_owned(),
|
||||
}
|
||||
}
|
||||
SyncOp::DbDelete { model, state } => {
|
||||
delete_model(window, model).await?;
|
||||
SyncStateOp::Delete {
|
||||
state: state.to_owned(),
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Ok(sync_state_op)
|
||||
}
|
||||
|
||||
pub(crate) async fn apply_sync_state_ops<R: Runtime>(
|
||||
window: &WebviewWindow<R>,
|
||||
workspace: &Workspace,
|
||||
workspace_id: &str,
|
||||
sync_dir: &Path,
|
||||
ops: Vec<SyncStateOp>,
|
||||
) -> Result<()> {
|
||||
for op in ops {
|
||||
apply_sync_state_op(window, workspace, op).await?
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn apply_sync_state_op<R: Runtime>(
|
||||
window: &WebviewWindow<R>,
|
||||
workspace: &Workspace,
|
||||
op: SyncStateOp,
|
||||
) -> Result<()> {
|
||||
let dir_path = get_workspace_sync_dir(workspace)?;
|
||||
match op {
|
||||
SyncStateOp::Create {
|
||||
checksum,
|
||||
rel_path,
|
||||
model_id,
|
||||
} => {
|
||||
let sync_state = SyncState {
|
||||
workspace_id: workspace.to_owned().id,
|
||||
match op {
|
||||
SyncStateOp::Create {
|
||||
checksum,
|
||||
rel_path,
|
||||
model_id,
|
||||
} => {
|
||||
let sync_state = SyncState {
|
||||
workspace_id: workspace_id.to_string(),
|
||||
model_id,
|
||||
checksum,
|
||||
sync_dir: sync_dir.to_str().unwrap().to_string(),
|
||||
rel_path: rel_path.to_str().unwrap().to_string(),
|
||||
flushed_at: Utc::now().naive_utc(),
|
||||
..Default::default()
|
||||
};
|
||||
upsert_sync_state(window, sync_state).await?;
|
||||
}
|
||||
SyncStateOp::Update {
|
||||
state: sync_state,
|
||||
checksum,
|
||||
sync_dir: dir_path.to_str().unwrap().to_string(),
|
||||
rel_path: rel_path.to_str().unwrap().to_string(),
|
||||
flushed_at: Utc::now().naive_utc(),
|
||||
..Default::default()
|
||||
};
|
||||
upsert_sync_state(window, sync_state).await?;
|
||||
}
|
||||
SyncStateOp::Update {
|
||||
state: sync_state,
|
||||
checksum,
|
||||
rel_path,
|
||||
} => {
|
||||
let sync_state = SyncState {
|
||||
checksum,
|
||||
sync_dir: dir_path.to_str().unwrap().to_string(),
|
||||
rel_path: rel_path.to_str().unwrap().to_string(),
|
||||
flushed_at: Utc::now().naive_utc(),
|
||||
..sync_state
|
||||
};
|
||||
upsert_sync_state(window, sync_state).await?;
|
||||
}
|
||||
SyncStateOp::Delete { state } => {
|
||||
delete_sync_state(window, state.id.as_str()).await?;
|
||||
rel_path,
|
||||
} => {
|
||||
let sync_state = SyncState {
|
||||
checksum,
|
||||
sync_dir: sync_dir.to_str().unwrap().to_string(),
|
||||
rel_path: rel_path.to_str().unwrap().to_string(),
|
||||
flushed_at: Utc::now().naive_utc(),
|
||||
..sync_state
|
||||
};
|
||||
upsert_sync_state(window, sync_state).await?;
|
||||
}
|
||||
SyncStateOp::Delete { state } => {
|
||||
delete_sync_state(window, state.id.as_str()).await?;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn get_workspace_sync_dir(workspace: &Workspace) -> Result<PathBuf> {
|
||||
let workspace_id = workspace.to_owned().id;
|
||||
match workspace.setting_sync_dir.to_owned() {
|
||||
Some(d) => Ok(Path::new(&d).to_path_buf()),
|
||||
None => Err(WorkspaceSyncNotConfigured(workspace_id)),
|
||||
}
|
||||
}
|
||||
|
||||
fn derive_full_model_path(workspace: &Workspace, m: &SyncModel) -> Result<PathBuf> {
|
||||
let dir = get_workspace_sync_dir(workspace)?;
|
||||
Ok(dir.join(derive_model_filename(m)))
|
||||
}
|
||||
|
||||
fn derive_model_filename(m: &SyncModel) -> PathBuf {
|
||||
let rel = format!("yaak.2.{}.yaml", m.id());
|
||||
let rel = Path::new(&rel).to_path_buf();
|
||||
|
||||
// Ensure parent dir exists
|
||||
rel
|
||||
}
|
||||
|
||||
async fn upsert_model<R: Runtime>(window: &WebviewWindow<R>, m: &SyncModel) -> Result<()> {
|
||||
match m {
|
||||
SyncModel::Workspace(m) => {
|
||||
upsert_workspace(window, m.to_owned(), &UpdateSource::Sync).await?;
|
||||
}
|
||||
SyncModel::Environment(m) => {
|
||||
upsert_environment(window, m.to_owned(), &UpdateSource::Sync).await?;
|
||||
}
|
||||
SyncModel::Folder(m) => {
|
||||
upsert_folder(window, m.to_owned(), &UpdateSource::Sync).await?;
|
||||
}
|
||||
SyncModel::HttpRequest(m) => {
|
||||
upsert_http_request(window, m.to_owned(), &UpdateSource::Sync).await?;
|
||||
}
|
||||
SyncModel::GrpcRequest(m) => {
|
||||
upsert_grpc_request(window, m.to_owned(), &UpdateSource::Sync).await?;
|
||||
}
|
||||
};
|
||||
Ok(())
|
||||
let rel = format!("yaak.{}.yaml", m.id());
|
||||
Path::new(&rel).to_path_buf()
|
||||
}
|
||||
|
||||
async fn delete_model<R: Runtime>(window: &WebviewWindow<R>, model: &SyncModel) -> Result<()> {
|
||||
|
||||
Reference in New Issue
Block a user