From 44f8a2207d9b24426fc9a87f39aced6a7658597a Mon Sep 17 00:00:00 2001 From: Alexander Zhirov Date: Sun, 25 May 2025 03:32:47 +0300 Subject: [PATCH] =?UTF-8?q?=D0=A2=D0=B5=D0=BF=D0=B5=D1=80=D1=8C=20=D0=BA?= =?UTF-8?q?=D0=BE=D0=BC=D0=BC=D0=B8=D1=82=D1=8B=20=D1=81=D0=BE=D0=B7=D0=B4?= =?UTF-8?q?=D0=B0=D1=8E=D1=82=D1=81=D1=8F=20=D0=BA=D0=BE=D1=80=D1=80=D0=B5?= =?UTF-8?q?=D0=BA=D1=82=D0=BD=D0=BE,=20=D0=BD=D0=B5=20=D0=BF=D0=B5=D1=80?= =?UTF-8?q?=D0=B5=D0=BA=D1=80=D1=8B=D0=B2=D0=B0=D1=8E=D1=82=20=D1=81=D0=BE?= =?UTF-8?q?=D1=81=D1=82=D0=BE=D1=8F=D0=BD=D0=B8=D1=8F=20=D1=84=D0=B0=D0=B9?= =?UTF-8?q?=D0=BB=D0=BE=D0=B2=20=D0=B4=D1=80=D1=83=D0=B3=20=D0=B4=D1=80?= =?UTF-8?q?=D1=83=D0=B3=D0=B0.=20=D0=9F=D1=80=D0=B8=20=D1=81=D0=BE=D0=B7?= =?UTF-8?q?=D0=B4=D0=B0=D0=BD=D0=B8=D0=B8=20=D0=BA=D0=BE=D0=BC=D0=BC=D0=B8?= =?UTF-8?q?=D1=82=D0=BE=D0=B2=20=D0=BF=D1=80=D0=BE=D0=B8=D1=81=D1=85=D0=BE?= =?UTF-8?q?=D0=B4=D0=B8=D1=82=20=D0=BF=D1=80=D0=BE=D0=B2=D0=B5=D1=80=D0=BA?= =?UTF-8?q?=D0=B0=20=D0=BD=D0=B0=20=D0=BD=D0=B0=D0=BB=D0=B8=D1=87=D0=B8?= =?UTF-8?q?=D0=B5=20=D0=BF=D0=BE=D1=81=D0=BB=D0=B5=D0=B4=D0=BD=D0=B5=D0=B3?= =?UTF-8?q?=D0=BE=20=D0=BA=D0=BE=D0=BC=D0=BC=D0=B8=D1=82=D0=B0=20=D0=B2=20?= =?UTF-8?q?=D0=B2=D0=B5=D1=82=D0=BA=D0=B5=20=D0=B8,=20=D0=B5=D1=81=D0=BB?= =?UTF-8?q?=D0=B8=20=D0=BA=D0=BE=D0=BC=D0=BC=D0=B8=D1=82=20=D0=BD=D0=B5=20?= =?UTF-8?q?=D1=8F=D0=B2=D0=BB=D1=8F=D0=B5=D1=82=D1=81=D1=8F=20=D0=BF=D0=BE?= =?UTF-8?q?=D1=81=D0=BB=D0=B5=D0=B4=D0=BD=D0=B8=D0=BC=20-=20=D1=82=D0=BE?= =?UTF-8?q?=20=D0=BF=D1=80=D0=BE=D0=B8=D1=81=D1=85=D0=BE=D0=B4=D0=B8=D1=82?= =?UTF-8?q?=20=D0=BE=D1=82=D0=B2=D0=B5=D1=82=D0=B2=D0=BB=D0=B5=D0=BD=D0=B8?= =?UTF-8?q?=D0=B5=20"=D1=82=D0=B5=D0=BA=D1=83=D1=89=D0=B0=D1=8F=20=D0=B4?= =?UTF-8?q?=D0=B0=D1=82=D0=B0"=20+=20"=D1=82=D0=B5=D0=BA=D1=83=D1=89=D0=B8?= =?UTF-8?q?=D0=B9=20=D0=BA=D0=BE=D0=BC=D0=BC=D0=B8=D1=82".=20=D0=9D=D0=B5?= =?UTF-8?q?=D0=B1=D0=BE=D0=BB=D1=8C=D1=88=D0=BE=D0=B9=20=D1=80=D0=B5=D1=84?= =?UTF-8?q?=D0=B0=D0=BA=D1=82=D0=BE=D1=80=D0=B8=D0=BD=D0=B3.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- source/snag/core/core.d | 126 +++++++++++++++++++++++++--------------- 1 file changed, 80 insertions(+), 46 deletions(-) diff --git a/source/snag/core/core.d b/source/snag/core/core.d index c283cc8..61f561c 100644 --- a/source/snag/core/core.d +++ b/source/snag/core/core.d @@ -2,6 +2,7 @@ module snag.core.core; import snag.config; import std.format; +import std.datetime : Clock; import std.stdio; import std.array; import std.process; @@ -14,6 +15,7 @@ import snag.core.exception; class Snag { private string[] _baseCommand; private SnagConfig _config; + private string _date; private bool isValidHash(string hash) { auto hashPattern = ctRegex!r"^[a-fA-F0-9]{7}$"; @@ -26,6 +28,15 @@ class Snag { config.git, config.project ).split(); _config = config; + + auto currentTime = Clock.currTime(); + + _date = format("%02d%03d%02d%02d%02d", + currentTime.year % 100, + currentTime.dayOfYear, + currentTime.hour, + currentTime.minute, + currentTime.second); } private auto git(string[] command, string message, string separator = ":\n") { @@ -51,8 +62,8 @@ class Snag { "A Git repository initialization error occurred" ); writeln( - "The Git repository has been initialized successfully: " - ~ _config.git + "The Git repository has been initialized successfully: ", + _config.git ); } @@ -62,8 +73,12 @@ class Snag { "An error occurred while checking the file tracking status" ); - writeln("The following list of files requires backup:"); + if (!result.output.length) { + writeln("The current state of the files is up to date as of the latest snapshot"); + return; + } + 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]); }); @@ -75,6 +90,7 @@ class Snag { "An error occurred while checking the file tracking status" ); + // Если нечего коммитить, то выходим if (!result.output.length) throw new SnagException( "Current file state doesn't need to be archived again" @@ -82,6 +98,7 @@ class Snag { result = execute(_baseCommand ~ ["rev-parse", "--short", "HEAD"]); if (result.status == 128) { + // Если это самый первый коммит после инициализации репозитория git(["add", "."], "Failed to prepare files for archiving"); git(["commit", "-m", "test"], "Failed to create a backup"); writeln("Backup was created successfully"); @@ -92,56 +109,76 @@ class Snag { ~ result.output ); + // Текущий коммит, который был изменен string currentSnapshot = result.output.strip('\n'); - git( - ["checkout", "-b", "mod", currentSnapshot ], - "Failed to create a branch from the current state" - ); - git( - ["add", "."], - "Failed to prepare files for archiving" - ); - git( - ["commit", "-m", "test"], - "Failed to create a backup" - ); - git( - ["checkout", "master"], - "Failed to perform intermediate state switching" - ); - git( - ["rebase", "--onto", "mod", currentSnapshot, "master", "-X", "theirs"], - "Ошибка при rebase" - ); + // Если текущий измененный коммит является последним в ветке - то продолжить коммиты в этой ветке + string currentBranch = git( + ["for-each-ref", "--contains", currentSnapshot, "--format='%(refname:short)'"], + "Error while getting the current branch" + ).output.split('\n')[0].strip('\''); + // Получение списка коммитов между текущим и веткой result = git( - ["rev-parse", "--short", "mod"], - "An error occurred while checking the file tracking status" + ["log", "--oneline", "HEAD.." ~ currentBranch], + "Failed to get the commit list between HEAD and " ~ currentBranch ); - string newSnapshot = result.output.strip('\n'); + string newSnapshot; - git( - ["checkout", newSnapshot], - "Failed to perform intermediate state switching" - ); - git( - ["branch", "-D", "mod"], - "Error while deleting temporary intermediate snapshot" - ); - writeln("Backup was created successfully"); + // Если список существует + if (result.output.length) { + // Если коммит не является последним, то необходимо ответвление + string newBranch = "%s-%s".format(_date, currentSnapshot); + git( + ["checkout", "-b", newBranch, currentSnapshot ], + "Failed to create a branch from the current state" + ); + git( + ["add", "."], + "Failed to prepare files for archiving" + ); + git( + ["commit", "-m", "test"], + "Failed to create a backup" + ); + newSnapshot = git( + ["rev-parse", "--short", "HEAD"], + "Failed to retrieve current snapshot information" + ).output.strip('\n'); + } else { + // Если коммит является посленим в ветке + git( + ["add", "."], + "Failed to prepare files for archiving" + ); + git( + ["commit", "-m", "test"], + "Failed to create a backup" + ); + newSnapshot = git( + ["rev-parse", "--short", "HEAD"], + "Failed to retrieve current snapshot information" + ).output.strip('\n'); + git( + ["checkout", currentBranch], + "Failed to perform intermediate state switching" + ); + git( + ["merge", newSnapshot], + "Issue with including the commit into the branch " ~ currentBranch + ); + } + writeln("Backup was created successfully: ", newSnapshot); } void list() { - auto result = git( + string currentSnapshot = git( ["rev-parse", "--short", "HEAD"], "Failed to retrieve current snapshot information" - ); + ).output.strip('\n'); - string current = result.output.strip('\n'); - - result = git( + git( [ "log", "--all", @@ -149,11 +186,8 @@ class Snag { "--pretty=format:%ad\t%h" ], "Failed to retrieve the list of snapshots" - ); - - result.output.split('\n').map!(line => line.split('\t')).array - .sort!((a, b) => a[0] > b[0]).each!(e => - writefln("%s\t%s\t%s", current == e[1] ? " >" : "", e[0], e[1]) + ).output.split('\n').map!(line => line.split('\t')).array.each!(e => + writefln("%s\t%s\t%s", currentSnapshot == e[1] ? " >" : "", e[0], e[1]) ); } @@ -182,6 +216,6 @@ class Snag { ["checkout", hash], "Failed to restore the snapshot state " ~ hash ); - writeln("Backup was restored successfully"); + writeln("Backup was restored successfully: ", hash); } }