mirror of
https://github.com/Start9Labs/start-sdk.git
synced 2026-03-26 10:21:55 +00:00
feat: remove the file things since we now are in node
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
import { SDKManifest } from "../manifest/ManifestTypes"
|
||||
import * as T from "../types"
|
||||
import fs from "fs"
|
||||
|
||||
export type BACKUP = "BACKUP"
|
||||
export const DEFAULT_OPTIONS: T.BackupOptions = {
|
||||
@@ -93,47 +94,45 @@ export class Backups<M extends SDKManifest> {
|
||||
const createBackup: T.ExpectedExports.createBackup = async ({
|
||||
effects,
|
||||
}) => {
|
||||
const previousItems = (
|
||||
await effects
|
||||
.readDir({
|
||||
volumeId: Backups.BACKUP,
|
||||
path: ".",
|
||||
})
|
||||
.catch(() => [])
|
||||
).map((x) => `${x}`)
|
||||
const backupPaths = this.backupSet
|
||||
.filter((x) => x.dstVolume === Backups.BACKUP)
|
||||
.map((x) => x.dstPath)
|
||||
.map((x) => x.replace(/\.\/([^]*)\//, "$1"))
|
||||
const filteredItems = previousItems.filter(
|
||||
(x) => backupPaths.indexOf(x) === -1,
|
||||
)
|
||||
for (const itemToRemove of filteredItems) {
|
||||
effects.console.error(`Trying to remove ${itemToRemove}`)
|
||||
await effects
|
||||
.removeDir({
|
||||
volumeId: Backups.BACKUP,
|
||||
path: itemToRemove,
|
||||
})
|
||||
.catch(() =>
|
||||
effects.removeFile({
|
||||
volumeId: Backups.BACKUP,
|
||||
path: itemToRemove,
|
||||
}),
|
||||
)
|
||||
.catch(() => {
|
||||
effects.console.warn(
|
||||
`Failed to remove ${itemToRemove} from backup volume`,
|
||||
)
|
||||
})
|
||||
}
|
||||
// const previousItems = (
|
||||
// await effects
|
||||
// .readDir({
|
||||
// volumeId: Backups.BACKUP,
|
||||
// path: ".",
|
||||
// })
|
||||
// .catch(() => [])
|
||||
// ).map((x) => `${x}`)
|
||||
// const backupPaths = this.backupSet
|
||||
// .filter((x) => x.dstVolume === Backups.BACKUP)
|
||||
// .map((x) => x.dstPath)
|
||||
// .map((x) => x.replace(/\.\/([^]*)\//, "$1"))
|
||||
// const filteredItems = previousItems.filter(
|
||||
// (x) => backupPaths.indexOf(x) === -1,
|
||||
// )
|
||||
// for (const itemToRemove of filteredItems) {
|
||||
// effects.console.error(`Trying to remove ${itemToRemove}`)
|
||||
// await effects
|
||||
// .removeDir({
|
||||
// volumeId: Backups.BACKUP,
|
||||
// path: itemToRemove,
|
||||
// })
|
||||
// .catch(() =>
|
||||
// effects.removeFile({
|
||||
// volumeId: Backups.BACKUP,
|
||||
// path: itemToRemove,
|
||||
// }),
|
||||
// )
|
||||
// .catch(() => {
|
||||
// console.warn(`Failed to remove ${itemToRemove} from backup volume`)
|
||||
// })
|
||||
// }
|
||||
for (const item of this.backupSet) {
|
||||
if (notEmptyPath(item.dstPath)) {
|
||||
await effects.createDir({
|
||||
volumeId: item.dstVolume,
|
||||
path: item.dstPath,
|
||||
})
|
||||
}
|
||||
// if (notEmptyPath(item.dstPath)) {
|
||||
// await effects.createDir({
|
||||
// volumeId: item.dstVolume,
|
||||
// path: item.dstPath,
|
||||
// })
|
||||
// }
|
||||
await effects
|
||||
.runRsync({
|
||||
...item,
|
||||
@@ -150,12 +149,14 @@ export class Backups<M extends SDKManifest> {
|
||||
effects,
|
||||
}) => {
|
||||
for (const item of this.backupSet) {
|
||||
if (notEmptyPath(item.srcPath)) {
|
||||
await effects.createDir({
|
||||
volumeId: item.srcVolume,
|
||||
path: item.srcPath,
|
||||
})
|
||||
}
|
||||
// if (notEmptyPath(item.srcPath)) {
|
||||
// await new Promise((resolve, reject) => fs.mkdir(items.src)).createDir(
|
||||
// {
|
||||
// volumeId: item.srcVolume,
|
||||
// path: item.srcPath,
|
||||
// },
|
||||
// )
|
||||
// }
|
||||
await effects
|
||||
.runRsync({
|
||||
options: {
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import { string } from "ts-matches"
|
||||
import { Backups } from "./Backups"
|
||||
import { SDKManifest } from "../manifest/ManifestTypes"
|
||||
import { BackupOptions, ExpectedExports } from "../types"
|
||||
import { ExpectedExports } from "../types"
|
||||
import { _ } from "../util"
|
||||
|
||||
export type SetupBackupsParams<M extends SDKManifest> = Array<
|
||||
|
||||
@@ -60,7 +60,7 @@ export function setupConfig<
|
||||
return {
|
||||
setConfig: (async ({ effects, input }) => {
|
||||
if (!validator.test(input)) {
|
||||
await effects.console.error(String(validator.errorMessage(input)))
|
||||
await console.error(String(validator.errorMessage(input)))
|
||||
return { error: "Set config type error for config" }
|
||||
}
|
||||
const { restart } = await write({
|
||||
|
||||
@@ -23,9 +23,9 @@ export const checkWebUrl = async (
|
||||
message: successMessage,
|
||||
}))
|
||||
.catch((e) => {
|
||||
effects.console.warn(`Error while fetching URL: ${url}`)
|
||||
effects.console.error(JSON.stringify(e))
|
||||
effects.console.error(e.toString())
|
||||
console.warn(`Error while fetching URL: ${url}`)
|
||||
console.error(JSON.stringify(e))
|
||||
console.error(e.toString())
|
||||
return { status: "failing" as const, message: errorMessage }
|
||||
})
|
||||
}
|
||||
|
||||
@@ -23,9 +23,9 @@ export const runHealthScript = async <A extends string>(
|
||||
effects.runCommand(runCommand, { timeoutMillis: timeout }),
|
||||
timeoutPromise(timeout),
|
||||
]).catch((e) => {
|
||||
effects.console.warn(errorMessage)
|
||||
effects.console.warn(JSON.stringify(e))
|
||||
effects.console.warn(e.toString())
|
||||
console.warn(errorMessage)
|
||||
console.warn(JSON.stringify(e))
|
||||
console.warn(e.toString())
|
||||
throw { status: "failing", message: errorMessage } as CheckResult
|
||||
})
|
||||
return {
|
||||
|
||||
71
lib/types.ts
71
lib/types.ts
@@ -181,63 +181,11 @@ export type NetworkInterface = {
|
||||
|
||||
/** Used to reach out from the pure js runtime */
|
||||
export type Effects = {
|
||||
/** Usable when not sandboxed */
|
||||
writeFile(input: {
|
||||
path: string
|
||||
volumeId: string
|
||||
toWrite: string
|
||||
}): Promise<void>
|
||||
readFile(input: { volumeId: string; path: string }): Promise<string>
|
||||
/** Usable when not sandboxed */
|
||||
appendFile(input: {
|
||||
path: string
|
||||
volumeId: string
|
||||
toWrite: string
|
||||
}): Promise<void>
|
||||
/**
|
||||
* Move file from src to dst
|
||||
* Usable when not sandboxed */
|
||||
moveFile(input: {
|
||||
srcVolume: string
|
||||
dstVolume: string
|
||||
srcPath: string
|
||||
dstPath: string
|
||||
}): Promise<void>
|
||||
/**
|
||||
* copy from src to dst
|
||||
* Usable when not sandboxed */
|
||||
copyFile(input: {
|
||||
srcVolume: string
|
||||
dstVolume: string
|
||||
srcPath: string
|
||||
dstPath: string
|
||||
}): Promise<void>
|
||||
metadata(input: { volumeId: string; path: string }): Promise<Metadata>
|
||||
/** Create a directory. Usable when not sandboxed */
|
||||
createDir(input: { volumeId: string; path: string }): Promise<string>
|
||||
|
||||
readDir(input: { volumeId: string; path: string }): Promise<string[]>
|
||||
/** Remove a directory. Usable when not sandboxed */
|
||||
removeDir(input: { volumeId: string; path: string }): Promise<string>
|
||||
removeFile(input: { volumeId: string; path: string }): Promise<void>
|
||||
|
||||
/** Write a json file into an object. Usable when not sandboxed */
|
||||
writeJsonFile(input: {
|
||||
volumeId: string
|
||||
path: string
|
||||
toWrite: Record<string, unknown>
|
||||
}): Promise<void>
|
||||
|
||||
/** Read a json file into an object */
|
||||
readJsonFile(input: {
|
||||
volumeId: string
|
||||
path: string
|
||||
}): Promise<Record<string, unknown>>
|
||||
|
||||
runCommand<A extends string>(
|
||||
command: ValidIfNoStupidEscape<A> | [string, ...string[]],
|
||||
options?: {
|
||||
timeoutMillis?: number
|
||||
env?: Record<string, string>
|
||||
},
|
||||
): Promise<string>
|
||||
runDaemon<A extends string>(
|
||||
@@ -252,23 +200,6 @@ export type Effects = {
|
||||
/** Uses the chmod on the system */
|
||||
chmod(input: { volumeId: string; path: string; mode: string }): Promise<null>
|
||||
|
||||
sleep(timeMs: TimeMs): Promise<null>
|
||||
|
||||
console: {
|
||||
/** Log at the trace level */
|
||||
log(whatToPrint: string): Promise<void>
|
||||
/** Log at the trace level */
|
||||
trace(whatToPrint: string): Promise<void>
|
||||
/** Log at the warn level */
|
||||
warn(whatToPrint: string): Promise<void>
|
||||
/** Log at the error level */
|
||||
error(whatToPrint: string): Promise<void>
|
||||
/** Log at the debug level */
|
||||
debug(whatToPrint: string): Promise<void>
|
||||
/** Log at the info level */
|
||||
info(whatToPrint: string): Promise<void>
|
||||
}
|
||||
|
||||
/** Sandbox mode lets us read but not write */
|
||||
is_sandboxed(): boolean
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@ import * as matches from "ts-matches"
|
||||
import * as YAML from "yaml"
|
||||
import * as TOML from "@iarna/toml"
|
||||
import * as T from "../types"
|
||||
import { exists } from "."
|
||||
import fs from "fs"
|
||||
|
||||
const previousPath = /(.+?)\/([^/]*)$/
|
||||
|
||||
@@ -54,39 +54,32 @@ const previousPath = /(.+?)\/([^/]*)$/
|
||||
export class FileHelper<A> {
|
||||
protected constructor(
|
||||
readonly path: string,
|
||||
readonly volume: string,
|
||||
readonly writeData: (dataIn: A) => string,
|
||||
readonly readData: (stringValue: string) => A,
|
||||
) {}
|
||||
async write(data: A, effects: T.Effects) {
|
||||
let matched
|
||||
if ((matched = previousPath.exec(this.path))) {
|
||||
await effects.createDir({
|
||||
volumeId: this.volume,
|
||||
path: matched[1],
|
||||
})
|
||||
if (previousPath.exec(this.path)) {
|
||||
await new Promise((resolve, reject) =>
|
||||
fs.mkdir(this.path, (err) => (!err ? resolve(null) : reject(err))),
|
||||
)
|
||||
}
|
||||
|
||||
await effects.writeFile({
|
||||
path: this.path,
|
||||
volumeId: this.volume,
|
||||
toWrite: this.writeData(data),
|
||||
})
|
||||
await new Promise((resolve, reject) =>
|
||||
fs.writeFile(this.path, this.writeData(data), (err) =>
|
||||
!err ? resolve(null) : reject(err),
|
||||
),
|
||||
)
|
||||
}
|
||||
async read(effects: T.Effects) {
|
||||
if (
|
||||
!(await exists(effects, {
|
||||
path: this.path,
|
||||
volumeId: this.volume,
|
||||
}))
|
||||
) {
|
||||
if (!fs.existsSync(this.path)) {
|
||||
return null
|
||||
}
|
||||
return this.readData(
|
||||
await effects.readFile({
|
||||
path: this.path,
|
||||
volumeId: this.volume,
|
||||
}),
|
||||
await new Promise((resolve, reject) =>
|
||||
fs.readFile(this.path, (err, data) =>
|
||||
!err ? resolve(data.toString("utf-8")) : reject(err),
|
||||
),
|
||||
),
|
||||
)
|
||||
}
|
||||
/**
|
||||
@@ -96,23 +89,17 @@ export class FileHelper<A> {
|
||||
*/
|
||||
static raw<A>(
|
||||
path: string,
|
||||
volume: string,
|
||||
toFile: (dataIn: A) => string,
|
||||
fromFile: (rawData: string) => A,
|
||||
) {
|
||||
return new FileHelper<A>(path, volume, toFile, fromFile)
|
||||
return new FileHelper<A>(path, toFile, fromFile)
|
||||
}
|
||||
/**
|
||||
* Create a File Helper for a .json file
|
||||
*/
|
||||
static json<A>(
|
||||
path: string,
|
||||
volume: string,
|
||||
shape: matches.Validator<unknown, A>,
|
||||
) {
|
||||
static json<A>(path: string, shape: matches.Validator<unknown, A>) {
|
||||
return new FileHelper<A>(
|
||||
path,
|
||||
volume,
|
||||
(inData) => {
|
||||
return JSON.stringify(inData, null, 2)
|
||||
},
|
||||
@@ -126,12 +113,10 @@ export class FileHelper<A> {
|
||||
*/
|
||||
static toml<A extends Record<string, unknown>>(
|
||||
path: string,
|
||||
volume: string,
|
||||
shape: matches.Validator<unknown, A>,
|
||||
) {
|
||||
return new FileHelper<A>(
|
||||
path,
|
||||
volume,
|
||||
(inData) => {
|
||||
return JSON.stringify(inData, null, 2)
|
||||
},
|
||||
@@ -145,12 +130,10 @@ export class FileHelper<A> {
|
||||
*/
|
||||
static yaml<A extends Record<string, unknown>>(
|
||||
path: string,
|
||||
volume: string,
|
||||
shape: matches.Validator<unknown, A>,
|
||||
) {
|
||||
return new FileHelper<A>(
|
||||
path,
|
||||
volume,
|
||||
(inData) => {
|
||||
return JSON.stringify(inData, null, 2)
|
||||
},
|
||||
|
||||
@@ -30,27 +30,11 @@ T extends object ? {} & {[P in keyof T]: T[P]} :
|
||||
|
||||
export type _<T> = FlattenIntersection<T>
|
||||
|
||||
/** Used to check if the file exists before hand */
|
||||
export const exists = (
|
||||
effects: T.Effects,
|
||||
props: { path: string; volumeId: string },
|
||||
) =>
|
||||
effects.metadata(props).then(
|
||||
(_) => true,
|
||||
(_) => false,
|
||||
)
|
||||
|
||||
export const isKnownError = (e: unknown): e is T.KnownError =>
|
||||
e instanceof Object && ("error" in e || "error-code" in e)
|
||||
|
||||
type Cdr<A> = A extends [unknown, ...infer Cdr] ? Cdr : []
|
||||
|
||||
declare const affine: unique symbol
|
||||
|
||||
function withAffine<B>() {
|
||||
return {} as { [affine]: B }
|
||||
}
|
||||
|
||||
export type WrapperDataOptionals<WrapperData, Path extends string> = {
|
||||
validator?: Parser<unknown, ExtractWrapperData<WrapperData, Path>>
|
||||
/** Defaults to what ever the package currently in */
|
||||
@@ -95,7 +79,6 @@ export type Utils<WD, WrapperOverWrite = { const: never }> = {
|
||||
bindLan: (port: number) => Promise<LocalBinding>
|
||||
networkBuilder: () => NetworkBuilder
|
||||
torHostName: (id: string) => TorHostname
|
||||
exists: (props: { path: string; volumeId: string }) => Promise<boolean>
|
||||
nullIfEmpty: typeof nullIfEmpty
|
||||
}
|
||||
export const utils = <WrapperData = never, WrapperOverWrite = { const: never }>(
|
||||
@@ -106,7 +89,6 @@ export const utils = <WrapperData = never, WrapperOverWrite = { const: never }>(
|
||||
readFile: <A>(fileHelper: FileHelper<A>) => fileHelper.read(effects),
|
||||
writeFile: <A>(fileHelper: FileHelper<A>, data: A) =>
|
||||
fileHelper.write(data, effects),
|
||||
exists: (props: { path: string; volumeId: string }) => exists(effects, props),
|
||||
nullIfEmpty,
|
||||
getWrapperData: <WrapperData = never, Path extends string = never>(
|
||||
packageId: string,
|
||||
|
||||
Reference in New Issue
Block a user