1 import { promisify } from "util";
2 import { exec } from "child_process";
3 import Logger from "../logger.mjs";
4 import { unlink } from "fs/promises";
5 import type Settings from "../settings.mjs";
6 import { SettingsKey, HOME_VAR } from "../settings.mjs";
7 import { homedir } from "os";
8 import which from "which";
9 import { window } from "vscode";
11 export const execAsync = promisify(exec);
14 * Get installed version of git, and install it if it isn't already
16 export async function getGit(settings: Settings): Promise<string | undefined> {
17 let gitExecutable: string | undefined =
19 .getString(SettingsKey.gitPath)
20 ?.replace(HOME_VAR, homedir().replaceAll("\\", "/")) || "git";
21 let gitPath = await which(gitExecutable, { nothrow: true });
22 if (gitPath === null) {
23 // if git is not in path then checkForInstallationRequirements
24 // maye downloaded it, so reload
26 gitExecutable = settings
27 .getString(SettingsKey.gitPath)
28 ?.replace(HOME_VAR, homedir().replaceAll("\\", "/"));
29 if (gitExecutable === null || gitExecutable === undefined) {
30 Logger.log("Error: Git not found.");
32 await window.showErrorMessage(
33 "Git not found. Please install and add to PATH or " +
34 "set the path to the git executable in global settings."
39 gitPath = await which(gitExecutable, { nothrow: true });
43 return gitPath || undefined;
47 * Initialize git submodules in downloaded Pico-SDK.
49 * @param sdkDirectory The directory of the downloaded Pico-SDK.
50 * @returns True if the submodules were initialized successfully, false otherwise.
52 export async function initSubmodules(
54 gitExecutable: string = "git"
57 // Use the "git submodule update --init" command in the specified directory
58 // `cd` command need '/d' option on Windows. (Change drive "d:\" to "c:\")
61 process.env.ComSpec?.endsWith("cmd.exe") ? "/d " : " "
62 }"${sdkDirectory}" && ` +
64 process.env.ComSpec === "powershell.exe" ? "&" : ""
65 }"${gitExecutable}" submodule update --init`;
66 await execAsync(command);
76 export async function cloneRepository(
79 targetDirectory: string,
80 gitExecutable: string = "git"
82 // Clone the repository at the specified tag into the target directory
85 process.env.ComSpec === "powershell.exe" ? "&" : ""
86 }"${gitExecutable}" -c advice.detachedHead=false clone --branch ` +
87 `${branch} ${repository} "${targetDirectory}"`;
90 await execAsync(cloneCommand);
92 Logger.log(`${repository} ${branch} has been cloned and installed.`);
97 await unlink(targetDirectory);
102 const err = error instanceof Error ? error.message : (error as string);
103 if (err.includes("already exists")) {
106 Logger.log(`Error while cloning repository: ${err}`);
112 export async function sparseCloneRepository(
115 targetDirectory: string,
116 gitExecutable: string = "git"
117 ): Promise<boolean> {
118 // Clone the repository at the specified tag into the target directory
121 process.env.ComSpec === "powershell.exe" ? "&" : ""
122 }"${gitExecutable}" -c advice.detachedHead=false clone ` +
123 "--filter=blob:none --sparse --branch " +
124 `${branch} ${repository} "${targetDirectory}"`;
127 await execAsync(cloneCommand);
130 process.env.ComSpec?.endsWith("cmd.exe") ? "/d " : " "
131 }"${targetDirectory}" && ${
132 process.env.ComSpec === "powershell.exe" ? "&" : ""
133 }"${gitExecutable}" sparse-checkout set --cone`
137 `${repository} ${branch} has been cloned with a sparse-checkout.`
143 await unlink(targetDirectory);
148 const err = error instanceof Error ? error.message : (error as string);
149 if (err.includes("already exists")) {
152 Logger.log(`Error while cloning repository: ${err}`);
159 * Add a path to the sparse-checkout of a repository.
161 * @param repoDirectory The directory of the git repository (absolute).
162 * @param checkoutPath The repo-relative path to add to the sparse-checkout.
163 * @param gitExecutable The path to the git executable.
164 * @returns True if the path was added successfully, false otherwise.
166 export async function sparseCheckout(
167 repoDirectory: string,
168 checkoutPath: string,
169 gitExecutable: string = "git"
170 ): Promise<boolean> {
174 process.env.ComSpec?.endsWith("cmd.exe") ? "/d " : " "
175 } "${repoDirectory}" && ${
176 process.env.ComSpec === "powershell.exe" ? "&" : ""
177 }"${gitExecutable}" sparse-checkout add ${checkoutPath}`
182 const err = error instanceof Error ? error.message : (error as string);
183 Logger.log(`Error while cloning repository: ${err}`);