]> Git Repo - pico-vscode.git/blob - src/utils/gitUtil.mts
Ensure examples clone is up to date
[pico-vscode.git] / src / utils / gitUtil.mts
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";
10
11 export const execAsync = promisify(exec);
12
13 /**
14  * Get installed version of git, and install it if it isn't already
15  */
16 export async function getGit(
17   settings: Settings
18 ): Promise<string | undefined> {
19   let gitExecutable: string | undefined =
20     settings
21       .getString(SettingsKey.gitPath)
22       ?.replace(HOME_VAR, homedir().replaceAll("\\", "/")) || "git";
23   let gitPath = await which(gitExecutable, { nothrow: true });
24   if (gitPath === null) {
25     // if git is not in path then checkForInstallationRequirements
26     // maye downloaded it, so reload
27     settings.reload();
28     gitExecutable = settings
29       .getString(SettingsKey.gitPath)
30       ?.replace(HOME_VAR, homedir().replaceAll("\\", "/"));
31     if (gitExecutable === null || gitExecutable === undefined) {
32       Logger.log("Error: Git not found.");
33
34       await window.showErrorMessage(
35         "Git not found. Please install and add to PATH or " +
36           "set the path to the git executable in global settings."
37       );
38
39       return undefined;
40     } else {
41       gitPath = await which(gitExecutable, { nothrow: true });
42     }
43   }
44
45   return gitPath;
46 }
47
48 /**
49  * Initialize git submodules in downloaded Pico-SDK.
50  *
51  * @param sdkDirectory The directory of the downloaded Pico-SDK.
52  * @returns True if the submodules were initialized successfully, false otherwise.
53  */
54 export async function initSubmodules(
55   sdkDirectory: string,
56   gitExecutable: string = "git"
57 ): Promise<boolean> {
58   try {
59     // Use the "git submodule update --init" command in the specified directory
60     const command =
61       `cd "${sdkDirectory}" && ` +
62       `${
63         process.env.ComSpec === "powershell.exe" ? "&" : ""
64       }"${gitExecutable}" submodule update --init`;
65     await execAsync(command);
66
67     return true;
68   } catch (error) {
69     console.error(error);
70
71     return false;
72   }
73 }
74
75 export async function cloneRepository(
76   repository: string,
77   branch: string,
78   targetDirectory: string,
79   gitExecutable: string = "git"
80 ): Promise<boolean> {
81   // Clone the repository at the specified tag into the target directory
82   const cloneCommand =
83     `${
84       process.env.ComSpec === "powershell.exe" ? "&" : ""
85     }"${gitExecutable}" -c advice.detachedHead=false clone --branch ` +
86     `${branch} ${repository} "${targetDirectory}"`;
87
88   try {
89     await execAsync(cloneCommand);
90
91     Logger.log(`${repository} ${branch} has been cloned and installed.`);
92
93     return true;
94   } catch (error) {
95     try {
96       await unlink(targetDirectory);
97     } catch {
98       /* */
99     }
100
101     const err = error instanceof Error ? error.message : (error as string);
102     if (err.includes("already exists")) {
103       return true;
104     }
105     Logger.log(`Error while cloning repository: ${err}`);
106
107     return false;
108   }
109 }
110
111 export async function sparseCloneRepository(
112   repository: string,
113   branch: string,
114   targetDirectory: string,
115   gitExecutable: string = "git"
116 ): Promise<boolean> {
117   // Clone the repository at the specified tag into the target directory
118   const cloneCommand =
119     `${
120       process.env.ComSpec === "powershell.exe" ? "&" : ""
121     }"${gitExecutable}" -c advice.detachedHead=false clone ` +
122     "--filter=blob:none --sparse --branch " +
123     `${branch} ${repository} "${targetDirectory}"`;
124
125   try {
126     await execAsync(cloneCommand);
127     await execAsync(
128       `cd "${targetDirectory}" && ${
129         process.env.ComSpec === "powershell.exe" ? "&" : ""
130       }"${gitExecutable}" sparse-checkout set --cone`
131     );
132
133     Logger.log(
134       `${repository} ${branch} has been cloned with a sparse-checkout.`
135     );
136
137     return true;
138   } catch (error) {
139     try {
140       await unlink(targetDirectory);
141     } catch {
142       /* */
143     }
144
145     const err = error instanceof Error ? error.message : (error as string);
146     if (err.includes("already exists")) {
147       return true;
148     }
149     Logger.log(`Error while cloning repository: ${err}`);
150
151     return false;
152   }
153 }
154
155 /**
156  * Add a path to the sparse-checkout of a repository.
157  *
158  * @param repoDirectory The directory of the git repository (absolute).
159  * @param checkoutPath The repo-relative path to add to the sparse-checkout.
160  * @param gitExecutable The path to the git executable.
161  * @returns True if the path was added successfully, false otherwise.
162  */
163 export async function sparseCheckout(
164   repoDirectory: string,
165   checkoutPath: string,
166   gitExecutable: string = "git"
167 ): Promise<boolean> {
168   try {
169     await execAsync(
170       `cd "${repoDirectory}" && ${
171         process.env.ComSpec === "powershell.exe" ? "&" : ""
172       }"${gitExecutable}" sparse-checkout add ${checkoutPath}`
173     );
174
175     return true;
176   } catch (error) {
177     const err = error instanceof Error ? error.message : (error as string);
178     Logger.log(`Error while cloning repository: ${err}`);
179
180     return false;
181   }
182 }
This page took 0.032559 seconds and 4 git commands to generate.