@reliverse/rse-sdk
Version:
@reliverse/rse-sdk allows you to create new plugins for @reliverse/rse CLI, interact with reliverse.org, and even extend your own CLI functionality (you may also try @reliverse/dler-sdk for this case).
181 lines (180 loc) • 6.15 kB
JavaScript
import path from "@reliverse/pathkit";
import { ensuredir } from "@reliverse/relifso";
import fs from "@reliverse/relifso";
import { setHiddenAttribute } from "@reliverse/relifso";
import { relinka } from "@reliverse/relinka";
import { confirmPrompt } from "@reliverse/rempts";
import { simpleGit } from "simple-git";
import tar from "tar-stream";
import { promisify } from "util";
import { gzip } from "zlib";
import {
cliConfigJsonc,
cliConfigJsoncTmp,
cliHomeTmp
} from "../../../../constants.js";
const gzipAsync = promisify(gzip);
async function createArchive(files) {
const pack = tar.pack();
for (const file of files) {
pack.entry({ name: file.name }, file.data);
}
pack.finalize();
const chunks = [];
for await (const chunk of pack) {
chunks.push(chunk);
}
const tarBuffer = Buffer.concat(chunks);
return gzipAsync(tarBuffer);
}
export async function archiveExistingRepoContent(repoUrl, projectPath) {
const tempDir = path.join(cliHomeTmp, Date.now().toString());
try {
await ensuredir(tempDir);
const git = simpleGit();
await git.clone(repoUrl, tempDir);
const shouldArchive = await confirmPrompt({
title: "Would you like to create an archive of the existing repository content?",
content: "In the future, you will be able to run `rse cli` to use merge operations on the project's old and new content. The term `cluster` is used as the name for the old content.",
defaultValue: false
});
if (shouldArchive) {
const fileInputs = [];
const tempFiles = await fs.readdir(tempDir);
for (const file of tempFiles) {
if (file !== ".git") {
const filePath = path.join(tempDir, file);
const stats = await fs.stat(filePath);
if (stats.isFile()) {
const data = await fs.readFile(filePath);
fileInputs.push({
name: file,
data: Buffer.isBuffer(data) ? data : Buffer.from(data)
});
} else if (stats.isDirectory()) {
const dirFiles = await fs.readdir(filePath, {
recursive: true
});
for (const dirFile of dirFiles) {
const fullPath = path.join(tempDir, file, dirFile);
if ((await fs.stat(fullPath)).isFile()) {
const data = await fs.readFile(fullPath);
fileInputs.push({
name: `${file}/${dirFile}`,
data: Buffer.isBuffer(data) ? data : Buffer.from(data)
});
}
}
}
}
}
if (fileInputs.length > 0) {
const archiveName = "cluster.tar.gz";
const archivePath = path.join(projectPath, archiveName);
const tarData = await createArchive(fileInputs);
await fs.writeFile(archivePath, tarData);
relinka(
"info",
`Created archive of repository content at ${archiveName}`
);
}
}
const gitDir = path.join(tempDir, ".git");
if (await fs.pathExists(gitDir)) {
const targetGitDir = path.join(projectPath, ".git");
if (await fs.pathExists(targetGitDir)) {
await fs.remove(targetGitDir);
relinka("verbose", "Removed existing .git directory");
}
await fs.copy(gitDir, path.join(projectPath, ".git"), {
preserveTimestamps: true,
dereference: false,
errorOnExist: false
});
const gitFolderPath = path.join(projectPath, ".git");
await setHiddenAttribute(gitFolderPath);
relinka("verbose", "Copied .git folder from existing repository");
} else {
throw new Error("Required .git folder not found");
}
const filesToCopy = [
{ name: "README.md", required: false },
{ alternatives: ["LICENSE", "LICENSE.md"], required: false },
{
name: cliConfigJsonc,
required: false,
targetName: cliConfigJsoncTmp,
hidden: true
}
];
let externalrseth;
for (const file of filesToCopy) {
if (file.name) {
const sourcePath = path.join(tempDir, file.name);
if (await fs.pathExists(sourcePath)) {
const targetPath = path.join(
projectPath,
file.targetName ?? file.name
);
await fs.copy(sourcePath, targetPath);
if (!file.hidden) {
relinka("info", `Copied ${file.name} from existing repository`);
}
if (file.name === cliConfigJsonc) {
externalrseth = targetPath;
}
}
} else if (file.alternatives) {
for (const name of file.alternatives) {
const filePath = path.join(tempDir, name);
if (await fs.pathExists(filePath)) {
await fs.copy(filePath, path.join(projectPath, name));
relinka("info", `Copied ${name} from existing repository`);
break;
}
}
}
}
return {
success: true,
...externalrseth && { externalRseConfig: externalrseth }
};
} catch (error) {
relinka(
"error",
"Failed to clone repository:",
error instanceof Error ? error.message : String(error)
);
return { success: false };
} finally {
try {
await fs.remove(tempDir);
} catch (error) {
relinka("warn", "Failed to cleanup temporary directory:", String(error));
}
}
}
export async function handleExistingRepoContent(memory, repoOwner, repoName, projectPath) {
try {
const repoUrl = `https://oauth2:${memory.githubKey}@github.com/${repoOwner}/${repoName}.git`;
const { success, externalRseConfig } = await archiveExistingRepoContent(
repoUrl,
projectPath
);
if (!success) {
throw new Error("Failed to retrieve repository git data");
}
relinka("success", "Retrieved repository git directory data");
return {
success: true,
...externalRseConfig && { externalRseConfig }
};
} catch (error) {
relinka(
"error",
"Failed to set up existing repository:",
error instanceof Error ? error.message : String(error)
);
return { success: false };
}
}