From 9c4c2c9d057fd8fd24e0ea482db25859f8ca160f Mon Sep 17 00:00:00 2001 From: Alexander Zhirov Date: Mon, 26 May 2025 23:13:54 +0300 Subject: [PATCH] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB=D0=B5?= =?UTF-8?q?=D0=BD=D0=B0=20=D0=BA=D0=BE=D0=BC=D0=B0=D0=BD=D0=B4=D0=B0=20?= =?UTF-8?q?=D0=B8=D0=BC=D0=BF=D0=BE=D1=80=D1=82=D0=B0=20import=20=D0=B8?= =?UTF-8?q?=D0=B7=20=D0=B0=D1=80=D1=85=D0=B8=D0=B2=D0=B0=20tar.gz?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- source/app.d | 32 ++++++++++++++ source/snag/core/core.d | 95 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 127 insertions(+) diff --git a/source/app.d b/source/app.d index 55f9e4a..6633a1e 100644 --- a/source/app.d +++ b/source/app.d @@ -18,6 +18,30 @@ int main(string[] args) .add(new Command("init", "Initializing the repository for storing snapshots")) .add(new Command("status", "Checking the status of tracked files")) .add(new Command("diff", "Show changed data")) + .add(new Command("import", "Import snapshot from a tar.gz archive") + .add(new Argument("archive", "The path to the tar.gz archive file").required) + .add(new Option("c", "comment", "Specify comment") + .optional + .validateEachWith( + opt => opt.length > 0, + "cannot be empty" + ) + ) + .add(new Option("a", "author", "Specify author") + .optional + .validateEachWith( + opt => opt.length > 0, + "cannot be empty" + ) + ) + .add(new Option("e", "email", "Specify email") + .optional + .validateEachWith( + opt => opt.isValidEmail, + "must contain an email address" + ) + ) + ) .add(new Command("export", "Export snapshot to a tar.gz archive") .add(new Argument("path", "Output directory path for the archive").required) .add(new Option("s", "snapshot", "Specify snapshot hash") @@ -123,6 +147,14 @@ int main(string[] args) e.arg("path"), e.option("snapshot", ""), ) + ) + .on("import", i => + snag.importSnapshot( + i.arg("archive"), + i.option("comment", ""), + i.option("author", ""), + i.option("email", "") + ) ); } catch (SnagException e) { e.print(); diff --git a/source/snag/core/core.d b/source/snag/core/core.d index b114dd7..fe75fb1 100644 --- a/source/snag/core/core.d +++ b/source/snag/core/core.d @@ -290,4 +290,99 @@ class Snag { ); writeln("Export to archive completed successfully: ", file); } + + void importSnapshot(string path, string comment, string author, string email) { + try { + (!path.isFile || !path.endsWith("tar.gz")) && + throw new SnagException( + "Path is not an archive file" + ); + } catch (Exception e) { + throw new SnagException( + "Failed to verify the archive file:\n\t" + ~ e.msg + ); + } + + string newBranch = _date ~ "-import"; + string tempDirectory = tempDir().buildPath(newBranch); + + mkdir(tempDirectory); + + scope(exit) tempDirectory.exists + && tempDirectory.isDir + && tempDirectory.rmdirRecurse; + + auto result = execute([ + "tar", "xf", path, "-C", tempDirectory + ]); + result.status && + throw new SnagException( + "The error occurred during decompression (or unpacking) of the archive:\n\t" + ~ result.output.split('\n')[0] + ); + + // Выполнение git команд относительно распакованного архива + string[] customCommand = format( + "git --git-dir=%s --work-tree=%s", + _config.git, tempDirectory + ).split(); + + // Необходимо проверить, что текущее состояние файлов не идентично файлам распакованного архива + result = execute(customCommand ~ ["status", "--porcelain"]); + result.status && + throw new SnagException( + "An error occurred while checking the file tracking status:\n" + ~ result.output.split('\n')[0] + ); + + // Если текущее состояние файлов идентично файлам распакованного архива + !result.output.length && + throw new SnagException( + "Import aborted:\n\t" + ~ "The new state of the files is up to date as of the current snapshot" + ); + + git( + ["checkout", "--orphan", newBranch ], + "Failed to create a branch from the new state" + ); + + // Создание нового снимка на основе состояния файлов из распакованного архива + result = execute(customCommand ~ ["add", "."]); + result.status && + throw new SnagException( + "Failed to prepare files for archiving:\n" + ~ result.output.split('\n')[0] + ); + + author.length && (environment["GIT_AUTHOR_NAME"] = author); + email.length && (environment["GIT_AUTHOR_EMAIL"] = email); + + string message = comment.length ? comment : "Creating a snapshot from import"; + + result = execute(customCommand ~ ["commit", "-m"] ~ message); + result.status && + throw new SnagException( + "Failed to create a snapshot:\n" + ~ result.output.split('\n')[0] + ); + + // Сброс состояния файлов + git( + ["restore", "."], + "Failed to reset file changes state" + ); + git( + ["clean", "-fd"], + "Failed to clean untracked files" + ); + + string newSnapshot = git( + ["rev-parse", "--short", "HEAD"], + "Failed to retrieve current snapshot information" + ).output.strip('\n'); + + writeln("Import completed successfully: ", newSnapshot); + } }