Промежуточный набросок для управления правилами

This commit is contained in:
Alexander Zhirov 2025-05-27 03:53:59 +03:00
parent db9a6be9f4
commit 573f1d7d51
Signed by: alexander
GPG key ID: C8D8BE544A27C511
6 changed files with 135 additions and 2 deletions

2
.vscode/launch.json vendored
View file

@ -11,7 +11,7 @@
"name": "Build & Debug DUB project",
"cwd": "${command:dubWorkingDirectory}",
"program": "bin/${command:dubTarget}",
"args": ["list"]
"args": ["create"]
}
]
}

View file

@ -10,5 +10,15 @@
"postsnag": [
"/usr/bin/ls",
"/usr/local/bin/script.sh"
]
],
"rules": {
"tracking": [
"/etc/systemd/*.conf",
"/usr/exit"
],
"ignore": [
"/usr/exit/.gitignore",
"/usr/exit/dd"
]
}
}

View file

@ -21,6 +21,7 @@ int main(string[] args)
.optional
)
)
.add(new Command("retracking", "Tracking rules update"))
.add(new Command("status", "Checking the status of tracked files"))
.add(new Command("diff", "Show changed data"))
.add(new Command("import", "Import snapshot from a tar.gz archive")
@ -160,6 +161,9 @@ int main(string[] args)
i.option("author", ""),
i.option("email", "")
)
)
.on("retracking", e =>
(new SnagRules(config)).create()
);
} catch (SnagException e) {
e.print();

View file

@ -5,6 +5,8 @@ import std.file;
import std.path;
import std.string;
import snag.lib;
import std.algorithm;
import std.array;
import snag.config.exception;
@ -13,6 +15,8 @@ class SnagConfig {
private string _project;
private string _email;
private string _author;
private string[] _tracking;
private string[] _ignore;
this(string configFile) {
string jsonText;
@ -93,10 +97,34 @@ class SnagConfig {
throw new SnagConfigException(
"The \"author\" parameter must contain an author name"
);
if ("rules" in jsonData) {
if (jsonData["rules"].type != JSONType.object)
throw new SnagConfigException(
"The \"rules\" parameter must be an object"
);
auto rules = jsonData["rules"];
if ("tracking" in rules) {
if (rules["tracking"].type != JSONType.array)
throw new SnagConfigException(
"The \"tracking\" parameter must be an array containing a set of paths to tracked files"
);
_tracking = rules["tracking"].array.map!(item => item.str).array;
}
if ("ignore" in rules) {
if (rules["ignore"].type != JSONType.array)
throw new SnagConfigException(
"The \"ignore\" parameter must contain a gitignore rule"
);
_ignore = rules["ignore"].array.map!(item => item.str).array;
}
}
}
@property string git() const { return _git; }
@property string project() const { return _project; }
@property string email() const { return _email; }
@property string author() const { return _author; }
@property const(string[]) tracking() const { return _tracking; }
@property const(string[]) ignore() const { return _ignore; }
}

View file

@ -2,3 +2,4 @@ module snag.core;
public import snag.core.core;
public import snag.core.exception;
public import snag.core.rules;

90
source/snag/core/rules.d Normal file
View file

@ -0,0 +1,90 @@
module snag.core.rules;
import snag.config;
import snag.core.exception;
import std.algorithm;
import std.array;
import std.path;
import std.stdio;
import std.string;
import std.conv;
import std.container;
import std.process;
class SnagRules {
private string[] _rules;
private SnagConfig _config;
private string[] _baseCommand;
private string[] generateGitignoreRules(string finalPath) {
string[] rules;
string[] parts = finalPath.split("/").filter!(p => !p.empty).array;
if (parts.length == 0) return rules;
rules ~= "/*";
rules ~= "!/" ~ parts[0];
rules ~= "/" ~ parts[0] ~ "/*";
if (parts.length > 1) {
string currentPath = "/" ~ parts[0];
foreach (i; 1 .. parts.length) {
currentPath ~= "/" ~ parts[i];
rules ~= "!" ~ currentPath;
if (i < parts.length.to!int - 1) {
rules ~= currentPath ~ "/*";
}
}
}
return rules;
}
private void generate() {
string[] rules;
auto tempRules = new RedBlackTree!string;
_config.tracking.each!(
track => rules ~= generateGitignoreRules(track)
);
rules.each!((rule) {
if (rule in tempRules) return;
tempRules.insert(rule);
_rules ~= rule;
});
_rules ~= _config.ignore;
}
this(SnagConfig config) {
_config = config;
_baseCommand = format(
"git --git-dir=%s --work-tree=%s",
config.git, config.project
).split();
}
void create() {
auto result = execute(_baseCommand ~ ["rev-parse", "--git-dir"]);
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));
}
// git ls-files -i -c --exclude-standard -z | xargs -0 git rm --cached
// git ls-files -i -c --exclude-standard
// git rm --cached <path-to-file>
}