mirror of
https://github.com/Start9Labs/start-sdk.git
synced 2026-03-30 12:21:57 +00:00
Merge pull request #17 from Start9Labs/chore/include-options
chore: including options
This commit is contained in:
93
backups.ts
93
backups.ts
@@ -1,21 +1,48 @@
|
|||||||
import { ok } from "./util.ts";
|
import { ok } from "./util.ts";
|
||||||
import * as T from "./types.ts";
|
import * as T from "./types.ts";
|
||||||
|
|
||||||
/**
|
export const DEFAULT_OPTIONS: T.BackupOptions = {
|
||||||
|
delete: true,
|
||||||
|
force: true,
|
||||||
|
ignoreExisting: false,
|
||||||
|
exclude: [],
|
||||||
|
};
|
||||||
|
type BackupSet = {
|
||||||
|
srcPath: string;
|
||||||
|
srcVolume: string;
|
||||||
|
dstPath: string;
|
||||||
|
dstVolume: string;
|
||||||
|
options?: Partial<T.BackupOptions>;
|
||||||
|
};
|
||||||
|
/**
|
||||||
* This utility simplifies the volume backup process.
|
* This utility simplifies the volume backup process.
|
||||||
* ```ts
|
* ```ts
|
||||||
* export const { createBackup, restoreBackup } = Backups.volumes("main").build();
|
* export const { createBackup, restoreBackup } = Backups.volumes("main").build();
|
||||||
* ```
|
* ```
|
||||||
*/
|
*
|
||||||
|
* Changing the options of the rsync, (ie exludes) use either
|
||||||
|
* ```ts
|
||||||
|
* Backups.volumes("main").set_options({exclude: ['bigdata/']}).volumes('excludedVolume').build()
|
||||||
|
* // or
|
||||||
|
* Backups.with_options({exclude: ['bigdata/']}).volumes('excludedVolume').build()
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
* Using the more fine control, using the addSets for more control
|
||||||
|
* ```ts
|
||||||
|
* Backups.addSets({
|
||||||
|
* srcVolume: 'main', srcPath:'smallData/', dstPath: 'main/smallData/', dstVolume: : Backups.BACKUP
|
||||||
|
* }, {
|
||||||
|
* srcVolume: 'main', srcPath:'bigData/', dstPath: 'main/bigData/', dstVolume: : Backups.BACKUP, options: {exclude:['bigData/excludeThis']}}
|
||||||
|
* ).build()
|
||||||
|
* ```
|
||||||
|
*/
|
||||||
export class Backups {
|
export class Backups {
|
||||||
static BACKUP = "BACKUP" as const;
|
static BACKUP = "BACKUP" as const;
|
||||||
public backupSet = [] as {
|
|
||||||
srcPath: string;
|
constructor(
|
||||||
srcVolume: string;
|
private options = DEFAULT_OPTIONS,
|
||||||
dstPath: string;
|
private backupSet = [] as BackupSet[],
|
||||||
dstVolume: string;
|
) {
|
||||||
}[];
|
|
||||||
constructor() {
|
|
||||||
}
|
}
|
||||||
static volumes(...volumeNames: string[]) {
|
static volumes(...volumeNames: string[]) {
|
||||||
return new Backups().addSets(...volumeNames.map((srcVolume) => ({
|
return new Backups().addSets(...volumeNames.map((srcVolume) => ({
|
||||||
@@ -26,24 +53,34 @@ export class Backups {
|
|||||||
})));
|
})));
|
||||||
}
|
}
|
||||||
static addSets(
|
static addSets(
|
||||||
...options: {
|
...options: BackupSet[]
|
||||||
srcPath: string;
|
|
||||||
srcVolume: string;
|
|
||||||
dstPath: string;
|
|
||||||
dstVolume: string;
|
|
||||||
}[]
|
|
||||||
) {
|
) {
|
||||||
return new Backups().addSets(...options);
|
return new Backups().addSets(...options);
|
||||||
}
|
}
|
||||||
|
static with_options(options?: Partial<T.BackupOptions>) {
|
||||||
|
return new Backups({ ...DEFAULT_OPTIONS, ...options });
|
||||||
|
}
|
||||||
|
set_options(options?: Partial<T.BackupOptions>) {
|
||||||
|
this.options = {
|
||||||
|
...this.options,
|
||||||
|
...options,
|
||||||
|
};
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
volumes(...volumeNames: string[]) {
|
||||||
|
return this.addSets(...volumeNames.map((srcVolume) => ({
|
||||||
|
srcVolume,
|
||||||
|
srcPath: "./",
|
||||||
|
dstPath: `./${srcVolume}/`,
|
||||||
|
dstVolume: Backups.BACKUP,
|
||||||
|
})));
|
||||||
|
}
|
||||||
addSets(
|
addSets(
|
||||||
...options: {
|
...options: BackupSet[]
|
||||||
srcPath: string;
|
|
||||||
srcVolume: string;
|
|
||||||
dstPath: string;
|
|
||||||
dstVolume: string;
|
|
||||||
}[]
|
|
||||||
) {
|
) {
|
||||||
options.forEach((x) => this.backupSet.push(x));
|
options.forEach((x) =>
|
||||||
|
this.backupSet.push({ ...x, options: { ...this.options, ...x.options } })
|
||||||
|
);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
build() {
|
build() {
|
||||||
@@ -58,10 +95,8 @@ export class Backups {
|
|||||||
await effects.runRsync({
|
await effects.runRsync({
|
||||||
...item,
|
...item,
|
||||||
options: {
|
options: {
|
||||||
delete: true,
|
...this.options,
|
||||||
force: true,
|
...item.options,
|
||||||
ignoreExisting: false,
|
|
||||||
exclude: [],
|
|
||||||
},
|
},
|
||||||
}).wait();
|
}).wait();
|
||||||
}
|
}
|
||||||
@@ -77,10 +112,8 @@ export class Backups {
|
|||||||
}
|
}
|
||||||
await effects.runRsync({
|
await effects.runRsync({
|
||||||
options: {
|
options: {
|
||||||
delete: true,
|
...this.options,
|
||||||
force: true,
|
...item.options,
|
||||||
ignoreExisting: false,
|
|
||||||
exclude: [],
|
|
||||||
},
|
},
|
||||||
srcVolume: item.dstVolume,
|
srcVolume: item.dstVolume,
|
||||||
dstVolume: item.srcVolume,
|
dstVolume: item.srcVolume,
|
||||||
|
|||||||
238
types.ts
238
types.ts
@@ -1,7 +1,10 @@
|
|||||||
// deno-lint-ignore no-namespace
|
// deno-lint-ignore no-namespace
|
||||||
export namespace ExpectedExports {
|
export namespace ExpectedExports {
|
||||||
/** Set configuration is called after we have modified and saved the configuration in the embassy ui. Use this to make a file for the docker to read from for configuration. */
|
/** Set configuration is called after we have modified and saved the configuration in the embassy ui. Use this to make a file for the docker to read from for configuration. */
|
||||||
export type setConfig = (effects: Effects, input: Config) => Promise<ResultType<SetResult>>;
|
export type setConfig = (
|
||||||
|
effects: Effects,
|
||||||
|
input: Config,
|
||||||
|
) => Promise<ResultType<SetResult>>;
|
||||||
/** Get configuration returns a shape that describes the format that the embassy ui will generate, and later send to the set config */
|
/** Get configuration returns a shape that describes the format that the embassy ui will generate, and later send to the set config */
|
||||||
export type getConfig = (effects: Effects) => Promise<ResultType<ConfigRes>>;
|
export type getConfig = (effects: Effects) => Promise<ResultType<ConfigRes>>;
|
||||||
/** These are how we make sure the our dependency configurations are valid and if not how to fix them. */
|
/** These are how we make sure the our dependency configurations are valid and if not how to fix them. */
|
||||||
@@ -9,17 +12,31 @@ export namespace ExpectedExports {
|
|||||||
/** For backing up service data though the embassyOS UI */
|
/** For backing up service data though the embassyOS UI */
|
||||||
export type createBackup = (effects: Effects) => Promise<ResultType<unknown>>;
|
export type createBackup = (effects: Effects) => Promise<ResultType<unknown>>;
|
||||||
/** For restoring service data that was previously backed up using the embassyOS UI create backup flow. Backup restores are also triggered via the embassyOS UI, or doing a system restore flow during setup. */
|
/** For restoring service data that was previously backed up using the embassyOS UI create backup flow. Backup restores are also triggered via the embassyOS UI, or doing a system restore flow during setup. */
|
||||||
export type restoreBackup = (effects: Effects) => Promise<ResultType<unknown>>;
|
export type restoreBackup = (
|
||||||
|
effects: Effects,
|
||||||
|
) => Promise<ResultType<unknown>>;
|
||||||
/** Properties are used to get values from the docker, like a username + password, what ports we are hosting from */
|
/** Properties are used to get values from the docker, like a username + password, what ports we are hosting from */
|
||||||
export type properties = (effects: Effects) => Promise<ResultType<Properties>>;
|
export type properties = (
|
||||||
|
effects: Effects,
|
||||||
|
) => Promise<ResultType<Properties>>;
|
||||||
|
|
||||||
export type health = {
|
export type health = {
|
||||||
/** Should be the health check id */
|
/** Should be the health check id */
|
||||||
[id: string]: (effects: Effects, dateMs: number) => Promise<ResultType<unknown>>;
|
[id: string]: (
|
||||||
|
effects: Effects,
|
||||||
|
dateMs: number,
|
||||||
|
) => Promise<ResultType<unknown>>;
|
||||||
};
|
};
|
||||||
export type migration = (effects: Effects, version: string, ...args: unknown[]) => Promise<ResultType<MigrationRes>>;
|
export type migration = (
|
||||||
|
effects: Effects,
|
||||||
|
version: string,
|
||||||
|
...args: unknown[]
|
||||||
|
) => Promise<ResultType<MigrationRes>>;
|
||||||
export type action = {
|
export type action = {
|
||||||
[id: string]: (effects: Effects, config?: Config) => Promise<ResultType<ActionResult>>;
|
[id: string]: (
|
||||||
|
effects: Effects,
|
||||||
|
config?: Config,
|
||||||
|
) => Promise<ResultType<ActionResult>>;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -32,7 +49,9 @@ export namespace ExpectedExports {
|
|||||||
/** Used to reach out from the pure js runtime */
|
/** Used to reach out from the pure js runtime */
|
||||||
export type Effects = {
|
export type Effects = {
|
||||||
/** Usable when not sandboxed */
|
/** Usable when not sandboxed */
|
||||||
writeFile(input: { path: string; volumeId: string; toWrite: string }): Promise<void>;
|
writeFile(
|
||||||
|
input: { path: string; volumeId: string; toWrite: string },
|
||||||
|
): Promise<void>;
|
||||||
readFile(input: { volumeId: string; path: string }): Promise<string>;
|
readFile(input: { volumeId: string; path: string }): Promise<string>;
|
||||||
metadata(input: { volumeId: string; path: string }): Promise<Metadata>;
|
metadata(input: { volumeId: string; path: string }): Promise<Metadata>;
|
||||||
/** Create a directory. Usable when not sandboxed */
|
/** Create a directory. Usable when not sandboxed */
|
||||||
@@ -42,12 +61,18 @@ export type Effects = {
|
|||||||
removeFile(input: { volumeId: string; path: string }): Promise<void>;
|
removeFile(input: { volumeId: string; path: string }): Promise<void>;
|
||||||
|
|
||||||
/** Write a json file into an object. Usable when not sandboxed */
|
/** Write a json file into an object. Usable when not sandboxed */
|
||||||
writeJsonFile(input: { volumeId: string; path: string; toWrite: Record<string, unknown> }): Promise<void>;
|
writeJsonFile(
|
||||||
|
input: { volumeId: string; path: string; toWrite: Record<string, unknown> },
|
||||||
|
): Promise<void>;
|
||||||
|
|
||||||
/** Read a json file into an object */
|
/** Read a json file into an object */
|
||||||
readJsonFile(input: { volumeId: string; path: string }): Promise<Record<string, unknown>>;
|
readJsonFile(
|
||||||
|
input: { volumeId: string; path: string },
|
||||||
|
): Promise<Record<string, unknown>>;
|
||||||
|
|
||||||
runCommand(input: { command: string; args?: string[]; timeoutMillis?: number }): Promise<ResultType<string>>;
|
runCommand(
|
||||||
|
input: { command: string; args?: string[]; timeoutMillis?: number },
|
||||||
|
): Promise<ResultType<string>>;
|
||||||
runDaemon(input: { command: string; args?: string[] }): {
|
runDaemon(input: { command: string; args?: string[] }): {
|
||||||
wait(): Promise<ResultType<string>>;
|
wait(): Promise<ResultType<string>>;
|
||||||
term(): Promise<void>;
|
term(): Promise<void>;
|
||||||
@@ -77,7 +102,7 @@ export type Effects = {
|
|||||||
method?: "GET" | "POST" | "PUT" | "DELETE" | "HEAD" | "PATCH";
|
method?: "GET" | "POST" | "PUT" | "DELETE" | "HEAD" | "PATCH";
|
||||||
headers?: Record<string, string>;
|
headers?: Record<string, string>;
|
||||||
body?: string;
|
body?: string;
|
||||||
}
|
},
|
||||||
): Promise<{
|
): Promise<{
|
||||||
method: string;
|
method: string;
|
||||||
ok: boolean;
|
ok: boolean;
|
||||||
@@ -91,18 +116,25 @@ export type Effects = {
|
|||||||
}>;
|
}>;
|
||||||
|
|
||||||
runRsync(options: {
|
runRsync(options: {
|
||||||
srcVolume: string,
|
srcVolume: string;
|
||||||
dstVolume: string,
|
dstVolume: string;
|
||||||
srcPath: string,
|
srcPath: string;
|
||||||
dstPath: string,
|
dstPath: string;
|
||||||
// rsync options: https://linux.die.net/man/1/rsync
|
// rsync options: https://linux.die.net/man/1/rsync
|
||||||
options: {
|
options: BackupOptions;
|
||||||
delete: boolean,
|
}): {
|
||||||
force: boolean,
|
id: () => Promise<string>;
|
||||||
ignoreExisting: boolean,
|
wait: () => Promise<null>;
|
||||||
exclude: string[]
|
progress: () => Promise<number>;
|
||||||
}
|
};
|
||||||
}): {id: () => Promise<string>, wait: () => Promise<null>, progress: () => Promise<number>}
|
};
|
||||||
|
|
||||||
|
// rsync options: https://linux.die.net/man/1/rsync
|
||||||
|
export type BackupOptions = {
|
||||||
|
delete: boolean;
|
||||||
|
force: boolean;
|
||||||
|
ignoreExisting: boolean;
|
||||||
|
exclude: string[];
|
||||||
};
|
};
|
||||||
export type Metadata = {
|
export type Metadata = {
|
||||||
fileType: string;
|
fileType: string;
|
||||||
@@ -177,8 +209,8 @@ export type Target<T extends string, V> = V & {
|
|||||||
|
|
||||||
export type UniqueBy =
|
export type UniqueBy =
|
||||||
| {
|
| {
|
||||||
any: UniqueBy[];
|
any: UniqueBy[];
|
||||||
}
|
}
|
||||||
| string
|
| string
|
||||||
| null;
|
| null;
|
||||||
|
|
||||||
@@ -188,19 +220,19 @@ export type WithNullable<T> = T & {
|
|||||||
export type DefaultString =
|
export type DefaultString =
|
||||||
| string
|
| string
|
||||||
| {
|
| {
|
||||||
/** The chars available for the randome generation */
|
/** The chars available for the randome generation */
|
||||||
charset?: string;
|
charset?: string;
|
||||||
/** Length that we generate to */
|
/** Length that we generate to */
|
||||||
len: number;
|
len: number;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type ValueSpecString = // deno-lint-ignore ban-types
|
export type ValueSpecString = // deno-lint-ignore ban-types
|
||||||
(
|
(
|
||||||
| {}
|
| {}
|
||||||
| {
|
| {
|
||||||
pattern: string;
|
pattern: string;
|
||||||
"pattern-description": string;
|
"pattern-description": string;
|
||||||
}
|
}
|
||||||
) & {
|
) & {
|
||||||
copyable?: boolean;
|
copyable?: boolean;
|
||||||
masked?: boolean;
|
masked?: boolean;
|
||||||
@@ -217,63 +249,71 @@ export type ValueSpecNumber = {
|
|||||||
export type ValueSpecBoolean = Record<string, unknown>;
|
export type ValueSpecBoolean = Record<string, unknown>;
|
||||||
export type ValueSpecAny =
|
export type ValueSpecAny =
|
||||||
| Tag<"boolean", WithDescription<WithDefault<ValueSpecBoolean, boolean>>>
|
| Tag<"boolean", WithDescription<WithDefault<ValueSpecBoolean, boolean>>>
|
||||||
| Tag<"string", WithDescription<WithNullableDefault<WithNullable<ValueSpecString>, DefaultString>>>
|
|
||||||
| Tag<"number", WithDescription<WithNullableDefault<WithNullable<ValueSpecNumber>, number>>>
|
|
||||||
| Tag<
|
| Tag<
|
||||||
"enum",
|
"string",
|
||||||
WithDescription<
|
WithDescription<
|
||||||
WithDefault<
|
WithNullableDefault<WithNullable<ValueSpecString>, DefaultString>
|
||||||
{
|
>
|
||||||
values: readonly string[] | string[];
|
>
|
||||||
"value-names": {
|
| Tag<
|
||||||
[key: string]: string;
|
"number",
|
||||||
};
|
WithDescription<WithNullableDefault<WithNullable<ValueSpecNumber>, number>>
|
||||||
},
|
>
|
||||||
string
|
| Tag<
|
||||||
>
|
"enum",
|
||||||
|
WithDescription<
|
||||||
|
WithDefault<
|
||||||
|
{
|
||||||
|
values: readonly string[] | string[];
|
||||||
|
"value-names": {
|
||||||
|
[key: string]: string;
|
||||||
|
};
|
||||||
|
},
|
||||||
|
string
|
||||||
>
|
>
|
||||||
>
|
>
|
||||||
|
>
|
||||||
| Tag<"list", ValueSpecList>
|
| Tag<"list", ValueSpecList>
|
||||||
| Tag<"object", WithDescription<WithNullableDefault<ValueSpecObject, Config>>>
|
| Tag<"object", WithDescription<WithNullableDefault<ValueSpecObject, Config>>>
|
||||||
| Tag<"union", WithDescription<WithDefault<ValueSpecUnion, string>>>
|
| Tag<"union", WithDescription<WithDefault<ValueSpecUnion, string>>>
|
||||||
| Tag<
|
| Tag<
|
||||||
"pointer",
|
"pointer",
|
||||||
WithDescription<
|
WithDescription<
|
||||||
| Subtype<
|
| Subtype<
|
||||||
"package",
|
"package",
|
||||||
| Target<
|
| Target<
|
||||||
"tor-key",
|
"tor-key",
|
||||||
{
|
{
|
||||||
"package-id": string;
|
"package-id": string;
|
||||||
interface: string;
|
interface: string;
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
| Target<
|
| Target<
|
||||||
"tor-address",
|
"tor-address",
|
||||||
{
|
{
|
||||||
"package-id": string;
|
"package-id": string;
|
||||||
interface: string;
|
interface: string;
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
| Target<
|
| Target<
|
||||||
"lan-address",
|
"lan-address",
|
||||||
{
|
{
|
||||||
"package-id": string;
|
"package-id": string;
|
||||||
interface: string;
|
interface: string;
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
| Target<
|
| Target<
|
||||||
"config",
|
"config",
|
||||||
{
|
{
|
||||||
"package-id": string;
|
"package-id": string;
|
||||||
selector: string;
|
selector: string;
|
||||||
multi: boolean;
|
multi: boolean;
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
>
|
|
||||||
| Subtype<"system", Record<string, unknown>>
|
|
||||||
>
|
>
|
||||||
>;
|
| Subtype<"system", Record<string, unknown>>
|
||||||
|
>
|
||||||
|
>;
|
||||||
export type ValueSpecUnion = {
|
export type ValueSpecUnion = {
|
||||||
/** What tag for the specification, for tag unions */
|
/** What tag for the specification, for tag unions */
|
||||||
tag: {
|
tag: {
|
||||||
@@ -297,12 +337,32 @@ export type ValueSpecObject = {
|
|||||||
"unique-by"?: UniqueBy;
|
"unique-by"?: UniqueBy;
|
||||||
};
|
};
|
||||||
export type ValueSpecList =
|
export type ValueSpecList =
|
||||||
| Subtype<"boolean", WithDescription<WithDefault<ListSpec<ValueSpecBoolean>, boolean[]>>>
|
| Subtype<
|
||||||
| Subtype<"string", WithDescription<WithDefault<ListSpec<ValueSpecString>, string[]>>>
|
"boolean",
|
||||||
| Subtype<"number", WithDescription<WithDefault<ListSpec<ValueSpecNumber>, number[]>>>
|
WithDescription<WithDefault<ListSpec<ValueSpecBoolean>, boolean[]>>
|
||||||
| Subtype<"enum", WithDescription<WithDefault<ListSpec<ValueSpecEnum>, string[]>>>
|
>
|
||||||
| Subtype<"object", WithDescription<WithNullableDefault<ListSpec<ValueSpecObject>, Record<string, unknown>[]>>>
|
| Subtype<
|
||||||
| Subtype<"union", WithDescription<WithDefault<ListSpec<ValueSpecUnion>, string[]>>>;
|
"string",
|
||||||
|
WithDescription<WithDefault<ListSpec<ValueSpecString>, string[]>>
|
||||||
|
>
|
||||||
|
| Subtype<
|
||||||
|
"number",
|
||||||
|
WithDescription<WithDefault<ListSpec<ValueSpecNumber>, number[]>>
|
||||||
|
>
|
||||||
|
| Subtype<
|
||||||
|
"enum",
|
||||||
|
WithDescription<WithDefault<ListSpec<ValueSpecEnum>, string[]>>
|
||||||
|
>
|
||||||
|
| Subtype<
|
||||||
|
"object",
|
||||||
|
WithDescription<
|
||||||
|
WithNullableDefault<ListSpec<ValueSpecObject>, Record<string, unknown>[]>
|
||||||
|
>
|
||||||
|
>
|
||||||
|
| Subtype<
|
||||||
|
"union",
|
||||||
|
WithDescription<WithDefault<ListSpec<ValueSpecUnion>, string[]>>
|
||||||
|
>;
|
||||||
export type ValueSpecEnum = {
|
export type ValueSpecEnum = {
|
||||||
values: string[];
|
values: string[];
|
||||||
"value-names": { [key: string]: string };
|
"value-names": { [key: string]: string };
|
||||||
@@ -354,8 +414,8 @@ export type DependsOn = {
|
|||||||
export type KnownError =
|
export type KnownError =
|
||||||
| { error: string }
|
| { error: string }
|
||||||
| {
|
| {
|
||||||
"error-code": [number, string] | readonly [number, string];
|
"error-code": [number, string] | readonly [number, string];
|
||||||
};
|
};
|
||||||
export type ResultType<T> = KnownError | { result: T };
|
export type ResultType<T> = KnownError | { result: T };
|
||||||
|
|
||||||
export type PackagePropertiesV2 = {
|
export type PackagePropertiesV2 = {
|
||||||
|
|||||||
Reference in New Issue
Block a user