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); + } }