-
Notifications
You must be signed in to change notification settings - Fork 13
Expand file tree
/
Copy pathclone.ts
More file actions
131 lines (118 loc) · 3.82 KB
/
clone.ts
File metadata and controls
131 lines (118 loc) · 3.82 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
import { Command } from "@cliffy/command";
import { Input } from "@cliffy/prompt/input";
import { colors } from "@cliffy/ansi/colors";
import sdk, { getCurrentUser } from "../../utils/sdk.ts";
import VTClient from "~/vt/vt/VTClient.ts";
import { relative } from "@std/path";
import { doWithSpinner, getClonePath } from "~/cmd/utils.ts";
import { tty } from "@cliffy/ansi/tty";
import { Confirm } from "@cliffy/prompt";
import { ensureAddEditorFiles } from "~/cmd/lib/utils/messages.ts";
import { parseValUrl } from "~/cmd/parsing.ts";
import { DEFAULT_BRANCH_NAME, DEFAULT_EDITOR_TEMPLATE } from "~/consts.ts";
import { arrayFromAsyncN } from "~/utils/mod.ts";
export const cloneCmd = new Command()
.name("clone")
.description("Clone a Val")
.arguments("[valUri:string] [targetDir:string] [branchName:string]")
.option("--no-editor-files", "Clone without editor configuration files")
.example(
"Interactive Val selection",
`vt clone`,
)
.example(
"Clone with username/valName",
`vt clone username/valName`,
)
.example(
"Clone into the current directory",
`vt clone username/valName .`,
)
.example(
"Clone with link",
`vt clone https://www.val.town/x/username/valName`,
)
.example(
"Clone into a new directory",
`vt clone username/valName new-directory`,
)
.example(
"Clone without editor files",
`vt clone username/valName --no-editor-files`,
)
.action(
async (
{ editorFiles }: { editorFiles: boolean },
valUri?: string,
targetDir?: string,
branchName?: string,
) => {
const user = await getCurrentUser();
let ownerName: string;
let valName: string;
// If no Val URI is provided, show interactive Val selection
if (!valUri) {
const vals = await doWithSpinner(
"Loading vals...",
async (spinner) => {
const [allVals, _] = await arrayFromAsyncN(
sdk.me.vals.list({}),
500,
);
spinner.stop();
return allVals;
},
);
if (vals.length === 0) {
console.log(colors.yellow("You don't have any Vals yet."));
return;
}
// Map vals to name format for selection
const valNames = vals.map((p) => p.name);
const selectedVal = await Input.prompt({
message: "Choose a Val to clone",
list: true,
info: true,
suggestions: valNames,
});
const val = vals.find((p) => p.name === selectedVal);
if (!val) {
console.log(colors.red("Val not found"));
return;
}
ownerName = val.author.username || user.username!;
valName = val.name;
// Scroll up a line so that they don't see the prompt they were just
// given
tty.scrollDown(1);
} else {
// Parse Val URI if provided
const parsed = parseValUrl(valUri, user.username!);
ownerName = parsed.ownerName;
valName = parsed.valName;
}
return await doWithSpinner("Cloning val...", async (spinner) => {
branchName = branchName || DEFAULT_BRANCH_NAME;
const clonePath = getClonePath(targetDir, valName);
const vt = await VTClient.clone({
rootPath: clonePath,
valName,
username: ownerName,
});
if (editorFiles) {
spinner.stop();
const { editorTemplate } = await vt.getConfig().loadConfig();
const confirmed = await Confirm.prompt(
ensureAddEditorFiles(editorTemplate ?? DEFAULT_EDITOR_TEMPLATE),
);
if (confirmed) await vt.addEditorTemplate();
console.log();
}
spinner.succeed(
`Val ${ownerName}/${valName} cloned to "${
relative(Deno.cwd(), clonePath)
}"`,
);
});
},
);