]> Git Repo - pico-vscode.git/blob - src/utils/gitUtil.mts
Update dependencies + auto-format
[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(settings: Settings): Promise<string | undefined> {
17   let gitExecutable: string | undefined =
18     settings
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
25     settings.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.");
31
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."
35       );
36
37       return undefined;
38     } else {
39       gitPath = await which(gitExecutable, { nothrow: true });
40     }
41   }
42
43   return gitPath || undefined;
44 }
45
46 /**
47  * Initialize git submodules in downloaded Pico-SDK.
48  *
49  * @param sdkDirectory The directory of the downloaded Pico-SDK.
50  * @returns True if the submodules were initialized successfully, false otherwise.
51  */
52 export async function initSubmodules(
53   sdkDirectory: string,
54   gitExecutable: string = "git"
55 ): Promise<boolean> {
56   try {
57     // Use the "git submodule update --init" command in the specified directory
58     const command =
59       `cd "${sdkDirectory}" && ` +
60       `${
61         process.env.ComSpec === "powershell.exe" ? "&" : ""
62       }"${gitExecutable}" submodule update --init`;
63     await execAsync(command);
64
65     return true;
66   } catch (error) {
67     console.error(error);
68
69     return false;
70   }
71 }
72
73 export async function cloneRepository(
74   repository: string,
75   branch: string,
76   targetDirectory: string,
77   gitExecutable: string = "git"
78 ): Promise<boolean> {
79   // Clone the repository at the specified tag into the target directory
80   const cloneCommand =
81     `${
82       process.env.ComSpec === "powershell.exe" ? "&" : ""
83     }"${gitExecutable}" -c advice.detachedHead=false clone --branch ` +
84     `${branch} ${repository} "${targetDirectory}"`;
85
86   try {
87     await execAsync(cloneCommand);
88
89     Logger.log(`${repository} ${branch} has been cloned and installed.`);
90
91     return true;
92   } catch (error) {
93     try {
94       await unlink(targetDirectory);
95     } catch {
96       /* */
97     }
98
99     const err = error instanceof Error ? error.message : (error as string);
100     if (err.includes("already exists")) {
101       return true;
102     }
103     Logger.log(`Error while cloning repository: ${err}`);
104
105     return false;
106   }
107 }
108
109 export async function sparseCloneRepository(
110   repository: string,
111   branch: string,
112   targetDirectory: string,
113   gitExecutable: string = "git"
114 ): Promise<boolean> {
115   // Clone the repository at the specified tag into the target directory
116   const cloneCommand =
117     `${
118       process.env.ComSpec === "powershell.exe" ? "&" : ""
119     }"${gitExecutable}" -c advice.detachedHead=false clone ` +
120     "--filter=blob:none --sparse --branch " +
121     `${branch} ${repository} "${targetDirectory}"`;
122
123   try {
124     await execAsync(cloneCommand);
125     await execAsync(
126       `cd "${targetDirectory}" && ${
127         process.env.ComSpec === "powershell.exe" ? "&" : ""
128       }"${gitExecutable}" sparse-checkout set --cone`
129     );
130
131     Logger.log(
132       `${repository} ${branch} has been cloned with a sparse-checkout.`
133     );
134
135     return true;
136   } catch (error) {
137     try {
138       await unlink(targetDirectory);
139     } catch {
140       /* */
141     }
142
143     const err = error instanceof Error ? error.message : (error as string);
144     if (err.includes("already exists")) {
145       return true;
146     }
147     Logger.log(`Error while cloning repository: ${err}`);
148
149     return false;
150   }
151 }
152
153 /**
154  * Add a path to the sparse-checkout of a repository.
155  *
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.
160  */
161 export async function sparseCheckout(
162   repoDirectory: string,
163   checkoutPath: string,
164   gitExecutable: string = "git"
165 ): Promise<boolean> {
166   try {
167     await execAsync(
168       `cd "${repoDirectory}" && ${
169         process.env.ComSpec === "powershell.exe" ? "&" : ""
170       }"${gitExecutable}" sparse-checkout add ${checkoutPath}`
171     );
172
173     return true;
174   } catch (error) {
175     const err = error instanceof Error ? error.message : (error as string);
176     Logger.log(`Error while cloning repository: ${err}`);
177
178     return false;
179   }
180 }
This page took 0.037039 seconds and 4 git commands to generate.