Skip to content

Commit 7535fab

Browse files
committed
Stub in quarto list command
1 parent 5fac1ce commit 7535fab

File tree

4 files changed

+179
-11
lines changed

4 files changed

+179
-11
lines changed

src/command/command.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import { buildJsCommand } from "./build-js/cmd.ts";
2222
import { installCommand } from "./install/cmd.ts";
2323
import { publishCommand } from "./publish/cmd.ts";
2424
import { removeCommand } from "./remove/cmd.ts";
25+
import { listCommand } from "./list/cmd.ts";
2526

2627
// deno-lint-ignore no-explicit-any
2728
export function commands(): Command<any>[] {
@@ -35,6 +36,7 @@ export function commands(): Command<any>[] {
3536
runCommand,
3637
installCommand,
3738
removeCommand,
39+
listCommand,
3840
publishCommand,
3941
capabilitiesCommand,
4042
inspectCommand,

src/command/list/cmd.ts

Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
/*
2+
* cmd.ts
3+
*
4+
* Copyright (C) 2021 by RStudio, PBC
5+
*
6+
*/
7+
import { Command } from "cliffy/command/mod.ts";
8+
import { Table } from "cliffy/table/mod.ts";
9+
import { initYamlIntelligenceResourcesFromFilesystem } from "../../core/schema/utils.ts";
10+
import { createTempContext } from "../../core/temp.ts";
11+
12+
import { info } from "log/mod.ts";
13+
import { outputTools } from "../remove/tools-console.ts";
14+
import { createExtensionContext } from "../../extension/extension.ts";
15+
import {
16+
Extension,
17+
ExtensionContext,
18+
extensionIdString,
19+
} from "../../extension/extension-shared.ts";
20+
import { projectContext } from "../../project/project-context.ts";
21+
22+
export const listCommand = new Command()
23+
.hidden()
24+
.name("list")
25+
.arguments("<type:string>")
26+
.description(
27+
"Lists an extension or global dependency.",
28+
)
29+
.example(
30+
"List installed extensions",
31+
"quarto list extensions",
32+
)
33+
.example(
34+
"List global tools",
35+
"quarto list tools",
36+
)
37+
.action(
38+
async (_options: unknown, type: string) => {
39+
await initYamlIntelligenceResourcesFromFilesystem();
40+
const temp = createTempContext();
41+
const extensionContext = createExtensionContext();
42+
try {
43+
if (type.toLowerCase() === "extensions") {
44+
await outputExtensions(Deno.cwd(), extensionContext);
45+
} else if (type.toLowerCase() === "tools") {
46+
await outputTools();
47+
} else {
48+
// This is an unrecognized type option
49+
info(
50+
`Unrecognized option '${type}' - please choose 'tools' or 'extensions'.`,
51+
);
52+
}
53+
} finally {
54+
temp.cleanup();
55+
}
56+
},
57+
);
58+
59+
async function outputExtensions(
60+
path: string,
61+
extensionContext: ExtensionContext,
62+
) {
63+
// Provide the with with a list
64+
const project = await projectContext(path);
65+
const extensions = extensionContext.extensions(path, project);
66+
67+
const extensionEntries: string[][] = [];
68+
69+
const provides = (extension: Extension) => {
70+
const contribs: string[] = [];
71+
if (
72+
extension.contributes.filters && extension.contributes.filters?.length > 0
73+
) {
74+
contribs.push("filter");
75+
}
76+
77+
if (
78+
extension.contributes.shortcodes &&
79+
extension.contributes.shortcodes?.length > 0
80+
) {
81+
contribs.push("shortcodes");
82+
}
83+
84+
if (
85+
extension.contributes.format
86+
) {
87+
contribs.push("formats");
88+
}
89+
return contribs.join(", ");
90+
};
91+
92+
extensions.forEach((ext) => {
93+
const row = [
94+
extensionIdString(ext.id),
95+
ext.version?.toString() || "(none)",
96+
`[${provides(ext)}]`,
97+
];
98+
extensionEntries.push(row);
99+
});
100+
101+
const table = new Table().header(["Id", "Version", "Type"]).body(
102+
extensionEntries,
103+
).padding(4);
104+
info(table.toString());
105+
}

src/command/remove/tools-console.ts

Lines changed: 68 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,16 @@
55
*
66
*/
77
import { Select } from "cliffy/prompt/mod.ts";
8-
import { allTools } from "../tools/tools.ts";
8+
import { Table } from "cliffy/table/mod.ts";
9+
import { allTools, toolSummary } from "../tools/tools.ts";
910

1011
import { withSpinner } from "../../core/console.ts";
11-
import { InstallableTool, RemotePackageInfo } from "../tools/types.ts";
12-
13-
interface AllTools {
14-
installed: InstallableTool[];
15-
notInstalled: InstallableTool[];
16-
}
12+
import {
13+
InstallableTool,
14+
RemotePackageInfo,
15+
ToolSummaryData,
16+
} from "../tools/types.ts";
17+
import { info, warning } from "log/mod.ts";
1718

1819
interface ToolInfo {
1920
tool: InstallableTool;
@@ -22,6 +23,66 @@ interface ToolInfo {
2223
latest: RemotePackageInfo;
2324
}
2425

26+
export async function outputTools() {
27+
const toolRows: string[][] = [];
28+
const statusMsgs: string[] = [];
29+
30+
await withSpinner({
31+
message: "Reading Tool Data",
32+
}, async () => {
33+
// Reads the status
34+
const installStatus = (summary: ToolSummaryData): string => {
35+
if (summary.installed) {
36+
if (summary.installedVersion) {
37+
if (summary.installedVersion === summary.latestRelease.version) {
38+
return "Up to date";
39+
} else {
40+
return "Update available";
41+
}
42+
} else {
43+
return "External Installation";
44+
}
45+
} else {
46+
return "Not installed";
47+
}
48+
};
49+
50+
// The column widths for output (in chars)
51+
const tools = await loadTools();
52+
for (const tool of tools) {
53+
const summary = await toolSummary(tool.tool.name);
54+
if (summary) {
55+
const toolDetails = [
56+
tool.tool.name,
57+
installStatus(summary),
58+
summary.installedVersion || "",
59+
summary.latestRelease.version,
60+
];
61+
toolRows.push(toolDetails);
62+
63+
if (summary.configuration.status !== "ok") {
64+
statusMsgs.push(
65+
`${summary.configuration.message}`,
66+
);
67+
}
68+
}
69+
}
70+
});
71+
// Write the output
72+
const table = new Table().header([
73+
"Tool",
74+
"Status",
75+
"Installed",
76+
"Latest",
77+
]).body(
78+
toolRows,
79+
).padding(4);
80+
info(table.toString());
81+
statusMsgs.forEach((msg) => {
82+
warning(msg);
83+
});
84+
}
85+
2586
export async function loadTools(): Promise<ToolInfo[]> {
2687
let sorted: ToolInfo[] = [];
2788
await withSpinner({ message: "Inspecting tools" }, async () => {

src/command/tools/tools/tinytex.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,7 @@ async function verifyConfiguration(): Promise<ToolConfigurationState> {
119119
} else {
120120
return {
121121
status: "warning",
122-
message: "TeX Live is not available on the path.",
122+
message: "TeX Live not on path.",
123123
};
124124
}
125125
}
@@ -340,9 +340,9 @@ This will instruct TeX Live to create symlinks that it needs in <bin_dir_on_path
340340
}
341341
const binPathMessage = envPath
342342
? `Setting TeXLive Binpath: ${envPath}`
343-
: Deno.build.os !== "windows" ?
344-
`Updating Path (inspecting ${paths.length} possible paths)` :
345-
"Updating Path";
343+
: Deno.build.os !== "windows"
344+
? `Updating Path (inspecting ${paths.length} possible paths)`
345+
: "Updating Path";
346346

347347
// Ensure symlinks are all set
348348
await context.withSpinner(

0 commit comments

Comments
 (0)