diff --git a/source/snag/core/core.d b/source/snag/core/core.d index 06aad49..b09fb89 100644 --- a/source/snag/core/core.d +++ b/source/snag/core/core.d @@ -7,6 +7,7 @@ import std.array; import std.process; import std.algorithm; import std.string; +import std.regex; import snag.core.exception; @@ -14,6 +15,11 @@ class Snag { private string[] _baseCommand; private SnagConfig _config; + private bool isValidHash(string hash) { + auto hashPattern = ctRegex!r"^[a-fA-F0-9]{7}$"; + return !matchFirst(hash, hashPattern).empty; + } + this(SnagConfig config) { _baseCommand = format( "git --git-dir=%s --work-tree=%s", @@ -67,9 +73,9 @@ class Snag { writeln("The following list of files requires backup:"); /** - Цепочка выполняет разбивку по переводу на новую строку, - отсеивает пустые строки, перебирает в цикле имеющиеся строки, - выводит только вторую часть строки (разделенную по пробелу) + * Цепочка выполняет разбивку по переводу на новую строку, + * отсеивает пустые строки, перебирает в цикле имеющиеся строки, + * выводит только вторую часть строки (разделенную по пробелу) */ result.output.split('\n').filter!(e => !e.strip.empty).each!((e) { writefln("\t/%s", e.strip.split[1]); @@ -77,7 +83,45 @@ class Snag { } void create() { + /** + * Проверка файлов на состояние изменения + */ auto result = execute( + _baseCommand ~ ["status", "--porcelain"] + ); + if (result.status) + throw new SnagException( + "An error occurred while checking the file tracking status:\n" + ~ result.output + ); + if (!result.output.length) + throw new SnagException( + "Current file state doesn't need to be archived again" + ); + + result = execute( + _baseCommand ~ [ + "rev-parse", "--short", "HEAD" + ] + ); + if (result.status) + throw new SnagException( + "Failed to retrieve current snapshot information:\n" + ~ result.output + ); + + string currentSnapshot = result.output.strip('\n'); + + result = execute( + _baseCommand ~ [ + "checkout", + "-b", + "mod", + currentSnapshot + ] + ); + + result = execute( _baseCommand ~ ["add", "."] ); if (result.status) @@ -95,6 +139,136 @@ class Snag { ~ result.output ); + result = execute( + _baseCommand ~ ["checkout", "master"] + ); + if (result.status) + throw new SnagException( + "Failed to perform intermediate state switching:\n" + ~ result.output + ); + + result = execute( + _baseCommand ~ [ + "merge", + "-X", + "theirs", + "--squash", + "mod" + ] + ); + if (result.status) + throw new SnagException( + "Failed to retrieve changes from the new intermediate snapshot:\n" + ~ result.output + ); + + result = execute( + _baseCommand ~ ["commit", "-m", "test"] + ); + if (result.status) + throw new SnagException( + "Failed to create backup after acquiring new intermediate snapshot:\n" + ~ result.output + ); + + result = execute( + _baseCommand ~ ["branch", "-D", "mod"] + ); + if (result.status) + throw new SnagException( + "Error while deleting temporary intermediate snapshot:\n" + ~ result.output + ); + writeln("Backup was created successfully"); } + + void list() { + auto result = execute( + _baseCommand ~ [ + "rev-parse", "--short", "HEAD" + ] + ); + if (result.status) + throw new SnagException( + "Failed to retrieve current snapshot information:\n" + ~ result.output + ); + + string current = result.output.strip('\n'); + + result = execute( + _baseCommand ~ [ + "log", + "--all", + "--date=format:%Y.%m.%d %H:%M", + "--pretty=format:%ad\t%h" + ] + ); + if (result.status) + throw new SnagException( + "Failed to retrieve the list of snapshots:\n" + ~ result.output + ); + + result.output.split('\n').each!((e) { + auto eArray = e.split('\t'); + if (current == eArray[1]) + writefln(" >\t%s\t%s", eArray[0], eArray[1]); + else + writefln("\t%s\t%s", eArray[0], eArray[1]); + }); + } + + void restore(string hash) { + if (!isValidHash(hash)) + throw new SnagException( + "Invalid snapshot hash provided" + ); + + auto result = execute( + _baseCommand ~ ["status", "--porcelain"] + ); + if (result.status) + throw new SnagException( + "An error occurred while checking the file tracking status:\n" + ~ result.output + ); + + if (result.output.length) { + result = execute( + _baseCommand ~ ["restore", "."] + ); + if (result.status) + throw new SnagException( + "Failed to reset file changes state:\n" + ~ result.output + ); + } + + result = execute( + _baseCommand ~ [ + "rev-parse", hash + ] + ); + if (result.status) + throw new SnagException( + "This snapshot is not available in the archive:\n" + ~ result.output.split('\n')[0] + ); + + result = execute( + _baseCommand ~ [ + "checkout", hash + ] + ); + if (result.status) + throw new SnagException( + "Failed to restore the snapshot state %s:\n" + .format(hash, result.output) + ); + + writeln("Backup was restored successfully"); + } }