diff --git a/snag.json b/snag.json index 0cdee67..518738f 100644 --- a/snag.json +++ b/snag.json @@ -4,12 +4,11 @@ "email": "user@site.domain", "author": "snag", "presnag": [ - "/usr/bin/ls", - "/usr/local/bin/script.sh" + "echo $(which ls)", + "pwd" ], "postsnag": [ - "/usr/bin/ls", - "/usr/local/bin/script.sh" + "/usr/bin/ls" ], "rules": { "tracking": [ diff --git a/source/app.d b/source/app.d index b15d19c..ef30132 100644 --- a/source/app.d +++ b/source/app.d @@ -63,6 +63,14 @@ int main(string[] args) "must contain an email address" ) ) + .add(new Flag(null, "no-presnag", "Execution without running pre-execution commands") + .name("nopre") + .optional + ) + .add(new Flag(null, "no-postsnag", "Execution without running post-execution commands") + .name("nopost") + .optional + ) ) .add(new Command("export", "Export snapshot to a tar.gz archive") .add(new Argument("path", "Output directory path for the archive").required) @@ -96,6 +104,14 @@ int main(string[] args) "must contain an email address" ) ) + .add(new Flag(null, "no-presnag", "Execution without running pre-execution commands") + .name("nopre") + .optional + ) + .add(new Flag(null, "no-postsnag", "Execution without running post-execution commands") + .name("nopost") + .optional + ) ) .add(new Command("list", "List of snapshots") .add(new Flag("c", "comment", "Show comment") @@ -113,6 +129,14 @@ int main(string[] args) ) .add(new Command("restore", "Restore to the specified snapshot state") .add(new Argument("snapshot", "Specify snapshot hash").required) + .add(new Flag(null, "no-presnag", "Execution without running pre-execution commands") + .name("nopre") + .optional + ) + .add(new Flag(null, "no-postsnag", "Execution without running post-execution commands") + .name("nopost") + .optional + ) ) .add(new Option("c", "config", "Сonfiguration file path") .optional @@ -147,13 +171,15 @@ int main(string[] args) .on("status", status => snag.status() ) - .on("create", create => + .on("create", (create) { + create.flag("nopre") || snag.executePreSnag(); snag.create( create.option("comment", ""), create.option("author", ""), create.option("email", "") - ) - ) + ); + create.flag("nopost") || snag.executePostSnag(); + }) .on("list", list => snag.list( list.flag("comment"), @@ -161,23 +187,27 @@ int main(string[] args) list.flag("email") ) ) - .on("restore", restore => - snag.restore(restore.arg("snapshot")) - ) + .on("restore", (restore) { + restore.flag("nopre") || snag.executePreSnag(); + snag.restore(restore.arg("snapshot")); + restore.flag("nopost") || snag.executePostSnag(); + }) .on("export", e => snag.exportSnapshot( e.arg("path"), e.option("snapshot", ""), ) ) - .on("import", i => + .on("import", (i) { + i.flag("nopre") || snag.executePreSnag(); snag.importSnapshot( i.arg("archive"), i.option("comment", ""), i.option("author", ""), i.option("email", "") - ) - ) + ); + i.flag("nopost") || snag.executePostSnag(); + }) .on("rules", (r) { auto rules = new SnagRules(config); r diff --git a/source/snag/config/config.d b/source/snag/config/config.d index 635cc6d..e9e0ca2 100644 --- a/source/snag/config/config.d +++ b/source/snag/config/config.d @@ -17,6 +17,8 @@ class SnagConfig { private string _author; private string[] _tracking; private string[] _ignore; + private string[] _presnag; + private string[] _postsnag; this(string configFile) { string jsonText; @@ -119,6 +121,22 @@ class SnagConfig { _ignore = rules["ignore"].array.map!(item => item.str).array; } } + + if ("presnag" in jsonData) { + if (jsonData["presnag"].type != JSONType.array) + throw new SnagConfigException( + "The \"presnag\" parameter must be an array containing a set of commands" + ); + _presnag = jsonData["presnag"].array.map!(item => item.str).array; + } + + if ("postsnag" in jsonData) { + if (jsonData["postsnag"].type != JSONType.array) + throw new SnagConfigException( + "The \"postsnag\" parameter must be an array containing a set of commands" + ); + _postsnag = jsonData["postsnag"].array.map!(item => item.str).array; + } } @property string git() const { return _git; } @@ -127,4 +145,6 @@ class SnagConfig { @property string author() const { return _author; } @property const(string[]) tracking() const { return _tracking; } @property const(string[]) ignore() const { return _ignore; } + @property const(string[]) presnag() const { return _presnag; } + @property const(string[]) postsnag() const { return _postsnag; } } diff --git a/source/snag/core/core.d b/source/snag/core/core.d index ef51792..7b05b61 100644 --- a/source/snag/core/core.d +++ b/source/snag/core/core.d @@ -61,6 +61,32 @@ class Snag { return formatted && fullStatus.length < 8 ? fullStatus ~ "\t" : fullStatus; } + void executePreSnag() { + _config.presnag().each!((command) { + auto result = executeShell(command); + result.status && throw new SnagException( + "%s:\n\t%s\n\n%s".format( + "An error occurred during presnag-command execution", + command, + result.output + ) + ); + }); + } + + void executePostSnag() { + _config.postsnag().each!((command) { + auto result = executeShell(command); + result.status && throw new SnagException( + "%s:\n\t%s\n\n%s".format( + "An error occurred during postsnag-command execution", + command, + result.output + ) + ); + }); + } + void initialize(bool force) { auto result = execute(_baseCommand ~ ["rev-parse", "--git-dir"]); !force && !result.status && @@ -127,13 +153,18 @@ class Snag { email.length && (environment["GIT_AUTHOR_EMAIL"] = email); string message = comment.length ? comment : "Standard snapshot creation"; + string newSnapshot; result = execute(_baseCommand ~ ["rev-parse", "--short", "HEAD"]); if (result.status == 128) { // Если это самый первый коммит после инициализации репозитория git(["add", "."], "Failed to prepare files for archiving"); - git(["commit", "-m"] ~ message, "Failed to create a backup"); - writeln("Backup was created successfully"); + git(["commit", "-m"] ~ message, "Failed to create a snapshot"); + newSnapshot = git( + ["rev-parse", "--short", "HEAD"], + "Failed to retrieve current snapshot information" + ).output.strip('\n'); + writeln("Snapshot was created successfully: ", newSnapshot); return; } else if (result.status != 0) throw new SnagException( @@ -157,8 +188,6 @@ class Snag { "Failed to get the commit list between HEAD and " ~ currentBranch ); - string newSnapshot; - // Если список существует if (result.output.length) { // Если коммит не является последним, то необходимо ответвление @@ -173,7 +202,7 @@ class Snag { ); git( ["commit", "-m"] ~ message, - "Failed to create a backup" + "Failed to create a snapshot" ); newSnapshot = git( ["rev-parse", "--short", "HEAD"], @@ -187,7 +216,7 @@ class Snag { ); git( ["commit", "-m"] ~ message, - "Failed to create a backup" + "Failed to create a snapshot" ); newSnapshot = git( ["rev-parse", "--short", "HEAD"], @@ -202,7 +231,7 @@ class Snag { "Issue with including the commit into the branch " ~ currentBranch ); } - writeln("Backup was created successfully: ", newSnapshot); + writeln("Snapshot was created successfully: ", newSnapshot); } void list(bool comment, bool author, bool email) { diff --git a/source/snag/core/rules.d b/source/snag/core/rules.d index ef585bd..d8a2c9c 100644 --- a/source/snag/core/rules.d +++ b/source/snag/core/rules.d @@ -86,7 +86,7 @@ class SnagRules { git( ["diff", "--cached", "--name-only"], "Failed to retrieve the list of files removed from tracking" - ).output.split('\n')[0..$-1].each!( + ).output.split('\n').filter!(e => !e.strip.empty).each!( file => git( ["add", "-f", file], "Failed to restore the file to tracking" @@ -98,7 +98,7 @@ class SnagRules { git( ["ls-files", "-i", "-c", "--exclude-standard"], "Failed to get the list of files to remove from tracking" - ).output.split('\n')[0..$-1].each!( + ).output.split('\n').filter!(e => !e.strip.empty).each!( file => git( ["rm", "--cached", file], "Failed to remove file from tracking" diff --git a/source/snag/version_.d b/source/snag/version_.d index 2c89ac7..b3c91c4 100644 --- a/source/snag/version_.d +++ b/source/snag/version_.d @@ -1,3 +1,3 @@ module snag.version_; -enum snagVersion = "0.0.11"; +enum snagVersion = "0.0.12";