@budibase/cli 2.3.20 → 2.3.21-alpha.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/analytics/Client.js +32 -0
- package/dist/analytics/index.js +55 -0
- package/dist/backups/index.js +119 -0
- package/dist/backups/objectStore.js +82 -0
- package/dist/backups/utils.js +110 -0
- package/dist/constants.js +9 -0
- package/dist/core/db.js +55 -0
- package/dist/environment.js +4 -0
- package/dist/events.js +13 -0
- package/dist/exec.js +49 -0
- package/dist/hosting/genUser.js +32 -0
- package/dist/hosting/index.js +21 -0
- package/dist/hosting/init.js +117 -0
- package/dist/hosting/makeFiles.js +143 -0
- package/dist/hosting/start.js +63 -0
- package/dist/hosting/status.js +30 -0
- package/dist/hosting/stop.js +30 -0
- package/dist/hosting/types.js +2 -0
- package/dist/hosting/update.js +58 -0
- package/dist/hosting/utils.js +125 -0
- package/dist/hosting/watch.js +47 -0
- package/dist/index.js +36 -0
- package/dist/options.js +14 -0
- package/dist/plugins/index.js +199 -0
- package/dist/plugins/skeleton.js +75 -0
- package/dist/prebuilds.js +46 -0
- package/dist/questions.js +58 -0
- package/dist/structures/Command.js +75 -0
- package/dist/structures/ConfigManager.js +39 -0
- package/dist/tsconfig.build.tsbuildinfo +1 -0
- package/dist/utils.js +126 -0
- package/package.json +20 -10
- package/src/analytics/Client.ts +33 -0
- package/src/analytics/{index.js → index.ts} +7 -10
- package/src/backups/{index.js → index.ts} +19 -19
- package/src/backups/{objectStore.js → objectStore.ts} +9 -9
- package/src/backups/{utils.js → utils.ts} +33 -28
- package/src/constants.ts +4 -0
- package/src/core/{db.js → db.ts} +8 -7
- package/src/{environment.js → environment.ts} +1 -0
- package/src/events.ts +11 -0
- package/src/{exec.js → exec.ts} +7 -7
- package/src/hosting/{genUser.js → genUser.ts} +4 -3
- package/src/hosting/{index.js → index.ts} +10 -12
- package/src/hosting/{init.js → init.ts} +20 -19
- package/src/hosting/{makeFiles.js → makeFiles.ts} +23 -21
- package/src/hosting/{start.js → start.ts} +6 -10
- package/src/hosting/{status.js → status.ts} +4 -8
- package/src/hosting/{stop.js → stop.ts} +4 -8
- package/src/hosting/types.ts +4 -0
- package/src/hosting/{update.js → update.ts} +10 -10
- package/src/hosting/{utils.js → utils.ts} +26 -23
- package/src/hosting/{watch.js → watch.ts} +7 -6
- package/src/{index.js → index.ts} +5 -5
- package/src/options.ts +8 -0
- package/src/plugins/{index.js → index.ts} +27 -25
- package/src/plugins/{skeleton.js → skeleton.ts} +14 -9
- package/src/{prebuilds.js → prebuilds.ts} +7 -6
- package/src/{questions.js → questions.ts} +6 -6
- package/src/structures/{Command.js → Command.ts} +29 -14
- package/src/structures/{ConfigManager.js → ConfigManager.ts} +7 -7
- package/src/utils.ts +112 -0
- package/start.sh +3 -0
- package/tsconfig.build.json +24 -0
- package/tsconfig.json +30 -0
- package/src/analytics/Client.js +0 -32
- package/src/constants.js +0 -25
- package/src/events.js +0 -11
- package/src/options.js +0 -8
- package/src/utils.js +0 -106
|
@@ -1,20 +1,20 @@
|
|
|
1
|
-
|
|
1
|
+
import {
|
|
2
2
|
checkDockerConfigured,
|
|
3
3
|
checkInitComplete,
|
|
4
|
-
|
|
4
|
+
downloadDockerCompose,
|
|
5
5
|
handleError,
|
|
6
6
|
getServices,
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
7
|
+
} from "./utils"
|
|
8
|
+
import { confirmation } from "../questions"
|
|
9
|
+
import compose from "docker-compose"
|
|
10
|
+
import { COMPOSE_PATH } from "./makeFiles"
|
|
11
|
+
import { info, success } from "../utils"
|
|
12
|
+
import { start } from "./start"
|
|
13
13
|
|
|
14
14
|
const BB_COMPOSE_SERVICES = ["app-service", "worker-service", "proxy-service"]
|
|
15
15
|
const BB_SINGLE_SERVICE = ["budibase"]
|
|
16
16
|
|
|
17
|
-
|
|
17
|
+
export async function update() {
|
|
18
18
|
const { services } = getServices(COMPOSE_PATH)
|
|
19
19
|
const isSingle = Object.keys(services).length === 1
|
|
20
20
|
await checkDockerConfigured()
|
|
@@ -23,7 +23,7 @@ exports.update = async () => {
|
|
|
23
23
|
!isSingle &&
|
|
24
24
|
(await confirmation("Do you wish to update you docker-compose.yaml?"))
|
|
25
25
|
) {
|
|
26
|
-
await
|
|
26
|
+
await downloadDockerCompose()
|
|
27
27
|
}
|
|
28
28
|
await handleError(async () => {
|
|
29
29
|
const status = await compose.ps()
|
|
@@ -1,24 +1,24 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
1
|
+
import { lookpath } from "lookpath"
|
|
2
|
+
import fs from "fs"
|
|
3
|
+
import * as makeFiles from "./makeFiles"
|
|
4
|
+
import { logErrorToFile, downloadFile, error } from "../utils"
|
|
5
|
+
import yaml from "yaml"
|
|
6
|
+
import { DockerCompose } from "./types"
|
|
6
7
|
|
|
7
8
|
const ERROR_FILE = "docker-error.log"
|
|
8
|
-
const
|
|
9
|
-
"https://raw.githubusercontent.com/Budibase/budibase/master/hosting/docker-compose.yaml"
|
|
10
|
-
]
|
|
9
|
+
const COMPOSE_URL =
|
|
10
|
+
"https://raw.githubusercontent.com/Budibase/budibase/master/hosting/docker-compose.yaml"
|
|
11
11
|
|
|
12
|
-
|
|
13
|
-
const
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
12
|
+
export async function downloadDockerCompose() {
|
|
13
|
+
const fileName = COMPOSE_URL.split("/").slice(-1)[0]
|
|
14
|
+
try {
|
|
15
|
+
await downloadFile(COMPOSE_URL, `./${fileName}`)
|
|
16
|
+
} catch (err) {
|
|
17
|
+
console.error(error(`Failed to retrieve compose file - ${err}`))
|
|
17
18
|
}
|
|
18
|
-
await Promise.all(promises)
|
|
19
19
|
}
|
|
20
20
|
|
|
21
|
-
|
|
21
|
+
export async function checkDockerConfigured() {
|
|
22
22
|
const error =
|
|
23
23
|
"docker/docker-compose has not been installed, please follow instructions at: https://docs.budibase.com/docs/docker-compose"
|
|
24
24
|
const docker = await lookpath("docker")
|
|
@@ -28,7 +28,7 @@ exports.checkDockerConfigured = async () => {
|
|
|
28
28
|
}
|
|
29
29
|
}
|
|
30
30
|
|
|
31
|
-
|
|
31
|
+
export function checkInitComplete() {
|
|
32
32
|
if (
|
|
33
33
|
!fs.existsSync(makeFiles.ENV_PATH) &&
|
|
34
34
|
!fs.existsSync(makeFiles.COMPOSE_PATH)
|
|
@@ -37,10 +37,10 @@ exports.checkInitComplete = () => {
|
|
|
37
37
|
}
|
|
38
38
|
}
|
|
39
39
|
|
|
40
|
-
|
|
40
|
+
export async function handleError(func: Function) {
|
|
41
41
|
try {
|
|
42
42
|
await func()
|
|
43
|
-
} catch (err) {
|
|
43
|
+
} catch (err: any) {
|
|
44
44
|
if (err && err.err) {
|
|
45
45
|
logErrorToFile(ERROR_FILE, err.err)
|
|
46
46
|
}
|
|
@@ -48,14 +48,14 @@ exports.handleError = async func => {
|
|
|
48
48
|
}
|
|
49
49
|
}
|
|
50
50
|
|
|
51
|
-
|
|
51
|
+
export function getServices(path: string) {
|
|
52
52
|
const dockerYaml = fs.readFileSync(path, "utf8")
|
|
53
53
|
const parsedYaml = yaml.parse(dockerYaml)
|
|
54
54
|
return { yaml: parsedYaml, services: parsedYaml.services }
|
|
55
55
|
}
|
|
56
56
|
|
|
57
|
-
|
|
58
|
-
const { yaml, services } =
|
|
57
|
+
export function getAppService(path: string) {
|
|
58
|
+
const { yaml, services } = getServices(path),
|
|
59
59
|
serviceList = Object.keys(services)
|
|
60
60
|
let service
|
|
61
61
|
if (services["app-service"]) {
|
|
@@ -66,14 +66,17 @@ exports.getAppService = path => {
|
|
|
66
66
|
return { yaml, service }
|
|
67
67
|
}
|
|
68
68
|
|
|
69
|
-
|
|
69
|
+
export function updateDockerComposeService(
|
|
70
|
+
// eslint-disable-next-line no-unused-vars
|
|
71
|
+
updateFn: (service: DockerCompose) => void
|
|
72
|
+
) {
|
|
70
73
|
const opts = ["docker-compose.yaml", "docker-compose.yml"]
|
|
71
74
|
const dockerFilePath = opts.find(name => fs.existsSync(name))
|
|
72
75
|
if (!dockerFilePath) {
|
|
73
76
|
console.log(error("Unable to locate docker-compose YAML."))
|
|
74
77
|
return
|
|
75
78
|
}
|
|
76
|
-
const { yaml: parsedYaml, service } =
|
|
79
|
+
const { yaml: parsedYaml, service } = getAppService(dockerFilePath)
|
|
77
80
|
if (!service) {
|
|
78
81
|
console.log(
|
|
79
82
|
error(
|
|
@@ -1,9 +1,10 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
1
|
+
import { resolve } from "path"
|
|
2
|
+
import fs from "fs"
|
|
3
|
+
import { error, success } from "../utils"
|
|
4
|
+
import { updateDockerComposeService } from "./utils"
|
|
5
|
+
import { DockerCompose } from "./types"
|
|
5
6
|
|
|
6
|
-
|
|
7
|
+
export async function watchPlugins(pluginPath: string, silent: boolean) {
|
|
7
8
|
const PLUGIN_PATH = "/plugins"
|
|
8
9
|
// get absolute path
|
|
9
10
|
pluginPath = resolve(pluginPath)
|
|
@@ -15,7 +16,7 @@ exports.watchPlugins = async (pluginPath, silent) => {
|
|
|
15
16
|
)
|
|
16
17
|
return
|
|
17
18
|
}
|
|
18
|
-
updateDockerComposeService(service => {
|
|
19
|
+
updateDockerComposeService((service: DockerCompose) => {
|
|
19
20
|
// set environment variable
|
|
20
21
|
service.environment["PLUGINS_DIR"] = PLUGIN_PATH
|
|
21
22
|
// add volumes to parsed yaml
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
|
|
2
|
+
import "./prebuilds"
|
|
3
|
+
import "./environment"
|
|
4
|
+
import { getCommands } from "./options"
|
|
5
|
+
import { Command } from "commander"
|
|
6
|
+
import { getHelpDescription } from "./utils"
|
|
4
7
|
const json = require("../package.json")
|
|
5
|
-
const { getCommands } = require("./options")
|
|
6
|
-
const { Command } = require("commander")
|
|
7
|
-
const { getHelpDescription } = require("./utils")
|
|
8
8
|
|
|
9
9
|
// add hosting config
|
|
10
10
|
async function init() {
|
package/src/options.ts
ADDED
|
@@ -1,18 +1,22 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
1
|
+
import { Command } from "../structures/Command"
|
|
2
|
+
import { CommandWord, AnalyticsEvent, InitType } from "../constants"
|
|
3
|
+
import { getSkeleton, fleshOutSkeleton } from "./skeleton"
|
|
4
|
+
import * as questions from "../questions"
|
|
5
|
+
import fs from "fs"
|
|
6
|
+
import { PluginType, PLUGIN_TYPE_ARR } from "@budibase/types"
|
|
7
|
+
import { plugins } from "@budibase/backend-core"
|
|
8
|
+
import { runPkgCommand } from "../exec"
|
|
9
|
+
import { join } from "path"
|
|
10
|
+
import { success, error, info, moveDirectory } from "../utils"
|
|
11
|
+
import { captureEvent } from "../events"
|
|
12
|
+
import { GENERATED_USER_EMAIL } from "../constants"
|
|
13
|
+
import { init as hostingInit } from "../hosting/init"
|
|
14
|
+
import { start as hostingStart } from "../hosting/start"
|
|
12
15
|
const fp = require("find-free-port")
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
+
|
|
17
|
+
type PluginOpts = {
|
|
18
|
+
init?: PluginType
|
|
19
|
+
}
|
|
16
20
|
|
|
17
21
|
function checkInPlugin() {
|
|
18
22
|
if (!fs.existsSync("package.json")) {
|
|
@@ -27,7 +31,7 @@ function checkInPlugin() {
|
|
|
27
31
|
}
|
|
28
32
|
}
|
|
29
33
|
|
|
30
|
-
async function askAboutTopLevel(name) {
|
|
34
|
+
async function askAboutTopLevel(name: string) {
|
|
31
35
|
const files = fs.readdirSync(process.cwd())
|
|
32
36
|
// we are in an empty git repo, don't ask
|
|
33
37
|
if (files.find(file => file === ".git")) {
|
|
@@ -45,8 +49,8 @@ async function askAboutTopLevel(name) {
|
|
|
45
49
|
}
|
|
46
50
|
}
|
|
47
51
|
|
|
48
|
-
async function init(opts) {
|
|
49
|
-
const type = opts["init"] || opts
|
|
52
|
+
async function init(opts: PluginOpts) {
|
|
53
|
+
const type = opts["init"] || (opts as PluginType)
|
|
50
54
|
if (!type || !PLUGIN_TYPE_ARR.includes(type)) {
|
|
51
55
|
console.log(
|
|
52
56
|
error(
|
|
@@ -82,7 +86,7 @@ async function init(opts) {
|
|
|
82
86
|
} else {
|
|
83
87
|
console.log(info(`Plugin created in directory "${name}"`))
|
|
84
88
|
}
|
|
85
|
-
captureEvent(
|
|
89
|
+
captureEvent(AnalyticsEvent.PluginInit, {
|
|
86
90
|
type,
|
|
87
91
|
name,
|
|
88
92
|
description,
|
|
@@ -109,7 +113,7 @@ async function verify() {
|
|
|
109
113
|
version = pkgJson.version
|
|
110
114
|
plugins.validate(schemaJson)
|
|
111
115
|
return { name, version }
|
|
112
|
-
} catch (err) {
|
|
116
|
+
} catch (err: any) {
|
|
113
117
|
if (err && err.message && err.message.includes("not valid JSON")) {
|
|
114
118
|
console.log(error(`schema.json is not valid JSON: ${err.message}`))
|
|
115
119
|
} else {
|
|
@@ -120,7 +124,7 @@ async function verify() {
|
|
|
120
124
|
|
|
121
125
|
async function build() {
|
|
122
126
|
const verified = await verify()
|
|
123
|
-
if (!verified
|
|
127
|
+
if (!verified?.name) {
|
|
124
128
|
return
|
|
125
129
|
}
|
|
126
130
|
console.log(success("Verified!"))
|
|
@@ -132,7 +136,7 @@ async function build() {
|
|
|
132
136
|
|
|
133
137
|
async function watch() {
|
|
134
138
|
const verified = await verify()
|
|
135
|
-
if (!verified
|
|
139
|
+
if (!verified?.name) {
|
|
136
140
|
return
|
|
137
141
|
}
|
|
138
142
|
const output = join("dist", `${verified.name}-${verified.version}.tar.gz`)
|
|
@@ -150,7 +154,7 @@ async function dev() {
|
|
|
150
154
|
const [port] = await fp(10000)
|
|
151
155
|
const password = "admin"
|
|
152
156
|
await hostingInit({
|
|
153
|
-
init:
|
|
157
|
+
init: InitType.QUICK,
|
|
154
158
|
single: true,
|
|
155
159
|
watchPluginDir: pluginDir,
|
|
156
160
|
genUser: password,
|
|
@@ -168,7 +172,7 @@ async function dev() {
|
|
|
168
172
|
console.log(success("Password: ") + info(password))
|
|
169
173
|
}
|
|
170
174
|
|
|
171
|
-
|
|
175
|
+
export default new Command(`${CommandWord.PLUGIN}`)
|
|
172
176
|
.addHelp(
|
|
173
177
|
"Custom plugins for Budibase, init, build and verify your components and datasources with this tool."
|
|
174
178
|
)
|
|
@@ -192,5 +196,3 @@ const command = new Command(`${CommandWords.PLUGIN}`)
|
|
|
192
196
|
"Run a development environment which automatically watches the current directory.",
|
|
193
197
|
dev
|
|
194
198
|
)
|
|
195
|
-
|
|
196
|
-
exports.command = command
|
|
@@ -1,21 +1,21 @@
|
|
|
1
|
-
|
|
1
|
+
import fetch from "node-fetch"
|
|
2
|
+
import fs from "fs"
|
|
3
|
+
import os from "os"
|
|
4
|
+
import { join } from "path"
|
|
5
|
+
import { processStringSync } from "@budibase/string-templates"
|
|
2
6
|
const download = require("download")
|
|
3
|
-
const fs = require("fs")
|
|
4
|
-
const os = require("os")
|
|
5
|
-
const { join } = require("path")
|
|
6
7
|
const tar = require("tar")
|
|
7
|
-
const { processStringSync } = require("@budibase/string-templates")
|
|
8
8
|
|
|
9
9
|
const HBS_FILES = ["package.json.hbs", "schema.json.hbs", "README.md.hbs"]
|
|
10
10
|
|
|
11
|
-
async function getSkeletonUrl(type) {
|
|
11
|
+
async function getSkeletonUrl(type: string) {
|
|
12
12
|
const resp = await fetch(
|
|
13
13
|
"https://api.github.com/repos/budibase/budibase-skeleton/releases/latest"
|
|
14
14
|
)
|
|
15
15
|
if (resp.status >= 300) {
|
|
16
16
|
throw new Error("Failed to retrieve skeleton metadata")
|
|
17
17
|
}
|
|
18
|
-
const json = await resp.json()
|
|
18
|
+
const json = (await resp.json()) as { assets: any[] }
|
|
19
19
|
for (let asset of json["assets"]) {
|
|
20
20
|
if (asset.name && asset.name.includes(type)) {
|
|
21
21
|
return asset["browser_download_url"]
|
|
@@ -24,7 +24,7 @@ async function getSkeletonUrl(type) {
|
|
|
24
24
|
throw new Error("No skeleton found in latest release.")
|
|
25
25
|
}
|
|
26
26
|
|
|
27
|
-
|
|
27
|
+
export async function getSkeleton(type: string, name: string) {
|
|
28
28
|
const url = await getSkeletonUrl(type)
|
|
29
29
|
const tarballFile = join(os.tmpdir(), "skeleton.tar.gz")
|
|
30
30
|
|
|
@@ -40,7 +40,12 @@ exports.getSkeleton = async (type, name) => {
|
|
|
40
40
|
fs.rmSync(tarballFile)
|
|
41
41
|
}
|
|
42
42
|
|
|
43
|
-
|
|
43
|
+
export async function fleshOutSkeleton(
|
|
44
|
+
type: string,
|
|
45
|
+
name: string,
|
|
46
|
+
description: string,
|
|
47
|
+
version: string
|
|
48
|
+
) {
|
|
44
49
|
for (let file of HBS_FILES) {
|
|
45
50
|
const oldFile = join(name, file),
|
|
46
51
|
newFile = join(name, file.substring(0, file.length - 4))
|
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
1
|
+
import os from "os"
|
|
2
|
+
import { join } from "path"
|
|
3
|
+
import fs from "fs"
|
|
4
|
+
import { error } from "./utils"
|
|
5
|
+
|
|
5
6
|
const PREBUILDS = "prebuilds"
|
|
6
7
|
const ARCH = `${os.platform()}-${os.arch()}`
|
|
7
8
|
const PREBUILD_DIR = join(process.execPath, "..", PREBUILDS, ARCH)
|
|
@@ -26,8 +27,8 @@ function checkForBinaries() {
|
|
|
26
27
|
}
|
|
27
28
|
}
|
|
28
29
|
|
|
29
|
-
function cleanup(evt) {
|
|
30
|
-
if (!isNaN(evt)) {
|
|
30
|
+
function cleanup(evt?: number) {
|
|
31
|
+
if (evt && !isNaN(evt)) {
|
|
31
32
|
return
|
|
32
33
|
}
|
|
33
34
|
if (evt) {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
const inquirer = require("inquirer")
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
export async function confirmation(question: string) {
|
|
4
4
|
const config = {
|
|
5
5
|
type: "confirm",
|
|
6
6
|
message: question,
|
|
@@ -10,8 +10,8 @@ exports.confirmation = async question => {
|
|
|
10
10
|
return (await inquirer.prompt(config)).confirmation
|
|
11
11
|
}
|
|
12
12
|
|
|
13
|
-
|
|
14
|
-
const config = {
|
|
13
|
+
export async function string(question: string, defaultString?: string) {
|
|
14
|
+
const config: any = {
|
|
15
15
|
type: "input",
|
|
16
16
|
name: "string",
|
|
17
17
|
message: question,
|
|
@@ -22,12 +22,12 @@ exports.string = async (question, defaultString = null) => {
|
|
|
22
22
|
return (await inquirer.prompt(config)).string
|
|
23
23
|
}
|
|
24
24
|
|
|
25
|
-
|
|
26
|
-
const config = {
|
|
25
|
+
export async function number(question: string, defaultNumber?: number) {
|
|
26
|
+
const config: any = {
|
|
27
27
|
type: "input",
|
|
28
28
|
name: "number",
|
|
29
29
|
message: question,
|
|
30
|
-
validate: value => {
|
|
30
|
+
validate: (value: string) => {
|
|
31
31
|
let valid = !isNaN(parseFloat(value))
|
|
32
32
|
return valid || "Please enter a number"
|
|
33
33
|
},
|
|
@@ -1,19 +1,31 @@
|
|
|
1
|
-
|
|
1
|
+
import {
|
|
2
2
|
getSubHelpDescription,
|
|
3
3
|
getHelpDescription,
|
|
4
4
|
error,
|
|
5
5
|
capitaliseFirstLetter,
|
|
6
|
-
}
|
|
6
|
+
} from "../utils"
|
|
7
7
|
|
|
8
|
-
|
|
9
|
-
|
|
8
|
+
type CommandOpt = {
|
|
9
|
+
command: string
|
|
10
|
+
help: string
|
|
11
|
+
func?: Function
|
|
12
|
+
extras: any[]
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export class Command {
|
|
16
|
+
command: string
|
|
17
|
+
opts: CommandOpt[]
|
|
18
|
+
func?: Function
|
|
19
|
+
help?: string
|
|
20
|
+
|
|
21
|
+
constructor(command: string, func?: Function) {
|
|
10
22
|
// if there are options, need to just get the command name
|
|
11
23
|
this.command = command
|
|
12
24
|
this.opts = []
|
|
13
25
|
this.func = func
|
|
14
26
|
}
|
|
15
27
|
|
|
16
|
-
convertToCommander(lookup) {
|
|
28
|
+
convertToCommander(lookup: string) {
|
|
17
29
|
const parts = lookup.toLowerCase().split("-")
|
|
18
30
|
// camel case, separate out first
|
|
19
31
|
const first = parts.shift()
|
|
@@ -22,21 +34,26 @@ class Command {
|
|
|
22
34
|
.join("")
|
|
23
35
|
}
|
|
24
36
|
|
|
25
|
-
addHelp(help) {
|
|
37
|
+
addHelp(help: string) {
|
|
26
38
|
this.help = help
|
|
27
39
|
return this
|
|
28
40
|
}
|
|
29
41
|
|
|
30
|
-
addSubOption(
|
|
42
|
+
addSubOption(
|
|
43
|
+
command: string,
|
|
44
|
+
help: string,
|
|
45
|
+
func?: Function,
|
|
46
|
+
extras: any[] = []
|
|
47
|
+
) {
|
|
31
48
|
this.opts.push({ command, help, func, extras })
|
|
32
49
|
return this
|
|
33
50
|
}
|
|
34
51
|
|
|
35
|
-
configure(program) {
|
|
52
|
+
configure(program: any) {
|
|
36
53
|
const thisCmd = this
|
|
37
54
|
let command = program.command(thisCmd.command)
|
|
38
55
|
if (this.help) {
|
|
39
|
-
command = command.description(getHelpDescription(thisCmd.help))
|
|
56
|
+
command = command.description(getHelpDescription(thisCmd.help!))
|
|
40
57
|
}
|
|
41
58
|
for (let opt of thisCmd.opts) {
|
|
42
59
|
command = command.option(opt.command, getSubHelpDescription(opt.help))
|
|
@@ -45,7 +62,7 @@ class Command {
|
|
|
45
62
|
"--help",
|
|
46
63
|
getSubHelpDescription(`Get help with ${this.command} options`)
|
|
47
64
|
)
|
|
48
|
-
command.action(async options => {
|
|
65
|
+
command.action(async (options: Record<string, string>) => {
|
|
49
66
|
try {
|
|
50
67
|
let executed = false,
|
|
51
68
|
found = false
|
|
@@ -53,7 +70,7 @@ class Command {
|
|
|
53
70
|
let lookup = opt.command.split(" ")[0].replace("--", "")
|
|
54
71
|
// need to handle how commander converts watch-plugin-dir to watchPluginDir
|
|
55
72
|
lookup = this.convertToCommander(lookup)
|
|
56
|
-
found = !executed && options[lookup]
|
|
73
|
+
found = !executed && !!options[lookup]
|
|
57
74
|
if (found && opt.func) {
|
|
58
75
|
const input =
|
|
59
76
|
Object.keys(options).length > 1 ? options : options[lookup]
|
|
@@ -69,11 +86,9 @@ class Command {
|
|
|
69
86
|
console.log(error(`Unknown ${this.command} option.`))
|
|
70
87
|
command.help()
|
|
71
88
|
}
|
|
72
|
-
} catch (err) {
|
|
89
|
+
} catch (err: any) {
|
|
73
90
|
console.log(error(err))
|
|
74
91
|
}
|
|
75
92
|
})
|
|
76
93
|
}
|
|
77
94
|
}
|
|
78
|
-
|
|
79
|
-
module.exports = Command
|
|
@@ -3,7 +3,9 @@ const path = require("path")
|
|
|
3
3
|
const os = require("os")
|
|
4
4
|
const { error } = require("../utils")
|
|
5
5
|
|
|
6
|
-
class ConfigManager {
|
|
6
|
+
export class ConfigManager {
|
|
7
|
+
path: string
|
|
8
|
+
|
|
7
9
|
constructor() {
|
|
8
10
|
this.path = path.join(os.homedir(), ".budibase.json")
|
|
9
11
|
if (!fs.existsSync(this.path)) {
|
|
@@ -24,26 +26,24 @@ class ConfigManager {
|
|
|
24
26
|
}
|
|
25
27
|
}
|
|
26
28
|
|
|
27
|
-
set config(json) {
|
|
29
|
+
set config(json: any) {
|
|
28
30
|
fs.writeFileSync(this.path, JSON.stringify(json))
|
|
29
31
|
}
|
|
30
32
|
|
|
31
|
-
getValue(key) {
|
|
33
|
+
getValue(key: string) {
|
|
32
34
|
return this.config[key]
|
|
33
35
|
}
|
|
34
36
|
|
|
35
|
-
setValue(key, value) {
|
|
37
|
+
setValue(key: string, value: any) {
|
|
36
38
|
this.config = {
|
|
37
39
|
...this.config,
|
|
38
40
|
[key]: value,
|
|
39
41
|
}
|
|
40
42
|
}
|
|
41
43
|
|
|
42
|
-
removeKey(key) {
|
|
44
|
+
removeKey(key: string) {
|
|
43
45
|
const updated = { ...this.config }
|
|
44
46
|
delete updated[key]
|
|
45
47
|
this.config = updated
|
|
46
48
|
}
|
|
47
49
|
}
|
|
48
|
-
|
|
49
|
-
module.exports = ConfigManager
|
package/src/utils.ts
ADDED
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import chalk from "chalk"
|
|
2
|
+
import fs from "fs"
|
|
3
|
+
import path from "path"
|
|
4
|
+
import { join } from "path"
|
|
5
|
+
import fetch from "node-fetch"
|
|
6
|
+
const progress = require("cli-progress")
|
|
7
|
+
|
|
8
|
+
export function downloadFile(url: string, filePath: string) {
|
|
9
|
+
return new Promise((resolve, reject) => {
|
|
10
|
+
filePath = path.resolve(filePath)
|
|
11
|
+
fetch(url, {
|
|
12
|
+
method: "GET",
|
|
13
|
+
})
|
|
14
|
+
.then(response => {
|
|
15
|
+
const writer = fs.createWriteStream(filePath)
|
|
16
|
+
if (response.body) {
|
|
17
|
+
response.body.pipe(writer)
|
|
18
|
+
response.body.on("end", resolve)
|
|
19
|
+
response.body.on("error", reject)
|
|
20
|
+
} else {
|
|
21
|
+
throw new Error(
|
|
22
|
+
`Unable to retrieve docker-compose file - ${response.status}`
|
|
23
|
+
)
|
|
24
|
+
}
|
|
25
|
+
})
|
|
26
|
+
.catch(err => {
|
|
27
|
+
throw err
|
|
28
|
+
})
|
|
29
|
+
})
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export async function httpCall(url: string, method: string) {
|
|
33
|
+
const response = await fetch(url, {
|
|
34
|
+
method,
|
|
35
|
+
})
|
|
36
|
+
return response.body
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export function getHelpDescription(str: string) {
|
|
40
|
+
return chalk.cyan(str)
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export function getSubHelpDescription(str: string) {
|
|
44
|
+
return chalk.green(str)
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export function error(err: string | number) {
|
|
48
|
+
process.exitCode = -1
|
|
49
|
+
return chalk.red(`Error - ${err}`)
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export function success(str: string) {
|
|
53
|
+
return chalk.green(str)
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export function info(str: string) {
|
|
57
|
+
return chalk.cyan(str)
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export function logErrorToFile(file: string, error: string) {
|
|
61
|
+
fs.writeFileSync(path.resolve(`./${file}`), `Budibase Error\n${error}`)
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export function parseEnv(env: string) {
|
|
65
|
+
const lines = env.toString().split("\n")
|
|
66
|
+
let result: Record<string, string> = {}
|
|
67
|
+
for (const line of lines) {
|
|
68
|
+
const match = line.match(/^([^=:#]+?)[=:](.*)/)
|
|
69
|
+
if (match) {
|
|
70
|
+
result[match[1].trim()] = match[2].trim()
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
return result
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
export function progressBar(total: number) {
|
|
77
|
+
const bar = new progress.SingleBar({}, progress.Presets.shades_classic)
|
|
78
|
+
bar.start(total, 0)
|
|
79
|
+
return bar
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
export function checkSlashesInUrl(url: string) {
|
|
83
|
+
return url.replace(/(https?:\/\/)|(\/)+/g, "$1$2")
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
export function moveDirectory(oldPath: string, newPath: string) {
|
|
87
|
+
const files = fs.readdirSync(oldPath)
|
|
88
|
+
// check any file exists already
|
|
89
|
+
for (let file of files) {
|
|
90
|
+
if (fs.existsSync(join(newPath, file))) {
|
|
91
|
+
throw new Error(
|
|
92
|
+
"Unable to remove top level directory - some skeleton files already exist."
|
|
93
|
+
)
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
for (let file of files) {
|
|
97
|
+
fs.renameSync(join(oldPath, file), join(newPath, file))
|
|
98
|
+
}
|
|
99
|
+
fs.rmdirSync(oldPath)
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
export function capitaliseFirstLetter(str: string) {
|
|
103
|
+
return str.charAt(0).toUpperCase() + str.slice(1)
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
export function stringifyToDotEnv(json: Record<string, string | number>) {
|
|
107
|
+
let str = ""
|
|
108
|
+
for (let [key, value] of Object.entries(json)) {
|
|
109
|
+
str += `${key}=${value}\n`
|
|
110
|
+
}
|
|
111
|
+
return str
|
|
112
|
+
}
|
package/start.sh
ADDED