Compare commits
4 commits
016455d8f2
...
f924800387
Author | SHA1 | Date | |
---|---|---|---|
f924800387 | |||
a2131ec574 | |||
5f746c33b7 | |||
9f8759238b |
6 changed files with 101 additions and 23 deletions
|
@ -4,12 +4,11 @@
|
||||||
"email": "user@site.domain",
|
"email": "user@site.domain",
|
||||||
"author": "snag",
|
"author": "snag",
|
||||||
"presnag": [
|
"presnag": [
|
||||||
"/usr/bin/ls",
|
"echo $(which ls)",
|
||||||
"/usr/local/bin/script.sh"
|
"pwd"
|
||||||
],
|
],
|
||||||
"postsnag": [
|
"postsnag": [
|
||||||
"/usr/bin/ls",
|
"/usr/bin/ls"
|
||||||
"/usr/local/bin/script.sh"
|
|
||||||
],
|
],
|
||||||
"rules": {
|
"rules": {
|
||||||
"tracking": [
|
"tracking": [
|
||||||
|
|
48
source/app.d
48
source/app.d
|
@ -63,6 +63,14 @@ int main(string[] args)
|
||||||
"must contain an email address"
|
"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 Command("export", "Export snapshot to a tar.gz archive")
|
||||||
.add(new Argument("path", "Output directory path for the archive").required)
|
.add(new Argument("path", "Output directory path for the archive").required)
|
||||||
|
@ -96,6 +104,14 @@ int main(string[] args)
|
||||||
"must contain an email address"
|
"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 Command("list", "List of snapshots")
|
||||||
.add(new Flag("c", "comment", "Show comment")
|
.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 Command("restore", "Restore to the specified snapshot state")
|
||||||
.add(new Argument("snapshot", "Specify snapshot hash").required)
|
.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")
|
.add(new Option("c", "config", "Сonfiguration file path")
|
||||||
.optional
|
.optional
|
||||||
|
@ -147,13 +171,15 @@ int main(string[] args)
|
||||||
.on("status", status =>
|
.on("status", status =>
|
||||||
snag.status()
|
snag.status()
|
||||||
)
|
)
|
||||||
.on("create", create =>
|
.on("create", (create) {
|
||||||
|
create.flag("nopre") || snag.executePreSnag();
|
||||||
snag.create(
|
snag.create(
|
||||||
create.option("comment", ""),
|
create.option("comment", ""),
|
||||||
create.option("author", ""),
|
create.option("author", ""),
|
||||||
create.option("email", "")
|
create.option("email", "")
|
||||||
)
|
);
|
||||||
)
|
create.flag("nopost") || snag.executePostSnag();
|
||||||
|
})
|
||||||
.on("list", list =>
|
.on("list", list =>
|
||||||
snag.list(
|
snag.list(
|
||||||
list.flag("comment"),
|
list.flag("comment"),
|
||||||
|
@ -161,23 +187,27 @@ int main(string[] args)
|
||||||
list.flag("email")
|
list.flag("email")
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
.on("restore", restore =>
|
.on("restore", (restore) {
|
||||||
snag.restore(restore.arg("snapshot"))
|
restore.flag("nopre") || snag.executePreSnag();
|
||||||
)
|
snag.restore(restore.arg("snapshot"));
|
||||||
|
restore.flag("nopost") || snag.executePostSnag();
|
||||||
|
})
|
||||||
.on("export", e =>
|
.on("export", e =>
|
||||||
snag.exportSnapshot(
|
snag.exportSnapshot(
|
||||||
e.arg("path"),
|
e.arg("path"),
|
||||||
e.option("snapshot", ""),
|
e.option("snapshot", ""),
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
.on("import", i =>
|
.on("import", (i) {
|
||||||
|
i.flag("nopre") || snag.executePreSnag();
|
||||||
snag.importSnapshot(
|
snag.importSnapshot(
|
||||||
i.arg("archive"),
|
i.arg("archive"),
|
||||||
i.option("comment", ""),
|
i.option("comment", ""),
|
||||||
i.option("author", ""),
|
i.option("author", ""),
|
||||||
i.option("email", "")
|
i.option("email", "")
|
||||||
)
|
);
|
||||||
)
|
i.flag("nopost") || snag.executePostSnag();
|
||||||
|
})
|
||||||
.on("rules", (r) {
|
.on("rules", (r) {
|
||||||
auto rules = new SnagRules(config);
|
auto rules = new SnagRules(config);
|
||||||
r
|
r
|
||||||
|
|
|
@ -17,6 +17,8 @@ class SnagConfig {
|
||||||
private string _author;
|
private string _author;
|
||||||
private string[] _tracking;
|
private string[] _tracking;
|
||||||
private string[] _ignore;
|
private string[] _ignore;
|
||||||
|
private string[] _presnag;
|
||||||
|
private string[] _postsnag;
|
||||||
|
|
||||||
this(string configFile) {
|
this(string configFile) {
|
||||||
string jsonText;
|
string jsonText;
|
||||||
|
@ -119,6 +121,22 @@ class SnagConfig {
|
||||||
_ignore = rules["ignore"].array.map!(item => item.str).array;
|
_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; }
|
@property string git() const { return _git; }
|
||||||
|
@ -127,4 +145,6 @@ class SnagConfig {
|
||||||
@property string author() const { return _author; }
|
@property string author() const { return _author; }
|
||||||
@property const(string[]) tracking() const { return _tracking; }
|
@property const(string[]) tracking() const { return _tracking; }
|
||||||
@property const(string[]) ignore() const { return _ignore; }
|
@property const(string[]) ignore() const { return _ignore; }
|
||||||
|
@property const(string[]) presnag() const { return _presnag; }
|
||||||
|
@property const(string[]) postsnag() const { return _postsnag; }
|
||||||
}
|
}
|
||||||
|
|
|
@ -61,6 +61,32 @@ class Snag {
|
||||||
return formatted && fullStatus.length < 8 ? fullStatus ~ "\t" : fullStatus;
|
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) {
|
void initialize(bool force) {
|
||||||
auto result = execute(_baseCommand ~ ["rev-parse", "--git-dir"]);
|
auto result = execute(_baseCommand ~ ["rev-parse", "--git-dir"]);
|
||||||
!force && !result.status &&
|
!force && !result.status &&
|
||||||
|
@ -127,13 +153,18 @@ class Snag {
|
||||||
email.length && (environment["GIT_AUTHOR_EMAIL"] = email);
|
email.length && (environment["GIT_AUTHOR_EMAIL"] = email);
|
||||||
|
|
||||||
string message = comment.length ? comment : "Standard snapshot creation";
|
string message = comment.length ? comment : "Standard snapshot creation";
|
||||||
|
string newSnapshot;
|
||||||
|
|
||||||
result = execute(_baseCommand ~ ["rev-parse", "--short", "HEAD"]);
|
result = execute(_baseCommand ~ ["rev-parse", "--short", "HEAD"]);
|
||||||
if (result.status == 128) {
|
if (result.status == 128) {
|
||||||
// Если это самый первый коммит после инициализации репозитория
|
// Если это самый первый коммит после инициализации репозитория
|
||||||
git(["add", "."], "Failed to prepare files for archiving");
|
git(["add", "."], "Failed to prepare files for archiving");
|
||||||
git(["commit", "-m"] ~ message, "Failed to create a backup");
|
git(["commit", "-m"] ~ message, "Failed to create a snapshot");
|
||||||
writeln("Backup was created successfully");
|
newSnapshot = git(
|
||||||
|
["rev-parse", "--short", "HEAD"],
|
||||||
|
"Failed to retrieve current snapshot information"
|
||||||
|
).output.strip('\n');
|
||||||
|
writeln("Snapshot was created successfully: ", newSnapshot);
|
||||||
return;
|
return;
|
||||||
} else if (result.status != 0)
|
} else if (result.status != 0)
|
||||||
throw new SnagException(
|
throw new SnagException(
|
||||||
|
@ -157,8 +188,6 @@ class Snag {
|
||||||
"Failed to get the commit list between HEAD and " ~ currentBranch
|
"Failed to get the commit list between HEAD and " ~ currentBranch
|
||||||
);
|
);
|
||||||
|
|
||||||
string newSnapshot;
|
|
||||||
|
|
||||||
// Если список существует
|
// Если список существует
|
||||||
if (result.output.length) {
|
if (result.output.length) {
|
||||||
// Если коммит не является последним, то необходимо ответвление
|
// Если коммит не является последним, то необходимо ответвление
|
||||||
|
@ -173,7 +202,7 @@ class Snag {
|
||||||
);
|
);
|
||||||
git(
|
git(
|
||||||
["commit", "-m"] ~ message,
|
["commit", "-m"] ~ message,
|
||||||
"Failed to create a backup"
|
"Failed to create a snapshot"
|
||||||
);
|
);
|
||||||
newSnapshot = git(
|
newSnapshot = git(
|
||||||
["rev-parse", "--short", "HEAD"],
|
["rev-parse", "--short", "HEAD"],
|
||||||
|
@ -187,7 +216,7 @@ class Snag {
|
||||||
);
|
);
|
||||||
git(
|
git(
|
||||||
["commit", "-m"] ~ message,
|
["commit", "-m"] ~ message,
|
||||||
"Failed to create a backup"
|
"Failed to create a snapshot"
|
||||||
);
|
);
|
||||||
newSnapshot = git(
|
newSnapshot = git(
|
||||||
["rev-parse", "--short", "HEAD"],
|
["rev-parse", "--short", "HEAD"],
|
||||||
|
@ -202,7 +231,7 @@ class Snag {
|
||||||
"Issue with including the commit into the branch " ~ currentBranch
|
"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) {
|
void list(bool comment, bool author, bool email) {
|
||||||
|
|
|
@ -86,7 +86,7 @@ class SnagRules {
|
||||||
git(
|
git(
|
||||||
["diff", "--cached", "--name-only"],
|
["diff", "--cached", "--name-only"],
|
||||||
"Failed to retrieve the list of files removed from tracking"
|
"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(
|
file => git(
|
||||||
["add", "-f", file],
|
["add", "-f", file],
|
||||||
"Failed to restore the file to tracking"
|
"Failed to restore the file to tracking"
|
||||||
|
@ -98,7 +98,7 @@ class SnagRules {
|
||||||
git(
|
git(
|
||||||
["ls-files", "-i", "-c", "--exclude-standard"],
|
["ls-files", "-i", "-c", "--exclude-standard"],
|
||||||
"Failed to get the list of files to remove from tracking"
|
"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(
|
file => git(
|
||||||
["rm", "--cached", file],
|
["rm", "--cached", file],
|
||||||
"Failed to remove file from tracking"
|
"Failed to remove file from tracking"
|
||||||
|
|
|
@ -1,3 +1,3 @@
|
||||||
module snag.version_;
|
module snag.version_;
|
||||||
|
|
||||||
enum snagVersion = "0.0.11";
|
enum snagVersion = "0.0.12";
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue