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
59 `cd "${sdkDirectory}" && ` +
61 process.env.ComSpec === "powershell.exe" ? "&" : ""
62 }"${gitExecutable}" submodule update --init`;
63 await execAsync(command);
73 export async function cloneRepository(
76 targetDirectory: string,
77 gitExecutable: string = "git"
79 // Clone the repository at the specified tag into the target directory
82 process.env.ComSpec === "powershell.exe" ? "&" : ""
83 }"${gitExecutable}" -c advice.detachedHead=false clone --branch ` +
84 `${branch} ${repository} "${targetDirectory}"`;
87 await execAsync(cloneCommand);
89 Logger.log(`${repository} ${branch} has been cloned and installed.`);
94 await unlink(targetDirectory);
99 const err = error instanceof Error ? error.message : (error as string);
100 if (err.includes("already exists")) {
103 Logger.log(`Error while cloning repository: ${err}`);
109 export async function sparseCloneRepository(
112 targetDirectory: string,
113 gitExecutable: string = "git"
114 ): Promise<boolean> {
115 // Clone the repository at the specified tag into the target directory
118 process.env.ComSpec === "powershell.exe" ? "&" : ""
119 }"${gitExecutable}" -c advice.detachedHead=false clone ` +
120 "--filter=blob:none --sparse --branch " +
121 `${branch} ${repository} "${targetDirectory}"`;
124 await execAsync(cloneCommand);
126 `cd "${targetDirectory}" && ${
127 process.env.ComSpec === "powershell.exe" ? "&" : ""
128 }"${gitExecutable}" sparse-checkout set --cone`
132 `${repository} ${branch} has been cloned with a sparse-checkout.`
138 await unlink(targetDirectory);
143 const err = error instanceof Error ? error.message : (error as string);
144 if (err.includes("already exists")) {
147 Logger.log(`Error while cloning repository: ${err}`);
154 * Add a path to the sparse-checkout of a repository.
156 * @param repoDirectory The directory of the git repository (absolute).
157 * @param checkoutPath The repo-relative path to add to the sparse-checkout.
158 * @param gitExecutable The path to the git executable.
159 * @returns True if the path was added successfully, false otherwise.
161 export async function sparseCheckout(
162 repoDirectory: string,
163 checkoutPath: string,
164 gitExecutable: string = "git"
165 ): Promise<boolean> {
168 `cd "${repoDirectory}" && ${
169 process.env.ComSpec === "powershell.exe" ? "&" : ""
170 }"${gitExecutable}" sparse-checkout add ${checkoutPath}`
175 const err = error instanceof Error ? error.message : (error as string);
176 Logger.log(`Error while cloning repository: ${err}`);