Допилено

This commit is contained in:
Alexander Zhirov 2025-05-28 00:05:00 +03:00
parent 573f1d7d51
commit bb58bfe030
Signed by: alexander
GPG key ID: C8D8BE544A27C511
4 changed files with 154 additions and 25 deletions

View file

@ -13,12 +13,12 @@
], ],
"rules": { "rules": {
"tracking": [ "tracking": [
"/etc/systemd/*.conf", "/etc/*.conf"
"/usr/exit"
], ],
"ignore": [ "ignore": [
"/usr/exit/.gitignore", "/usr/exit/.gitignore",
"/usr/exit/dd" "/usr/exit/dd",
"/file1"
] ]
} }
} }

View file

@ -21,7 +21,23 @@ int main(string[] args)
.optional .optional
) )
) )
.add(new Command("retracking", "Tracking rules update")) .add(new Command("rules", "Tracking rules")
.add(new Command("update", "Update rules")
.add(new Flag("r", "remove", "Removing from tracking the found ignored files")
.name("remove")
.optional
)
)
.add(new Command("reset", "Reset rules (restores rules to pre-change state)"))
.add(new Command("clear", "Clear rules"))
.add(new Command("save", "Save rules"))
.add(new Command("show", "Show rules")
.add(new Flag("c", "config", "Show rules from the configuration file")
.name("config")
.optional
)
)
)
.add(new Command("status", "Checking the status of tracked files")) .add(new Command("status", "Checking the status of tracked files"))
.add(new Command("diff", "Show changed data")) .add(new Command("diff", "Show changed data"))
.add(new Command("import", "Import snapshot from a tar.gz archive") .add(new Command("import", "Import snapshot from a tar.gz archive")
@ -162,8 +178,25 @@ int main(string[] args)
i.option("email", "") i.option("email", "")
) )
) )
.on("retracking", e => .on("rules", (r) {
(new SnagRules(config)).create() auto rules = new SnagRules(config);
r
.on("update", update =>
rules.update(update.flag("remove"))
)
.on("reset", reset =>
rules.reset()
)
.on("clear", clear =>
rules.clear()
)
.on("save", clear =>
rules.save()
)
.on("show", show =>
rules.show(show.flag("config"))
);
}
); );
} catch (SnagException e) { } catch (SnagException e) {
e.print(); e.print();

View file

@ -13,6 +13,7 @@ import std.path;
import snag.lib; import snag.lib;
import snag.core.exception; import snag.core.exception;
import snag.core.rules;
class Snag { class Snag {
private string[] _baseCommand; private string[] _baseCommand;
@ -44,6 +45,22 @@ class Snag {
return result; return result;
} }
private string gitStatus(string shortStatus, bool formatted = false) {
immutable string[string] statusMap = [
"??": "Untracked",
"A": "Added",
"M": "Modified",
"D": "Deleted",
"R": "Renamed",
"C": "Copied",
"U": "Unmerged",
"T": "Type changed",
"!": "Ignored"
];
string fullStatus = statusMap.get(shortStatus, shortStatus);
return formatted && fullStatus.length < 8 ? fullStatus ~ "\t" : fullStatus;
}
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 &&
@ -68,6 +85,9 @@ class Snag {
["config", "user.name", _config.author], ["config", "user.name", _config.author],
"A Git repository initialization error occurred" "A Git repository initialization error occurred"
); );
(new SnagRules(_config)).create();
writeln( writeln(
"The Git repository has been initialized successfully: ", "The Git repository has been initialized successfully: ",
_config.git _config.git
@ -84,9 +104,11 @@ class Snag {
return; return;
} }
writeln("The following list of files requires backup:"); writeln("The following list of files requires backup:");
result.output.split('\n').filter!(e => !e.strip.empty).each!((e) { result.output.split('\n')[0..$-1].map!(e =>
writefln("\t/%s", e.strip.split[1]); e.strip.split
}); ).each!(e =>
writefln("\t%s\t/%s", gitStatus(e[0], true), e[1])
);
} }
void create(string comment, string author, string email) { void create(string comment, string author, string email) {

View file

@ -10,11 +10,23 @@ import std.string;
import std.conv; import std.conv;
import std.container; import std.container;
import std.process; import std.process;
import std.file;
class SnagRules { class SnagRules {
private string[] _rules; private string[] _rules;
private SnagConfig _config; private SnagConfig _config;
private string[] _baseCommand; private string[] _baseCommand;
private string _gitignore;
private string _gitignoreBak;
private auto git(string[] command, string message, string separator = ":\n\t") {
auto result = execute(_baseCommand ~ command);
if (result.status)
throw new SnagException(
message ~ separator ~ result.output.split('\n')[0]
);
return result;
}
private string[] generateGitignoreRules(string finalPath) { private string[] generateGitignoreRules(string finalPath) {
string[] rules; string[] rules;
@ -59,32 +71,94 @@ class SnagRules {
this(SnagConfig config) { this(SnagConfig config) {
_config = config; _config = config;
_gitignore = config.git.buildPath("info/exclude");
_gitignoreBak = _gitignore ~ ".bak";
_baseCommand = format( _baseCommand = format(
"git --git-dir=%s --work-tree=%s", "git --git-dir=%s --work-tree=%s",
config.git, config.project config.git, config.project
).split(); ).split();
generate();
}
private void restoreUntracked() {
git(
["diff", "--cached", "--name-only"],
"Failed to retrieve the list of files removed from tracking"
).output.split('\n')[0..$-1].each!(
file => git(
["add", "-f", file],
"Failed to restore the file to tracking"
)
);
}
private void removeUntracked() {
git(
["ls-files", "-i", "-c", "--exclude-standard"],
"Failed to get the list of files to remove from tracking"
).output.split('\n')[0..$-1].each!(
file => git(
["rm", "--cached", file],
"Failed to remove file from tracking"
)
);
} }
void create() { void create() {
auto result = execute(_baseCommand ~ ["rev-parse", "--git-dir"]); auto file = File(_gitignore, "w");
result.status &&
throw new SnagException(
"A problem occurred while checking the repository: "
~ result.output.strip('\n')
);
generate();
string gitignore = _config.git.buildPath("info/exclude");
File file = File(gitignore, "w");
_rules.each!(rule => file.writeln(rule)); _rules.each!(rule => file.writeln(rule));
file.close();
} }
// git ls-files -i -c --exclude-standard -z | xargs -0 git rm --cached void update(bool remove) {
if (!_gitignoreBak.exists) {
readText(_gitignore).splitLines().equal(_rules) &&
throw new SnagException(
"Rule configuration is up-to-date and doesn't require updating"
);
copy(_gitignore, _gitignoreBak);
}
// git ls-files -i -c --exclude-standard restoreUntracked();
// git rm --cached <path-to-file> create();
remove && removeUntracked();
}
void reset() {
!_gitignoreBak.exists &&
throw new SnagException(
"No rule changes to reset"
);
restoreUntracked();
rename(_gitignoreBak, _gitignore);
}
void clear() {
!readText(_gitignore).splitLines().length &&
throw new SnagException(
"The configuration has no rules"
);
!_gitignoreBak.exists && copy(_gitignore, _gitignoreBak);
restoreUntracked();
File(_gitignore, "w").close();
}
void show(bool config) {
if (config)
_rules.join('\n').writeln;
else
readText(_gitignore).write;
}
void save() {
if (!_gitignoreBak.exists) {
writeln("The rules are up to date");
return;
}
remove(_gitignoreBak);
writeln("The rules have been saved");
}
} }