-
Notifications
You must be signed in to change notification settings - Fork 433
Expand file tree
/
Copy pathcmd.ts
More file actions
146 lines (141 loc) · 4.78 KB
/
cmd.ts
File metadata and controls
146 lines (141 loc) · 4.78 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
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
/*
* cmd.ts
*
* Copyright (C) 2021-2022 Posit Software, PBC
*/
import { Command } from "cliffy/command/mod.ts";
import { initYamlIntelligenceResourcesFromFilesystem } from "../../core/schema/utils.ts";
import { createTempContext } from "../../core/temp.ts";
import { installExtension } from "../../extension/install.ts";
import { findExtensionSource } from "../../extension/extension.ts";
import { join } from "../../deno_ral/path.ts";
import { info } from "../../deno_ral/log.ts";
import {
loadTools,
selectTool,
updateOrInstallTool,
} from "../../tools/tools-console.ts";
import { resolveCompatibleArgs } from "../remove/cmd.ts";
export const updateCommand = new Command()
.name("update")
.arguments("[target...]")
.option(
"--no-prompt",
"Do not prompt to confirm actions",
)
.option(
"--embed <extensionId>",
"Embed this extension within another extension (used when authoring extensions).",
)
.description(
"Updates an extension or global dependency.",
)
.example(
"Update extension (by installed directory)",
"quarto update extension <gh-org>/<extension-name>",
)
.example(
"Update extension (Github)",
"quarto update extension <gh-org>/<gh-repo>",
)
.example(
"Update extension (file)",
"quarto update extension <path-to-zip>",
)
.example(
"Update extension (url)",
"quarto update extension <url>",
)
.example(
"Update TinyTeX",
"quarto update tool tinytex",
)
.example(
"Update Chromium",
"quarto update tool chromium",
)
.example(
"Choose tool to update",
"quarto update tool",
)
.action(
async (
options: { prompt?: boolean; embed?: string },
...target: string[]
) => {
await initYamlIntelligenceResourcesFromFilesystem();
const temp = createTempContext();
try {
const resolved = resolveCompatibleArgs(target, "extension");
if (resolved.action === "extension") {
// Update an extension
if (resolved.name) {
let sourceToUpdate = resolved.name;
// Try to find the extension in the current directory's _extensions
// by treating the name as a directory path (e.g., "org/extension-name")
const extensionPath = join(Deno.cwd(), "_extensions", resolved.name);
const source = await findExtensionSource(extensionPath);
if (source) {
// Found an installed extension, use its source for update
info(
`Found installed extension at _extensions/${resolved.name}`,
);
// Normalize the source by trimming @TAG for GitHub-style sources
// (GitHub refs are like "org/repo" or "org/repo/subdir" with optional @tag)
const githubExtensionRegex = /^[a-zA-Z0-9-_.]+\/[a-zA-Z0-9-_.]+(?:\/[^@]*)?(?:@.+)?$/;
if (source.match(githubExtensionRegex)) {
// GitHub-style source, trim @TAG if present
sourceToUpdate = source.replace(/@.+$/, "");
} else {
// URL or local path, use as-is
sourceToUpdate = source;
}
info(
`Using installation source: ${sourceToUpdate}`,
);
} else {
// Extension not found locally, use the provided target
// This works for GitHub repos (org/repo), URLs, and file paths
info(
`Using provided target: ${resolved.name}`,
);
}
await installExtension(
sourceToUpdate,
temp,
options.prompt !== false,
options.embed,
);
} else {
info("Please provide an extension name, url, or path.");
}
} else if (resolved.action === "tool") {
// Install a tool
if (resolved.name) {
// Use the tool name
await updateOrInstallTool(resolved.name, "update", options.prompt);
} else {
// Not provided, give the user a list to choose from
const allTools = await loadTools();
if (allTools.filter((tool) => !tool.installed).length === 0) {
info("All tools are already installed.");
} else {
// Select which tool should be installed
const toolTarget = await selectTool(allTools, "update");
if (toolTarget) {
info("");
await updateOrInstallTool(toolTarget, "update");
}
}
}
} else {
// This is an unrecognized type option
info(
`Unrecognized option '${resolved.action}' - please choose 'tool' or 'extension'.`,
);
}
} finally {
temp.cleanup();
}
},
);