change git backup and Update server backup
* now git backup remove diif files in git. * update Server backup to wait seconds to before create Backup. * In the future bds cli move to separeted package.
This commit is contained in:
13317
package-lock.json
generated
13317
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -72,6 +72,7 @@
|
||||
"cli-color": "^2.0.2",
|
||||
"cron": "^1.8.2",
|
||||
"cron-validator": "^1.3.1",
|
||||
"dir-compare": "^4.0.0",
|
||||
"fs-extra": "^10.0.1",
|
||||
"prismarine-nbt": "^2.2.1",
|
||||
"simple-git": "^3.6.0",
|
||||
|
@ -5,9 +5,10 @@ import fs, { promises as fsPromise } from "fs";
|
||||
import fse from "fs-extra";
|
||||
import AdmZip from "adm-zip";
|
||||
import simpleGit from "simple-git";
|
||||
import { compare as compareDir } from "dir-compare";
|
||||
|
||||
const ServerPathRoot = path.resolve(process.env.SERVER_PATH||path.join(os.homedir(), "bds_core/servers"));
|
||||
const backupFolderPath = path.resolve(process.env.BACKUP_PATH||path.join(os.homedir(), "bds_core/backups"));
|
||||
export const backupFolderPath = path.resolve(process.env.BACKUP_PATH||path.join(os.homedir(), "bds_core/backups"));
|
||||
|
||||
async function createTempFolder() {
|
||||
let cleaned = false;
|
||||
@ -123,16 +124,18 @@ export async function CreateBackup(WriteFile: {path: string}|true|false = false)
|
||||
await TempFolder.cleanFolder();
|
||||
// Get Zip Buffer
|
||||
const zipBuffer = zip.toBuffer();
|
||||
if (typeof WriteFile === "object") {
|
||||
let BackupFile = path.resolve(backupFolderPath, `${new Date().toString().replace(/[-\(\)\:\s+]/gi, "_")}.zip`);
|
||||
let BackupFile = path.resolve(backupFolderPath, `${new Date().toString().replace(/[-\(\)\:\s+]/gi, "_")}.zip`);
|
||||
if (WriteFile === true) await fsPromise.writeFile(BackupFile, zipBuffer);
|
||||
else if (typeof WriteFile === "object") {
|
||||
if (!!WriteFile.path) BackupFile = path.resolve(WriteFile.path);
|
||||
fs.writeFileSync(BackupFile, zipBuffer);
|
||||
await fsPromise.writeFile(BackupFile, zipBuffer);
|
||||
}
|
||||
return zipBuffer;
|
||||
}
|
||||
|
||||
export type gitBackupOption = {
|
||||
repoUrl: string;
|
||||
branch?: string;
|
||||
Auth?: {
|
||||
Username?: string;
|
||||
PasswordToken: string
|
||||
@ -142,29 +145,36 @@ export type gitBackupOption = {
|
||||
|
||||
async function initGitRepo(RepoPath: string, options?: gitBackupOption): Promise<void> {
|
||||
if (fs.existsSync(RepoPath)) {
|
||||
if (fs.existsSync(path.join(RepoPath, ".git"))) await fsPromise.rm(RepoPath, {recursive: true});
|
||||
if (fs.existsSync(path.join(RepoPath, ".git"))) {
|
||||
if (options?.Auth?.Username || options?.Auth?.PasswordToken) {
|
||||
await fsPromise.rm(RepoPath, {recursive: true});
|
||||
} else return;
|
||||
}
|
||||
}
|
||||
await fsPromise.mkdir(RepoPath, {recursive: true});
|
||||
if (!!options) {
|
||||
if (!options.repoUrl) throw new Error("RepoUrl is required");
|
||||
let gitUrl = options.repoUrl;
|
||||
const { host, pathname, protocol } = new URL(options.repoUrl);
|
||||
if (!!options.Auth) {
|
||||
if (!!options.Auth.Username) gitUrl = `${protocol}//${options.Auth.Username}:${options.Auth.PasswordToken}@${host}${pathname}`;
|
||||
else gitUrl = `${protocol}//${options.Auth.PasswordToken}@${host}${pathname}`;
|
||||
if (options) {
|
||||
if (options.repoUrl) {
|
||||
let gitUrl = options.repoUrl;
|
||||
const gitClone = simpleGit(RepoPath);
|
||||
await gitClone.clone(gitUrl, RepoPath);
|
||||
if (options.branch) await gitClone.checkout(options.branch);
|
||||
} else {
|
||||
console.log("No Repo Url, creating empty repo");
|
||||
await initGitRepo(RepoPath);
|
||||
return;
|
||||
}
|
||||
const gitClone = simpleGit(RepoPath);
|
||||
await gitClone.clone(gitUrl, RepoPath);
|
||||
if (!!(await gitClone.getConfig("user.name").catch(() => {}))) await gitClone.addConfig("user.name", "BDS-Backup");
|
||||
if (!!(await gitClone.getConfig("user.email").catch(() => {}))) await gitClone.addConfig("user.email", "support_bds@sirherobrine23.org");
|
||||
return;
|
||||
} else {
|
||||
// Create empty git repo and create main branch
|
||||
const gitInit = simpleGit(RepoPath);
|
||||
await gitInit.init()
|
||||
// Create main branch
|
||||
await gitInit.checkoutBranch("main", "master");
|
||||
}
|
||||
// Create empty git repo and create main branch
|
||||
const gitInit = simpleGit(RepoPath);
|
||||
await gitInit.init()
|
||||
if (!!(await gitInit.getConfig("user.name").catch(() => {}))) await gitInit.addConfig("user.name", "BDS-Backup");
|
||||
if (!!(await gitInit.getConfig("user.email").catch(() => {}))) await gitInit.addConfig("user.email", "support_bds@sirherobrine23.org");
|
||||
await gitInit.checkout("main", ["-b", "main"]);
|
||||
const git = simpleGit(RepoPath);
|
||||
if (!!(await git.getConfig("user.email"))) await git.addConfig("user.email", "support_bds@sirherobrine23.org");
|
||||
if (!!(await git.getConfig("user.name"))) await git.addConfig("user.name", "BDS-Backup");
|
||||
// if (options?.Auth?.Username) await git.addConfig("user.name", options.Auth.Username);
|
||||
if (options?.Auth?.PasswordToken) await git.addConfig("user.password", options.Auth.PasswordToken);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -176,24 +186,30 @@ async function initGitRepo(RepoPath: string, options?: gitBackupOption): Promise
|
||||
export async function gitBackup(options?: gitBackupOption): Promise<void>{
|
||||
const gitFolder = path.join(backupFolderPath, "gitBackup");
|
||||
await initGitRepo(gitFolder, options);
|
||||
const Files = await genericAddFiles();
|
||||
const filesGit = (await fsPromise.readdir(gitFolder)).filter(a => a !== ".git");
|
||||
for (const file of filesGit) await fsPromise.rm(path.join(gitFolder, file), {recursive: true, force: true}).catch(err => console.log(err));
|
||||
for (const file of await Files.listFiles()) {
|
||||
await fsPromise.mkdir(path.join(gitFolder, path.parse(file).dir), {recursive: true}).catch(() => {});
|
||||
await fsPromise.copyFile(path.join(Files.tempFolderPath, file), path.join(gitFolder, file));
|
||||
const TempFiles = await genericAddFiles();
|
||||
const git = simpleGit(gitFolder, {baseDir: gitFolder});
|
||||
await git.stash();
|
||||
await git.pull();
|
||||
const Difff = (await compareDir(TempFiles.tempFolderPath, gitFolder, {excludeFilter: ".git"})).diffSet.filter(a => a.type1 === "missing"||a.type2 === "missing").filter(a => a.type1 === "file"||a.type2 === "file");
|
||||
await Promise.all(Difff.map(async file => {
|
||||
// Delete files
|
||||
const FileDelete = path.join(file.path2, file.name2);
|
||||
await fsPromise.rm(FileDelete, {force: true});
|
||||
}));
|
||||
await Promise.all((await TempFiles.listFiles()).map(async file => {
|
||||
const gitPath = path.join(gitFolder, file);
|
||||
const tempFolderPath = path.join(TempFiles.tempFolderPath, file);
|
||||
if (!(fs.existsSync(path.join(gitFolder, path.parse(file).dir)))) await fsPromise.mkdir(path.join(gitFolder, path.parse(file).dir), {recursive: true}).catch(() => {});
|
||||
await fsPromise.copyFile(tempFolderPath, gitPath);
|
||||
}))
|
||||
await TempFiles.cleanFolder();
|
||||
await git.add(gitFolder).then(() => git.commit(`BDS Backup - ${new Date()}`).catch(console.error));
|
||||
if (!!((options||{}).Auth||{}).Username) {
|
||||
console.log("Pushing to remote");
|
||||
await git.push([
|
||||
"--force",
|
||||
"--set-upstream"
|
||||
]);
|
||||
}
|
||||
await Files.cleanFolder();
|
||||
const git = simpleGit(gitFolder);
|
||||
await git.stash().pull().catch(() => {});
|
||||
if ((await (await git.status()).files.length > 0)) {
|
||||
await simpleGit(gitFolder).add(".");
|
||||
await simpleGit(gitFolder).commit(`BDS Backup - ${new Date().toString()}`);
|
||||
}
|
||||
if (!!((options||{}).Auth||{}).Username) await git.push([
|
||||
"--force",
|
||||
"--set-upstream",
|
||||
"--progress"
|
||||
]);
|
||||
return;
|
||||
}
|
||||
|
@ -8,18 +8,20 @@ import cli_color from "cli-color";
|
||||
import path from "path";
|
||||
import { promises as fsPromise } from "fs";
|
||||
|
||||
console.info("In the future, this cli well move to another separate package, more info: \"https://github.com/The-Bds-Maneger/bds-cli/wiki/Move-from-core-package-to-separated-package\"");
|
||||
const Yargs = yargs(process.argv.slice(2)).command("download", "Download and Install server", async yargs => {
|
||||
const options = yargs.option("version", {
|
||||
alias: "v",
|
||||
describe: "Server Version",
|
||||
demandOption: true,
|
||||
type: "string"
|
||||
demandOption: false,
|
||||
type: "string",
|
||||
default: "latest"
|
||||
}).option("platform", {
|
||||
alias: "p",
|
||||
describe: "Bds Core Platform",
|
||||
demandOption: true,
|
||||
type: "string",
|
||||
choices: ["bedrock", "java", "pocketmine", "spigot", "dragonfly"],
|
||||
choices: bdsTypes.PlatformArray,
|
||||
default: "bedrock"
|
||||
}).parseSync();
|
||||
const Platform = options.platform as bdsTypes.Platform;
|
||||
@ -63,19 +65,34 @@ const Yargs = yargs(process.argv.slice(2)).command("download", "Download and Ins
|
||||
describe: "Bds Core Platform",
|
||||
demandOption: true,
|
||||
type: "string",
|
||||
choices: ["bedrock", "java", "pocketmine", "spigot", "dragonfly"],
|
||||
choices: bdsTypes.PlatformArray,
|
||||
default: "bedrock"
|
||||
}).option("cronBackup", {
|
||||
alias: "b",
|
||||
alias: "c",
|
||||
describe: "cron job to backup server maps",
|
||||
type: "string"
|
||||
type: "string",
|
||||
default: ""
|
||||
}).option("gitBackup", {
|
||||
alias: "g",
|
||||
describe: "git config to backup, equal 'backup -g \"<user>,<pass>,<Url>\" or backup -g \"local\"', required if cronBackup is set",
|
||||
type: "string",
|
||||
default: ""
|
||||
}).parseAsync();
|
||||
const Platform = options.platform as bdsTypes.Platform;
|
||||
if (!!options.cronBackup) {
|
||||
if (!(isValidCron(options.cronBackup, {seconds: true}))) {
|
||||
if (!(isValidCron(options.cronBackup, {seconds: options.cronBackup.split(/\s+/g).length >= 6}))) {
|
||||
console.error("Invalid cron job");
|
||||
process.exit(1);
|
||||
}
|
||||
if (!!options.gitBackup) {
|
||||
if (options.gitBackup !== "local") {
|
||||
const [user, pass, url] = options.gitBackup.split(",");
|
||||
if (!(user && pass && url)) {
|
||||
console.error("Invalid git config, disable git backup");
|
||||
options.gitBackup = "";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
const Server = await BdsCore.Server.Start(Platform);
|
||||
console.log("Session ID: %s", Server.id);
|
||||
|
@ -350,46 +350,43 @@ export async function Start(Platform: bdsTypes.Platform, options?: startServerOp
|
||||
startDate: StartDate,
|
||||
seed: undefined,
|
||||
addonManeger: undefined,
|
||||
creteBackup: (crontime: string|Date, option?: {type: "git"; config: bdsBackup.gitBackupOption}|{type: "zip"}) => {
|
||||
function lockServerBackup() {
|
||||
if (Platform === "bedrock") {
|
||||
serverCommands.execCommand("save hold");
|
||||
serverCommands.execCommand("save query");
|
||||
}
|
||||
}
|
||||
function unLockServerBackup() {
|
||||
if (Platform === "bedrock") serverCommands.execCommand("save resume");
|
||||
}
|
||||
if (!!option) {
|
||||
creteBackup: (crontime: string|Date, option?: {type: "git"; config: bdsBackup.gitBackupOption}|{type: "zip", pathZip?: string}): node_cron.CronJob => {
|
||||
// Validate Config
|
||||
if (option) {
|
||||
if (option.type === "git") {
|
||||
if (!option.config) throw new Error("Config is required");
|
||||
const cronGit = new node_cron.CronJob(crontime, () => {
|
||||
lockServerBackup();
|
||||
bdsBackup.gitBackup(option.config).catch(() => undefined).then(() => unLockServerBackup());
|
||||
});
|
||||
cronGit.start();
|
||||
ServerProcess.on("exit", () => cronGit.stop());
|
||||
return cronGit;
|
||||
} else if (option.type === "zip") {
|
||||
const zipCron = new node_cron.CronJob(crontime, () => {
|
||||
lockServerBackup();
|
||||
bdsBackup.CreateBackup(true).catch(() => undefined).then(() => unLockServerBackup());
|
||||
});
|
||||
zipCron.start();
|
||||
ServerProcess.on("exit", () => zipCron.stop());
|
||||
return zipCron;
|
||||
}
|
||||
} else {
|
||||
const cronJob = new node_cron.CronJob(crontime, async () => {
|
||||
lockServerBackup();
|
||||
await bdsBackup.CreateBackup(true);
|
||||
unLockServerBackup();
|
||||
});
|
||||
ServerProcess.on("exit", () => cronJob.stop());
|
||||
cronJob.start();
|
||||
return cronJob;
|
||||
} else if (option.type === "zip") {}
|
||||
else option = {type: "zip", pathZip: undefined};
|
||||
}
|
||||
throw new Error("Invalid option");
|
||||
async function lockServerBackup() {
|
||||
if (Platform === "bedrock") {
|
||||
serverCommands.execCommand("save hold");
|
||||
await new Promise(accept => setTimeout(accept, 1000));
|
||||
serverCommands.execCommand("save query");
|
||||
await new Promise(accept => setTimeout(accept, 1000));
|
||||
}
|
||||
}
|
||||
async function unLockServerBackup() {
|
||||
if (Platform === "bedrock") {
|
||||
serverCommands.execCommand("save resume");
|
||||
await new Promise(accept => setTimeout(accept, 1000));
|
||||
}
|
||||
}
|
||||
if (!option) option = {type: "zip", pathZip: undefined};
|
||||
const CrontimeBackup = new node_cron.CronJob(crontime, async () => {
|
||||
if (option.type === "git") {
|
||||
await lockServerBackup();
|
||||
await bdsBackup.gitBackup(option.config).catch(() => undefined).then(() => unLockServerBackup());
|
||||
} else if (option.type === "zip") {
|
||||
await lockServerBackup();
|
||||
if (!!(option||{}).pathZip) await bdsBackup.CreateBackup({path: path.resolve(bdsBackup.backupFolderPath, option.pathZip)}).catch(() => undefined);
|
||||
else await bdsBackup.CreateBackup(true).catch(() => undefined);
|
||||
await unLockServerBackup();
|
||||
}
|
||||
});
|
||||
CrontimeBackup.start();
|
||||
onExit(() => CrontimeBackup.stop());
|
||||
return CrontimeBackup;
|
||||
},
|
||||
logRegister: onLog,
|
||||
onExit: onExit,
|
||||
|
Reference in New Issue
Block a user