-
Notifications
You must be signed in to change notification settings - Fork 13
Expand file tree
/
Copy pathclone.ts
More file actions
127 lines (114 loc) · 3.7 KB
/
clone.ts
File metadata and controls
127 lines (114 loc) · 3.7 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
import { Command } from "@cliffy/command";
import { Input } from "@cliffy/prompt/input";
import { colors } from "@cliffy/ansi/colors";
import { getCurrentUser, listMyVals } from "~/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";
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 listMyVals(100);
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)
}"`,
);
});
},
);