Skip to content

Commit

Permalink
feat: git release bundle (#61)
Browse files Browse the repository at this point in the history
  • Loading branch information
giladgd authored Oct 8, 2023
1 parent 3400fce commit ada896b
Show file tree
Hide file tree
Showing 6 changed files with 130 additions and 41 deletions.
12 changes: 11 additions & 1 deletion .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,9 @@ jobs:
- name: Generate docs
run: npm run generate-docs
- name: Download latest llama.cpp release
run: node ./dist/cli/cli.js download --release latest --skipBuild --updateBinariesReleaseMetadata
env:
CI: true
run: node ./dist/cli/cli.js download --release latest --skipBuild --updateBinariesReleaseMetadataAndSaveGitBundle
- name: Upload build artifact
uses: actions/upload-artifact@v3
with:
Expand All @@ -41,6 +43,11 @@ jobs:
with:
name: "llama.cpp"
path: "llama/llama.cpp"
- name: Upload gitRelease.bundle artifact
uses: actions/upload-artifact@v3
with:
name: "gitReleaseBundle"
path: "llama/gitRelease.bundle"

build-binaries:
name: Build binaries - ${{ matrix.config.name }}
Expand Down Expand Up @@ -243,6 +250,9 @@ jobs:
rm -f ./llama/binariesGithubRelease.json
mv artifacts/binariesGithubRelease/binariesGithubRelease.json ./llama/binariesGithubRelease.json
rm -f ./llama/gitRelease.bundle
mv artifacts/gitReleaseBundle/gitRelease.bundle ./llama/gitRelease.bundle
echo "Built binaries:"
ls llamaBins
- name: Add "postinstall" script to package.json
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ node_modules

/llama/compile_commands.json
/llama/llama.cpp
/llama/gitRelease.bundle
/llama/.temp
/llama/build
/llama/Release
Expand Down
49 changes: 9 additions & 40 deletions src/cli/commands/DownloadCommand.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,17 @@ import {CommandModule} from "yargs";
import {Octokit} from "octokit";
import fs from "fs-extra";
import chalk from "chalk";
import cliProgress from "cli-progress";
import simpleGit from "simple-git";
import {
defaultLlamaCppCudaSupport, defaultLlamaCppGitHubRepo, defaultLlamaCppMetalSupport, defaultLlamaCppRelease, llamaCppDirectory
defaultLlamaCppCudaSupport, defaultLlamaCppGitHubRepo, defaultLlamaCppMetalSupport, defaultLlamaCppRelease, isCI, llamaCppDirectory
} from "../../config.js";
import {compileLlamaCpp} from "../../utils/compileLLamaCpp.js";
import withOra from "../../utils/withOra.js";
import {clearTempFolder} from "../../utils/clearTempFolder.js";
import {setBinariesGithubRelease} from "../../utils/binariesGithubRelease.js";
import {downloadCmakeIfNeeded} from "../../utils/cmake.js";
import withStatusLogs from "../../utils/withStatusLogs.js";
import {saveCurrentRepoAsReleaseBundle} from "../../utils/gitReleaseBundles.js";
import {cloneLlamaCppRepo} from "../../utils/cloneLlamaCppRepo.js";

type DownloadCommandArgs = {
repo: string,
Expand All @@ -23,7 +23,7 @@ type DownloadCommandArgs = {
metal: boolean,
cuda: boolean,
skipBuild?: boolean,
updateBinariesReleaseMetadata?: boolean
updateBinariesReleaseMetadataAndSaveGitBundle?: boolean
};

export const DownloadCommand: CommandModule<object, DownloadCommandArgs> = {
Expand Down Expand Up @@ -68,7 +68,7 @@ export const DownloadCommand: CommandModule<object, DownloadCommandArgs> = {
default: false,
description: "Skip building llama.cpp after downloading it"
})
.option("updateBinariesReleaseMetadata", {
.option("updateBinariesReleaseMetadataAndSaveGitBundle", {
type: "boolean",
hidden: true, // this for the CI to use
default: false,
Expand All @@ -79,7 +79,7 @@ export const DownloadCommand: CommandModule<object, DownloadCommandArgs> = {
};

export async function DownloadLlamaCppCommand({
repo, release, arch, nodeTarget, metal, cuda, skipBuild, updateBinariesReleaseMetadata
repo, release, arch, nodeTarget, metal, cuda, skipBuild, updateBinariesReleaseMetadataAndSaveGitBundle
}: DownloadCommandArgs) {
const octokit = new Octokit();
const [githubOwner, githubRepo] = repo.split("/");
Expand Down Expand Up @@ -143,7 +143,7 @@ export async function DownloadLlamaCppCommand({
});

console.log(chalk.blue("Cloning llama.cpp"));
await cloneTag(githubOwner, githubRepo, githubRelease!.data.tag_name, llamaCppDirectory);
await cloneLlamaCppRepo(githubOwner, githubRepo, githubRelease!.data.tag_name);

if (!skipBuild) {
await downloadCmakeIfNeeded(true);
Expand All @@ -163,8 +163,9 @@ export async function DownloadLlamaCppCommand({
});
}

if (updateBinariesReleaseMetadata) {
if (isCI && updateBinariesReleaseMetadataAndSaveGitBundle) {
await setBinariesGithubRelease(githubRelease!.data.tag_name);
await saveCurrentRepoAsReleaseBundle();
}

console.log();
Expand All @@ -174,35 +175,3 @@ export async function DownloadLlamaCppCommand({
console.log();
console.log(chalk.green("Done"));
}


async function cloneTag(githubOwner: string, githubRepo: string, tag: string, directory: string) {
const progressBar = new cliProgress.Bar({
clearOnComplete: false,
hideCursor: true,
autopadding: true,
format: `${chalk.bold("Clone {repo}")} ${chalk.yellow("{percentage}%")} ${chalk.cyan("{bar}")} ${chalk.grey("{eta_formatted}")}`
}, cliProgress.Presets.shades_classic);

progressBar.start(100, 0, {
speed: "",
repo: `${githubOwner}/${githubRepo}`
});

try {
await simpleGit({
progress({progress, total, processed}) {
const totalProgress = (processed / 100) + (progress / total);

progressBar.update(Math.floor(totalProgress * 10000) / 100);
}
}).clone(`https://github.com/${githubOwner}/${githubRepo}.git`, directory, {
"--depth": 1,
"--branch": tag,
"--quiet": null
});
} finally {
progressBar.update(100);
progressBar.stop();
}
}
4 changes: 4 additions & 0 deletions src/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,15 @@ export const llamaCppGrammarsDirectory = path.join(llamaDirectory, "llama.cpp",
export const tempDownloadDirectory = path.join(os.tmpdir(), "node-llama-cpp", uuid.v4());
export const usedBinFlagJsonPath = path.join(llamaDirectory, "usedBin.json");
export const binariesGithubReleasePath = path.join(llamaDirectory, "binariesGithubRelease.json");
export const currentReleaseGitBundlePath = path.join(llamaDirectory, "gitRelease.bundle");
export const xpackDirectory = path.join(llamaDirectory, "xpack");
export const localXpacksStoreDirectory = path.join(xpackDirectory, "store");
export const localXpacksCacheDirectory = path.join(xpackDirectory, "cache");
export const xpmVersion = "^0.16.3";

export const isCI = env.get("CI")
.default("false")
.asBool();
export const defaultLlamaCppGitHubRepo = env.get("NODE_LLAMA_CPP_REPO")
.default("ggerganov/llama.cpp")
.asString();
Expand Down
71 changes: 71 additions & 0 deletions src/utils/cloneLlamaCppRepo.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
import simpleGit, {SimpleGit} from "simple-git";
import cliProgress from "cli-progress";
import chalk from "chalk";
import fs from "fs-extra";
import {llamaCppDirectory} from "../config.js";
import {getGitBundlePathForRelease} from "./gitReleaseBundles.js";


export async function cloneLlamaCppRepo(githubOwner: string, githubRepo: string, tag: string) {
const gitBundleForTag = await getGitBundlePathForRelease(githubOwner, githubRepo, tag);
const remoteGitUrl = `https://github.com/${githubOwner}/${githubRepo}.git`;

async function withGitCloneProgress<T>(cloneName: string, callback: (gitWithCloneProgress: SimpleGit) => Promise<T>): Promise<T> {
const progressBar = new cliProgress.Bar({
clearOnComplete: false,
hideCursor: true,
autopadding: true,
format: `${chalk.bold("Clone {repo}")} ${chalk.yellow("{percentage}%")} ${chalk.cyan("{bar}")} ${chalk.grey("{eta_formatted}")}`
}, cliProgress.Presets.shades_classic);

progressBar.start(100, 0, {
speed: "",
repo: `${githubOwner}/${githubRepo} (${cloneName})`
});

const gitWithCloneProgress = simpleGit({
progress({progress, total, processed}) {
const totalProgress = (processed / 100) + (progress / total);

progressBar.update(Math.floor(totalProgress * 10000) / 100);
}
});

try {
const res = await callback(gitWithCloneProgress);

progressBar.update(100);

return res;
} finally {
progressBar.stop();
}
}

if (gitBundleForTag != null) {
try {
await withGitCloneProgress("local bundle", async (gitWithCloneProgress) => {
await gitWithCloneProgress.clone(gitBundleForTag, llamaCppDirectory, {
"--quiet": null
});

await simpleGit(llamaCppDirectory)
.removeRemote("origin");
await simpleGit(llamaCppDirectory)
.addRemote("origin", remoteGitUrl);
});
return;
} catch (err) {
await fs.remove(llamaCppDirectory);
console.error("Failed to clone git bundle, cloning from GitHub instead", err);
}
}

await withGitCloneProgress("GitHub", async (gitWithCloneProgress) => {
await gitWithCloneProgress.clone(remoteGitUrl, llamaCppDirectory, {
"--depth": 1,
"--branch": tag,
"--quiet": null
});
});
}
34 changes: 34 additions & 0 deletions src/utils/gitReleaseBundles.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import fs from "fs-extra";
import simpleGit from "simple-git";
import {currentReleaseGitBundlePath, defaultLlamaCppGitHubRepo, llamaCppDirectory} from "../config.js";
import {getBinariesGithubRelease} from "./binariesGithubRelease.js";


export async function saveCurrentRepoAsReleaseBundle() {
if (!(await fs.pathExists(llamaCppDirectory)))
throw new Error("llama.cpp directory does not exist");

if (await fs.pathExists(currentReleaseGitBundlePath))
await fs.remove(currentReleaseGitBundlePath);

await simpleGit(llamaCppDirectory).raw(["bundle", "create", currentReleaseGitBundlePath, "HEAD"]);
}

export async function getGitBundlePathForRelease(githubOwner: string, githubRepo: string, release: string) {
const [defaultGithubOwner, defaultGithubRepo] = defaultLlamaCppGitHubRepo.split("/");
if (githubOwner !== defaultGithubOwner || githubRepo !== defaultGithubRepo)
return null;

const currentBundleRelease = await getBinariesGithubRelease();

if (currentBundleRelease === "latest")
return null;

if (currentBundleRelease !== release)
return null;

if (!(await fs.pathExists(currentReleaseGitBundlePath)))
return null;

return currentReleaseGitBundlePath;
}

0 comments on commit ada896b

Please sign in to comment.