Добавлен новый модуль rules для управления правилами отслеживания файлов в виде записей для gitignore
- create: создание правил из конфигурационного файла: - tracking - отслеживаемые файлы/пути - ignore - правила gitignore - update: обновление существующих правил из конфигурационного файла - reset: сброс изменений в правилах - откат на момент до внесения изменений в конфигурационный файл - clear: очистить файл с правилами - show: просмотр правил - save: сохранить правила без возможности сброса (reset)
This commit is contained in:
parent
db9a6be9f4
commit
5797e83f07
2 changed files with 165 additions and 0 deletions
|
@ -2,3 +2,4 @@ module snag.core;
|
|||
|
||||
public import snag.core.core;
|
||||
public import snag.core.exception;
|
||||
public import snag.core.rules;
|
||||
|
|
164
source/snag/core/rules.d
Normal file
164
source/snag/core/rules.d
Normal file
|
@ -0,0 +1,164 @@
|
|||
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;
|
||||
import std.file;
|
||||
|
||||
class SnagRules {
|
||||
private string[] _rules;
|
||||
private SnagConfig _config;
|
||||
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) {
|
||||
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;
|
||||
_gitignore = config.git.buildPath("info/exclude");
|
||||
_gitignoreBak = _gitignore ~ ".bak";
|
||||
|
||||
_baseCommand = format(
|
||||
"git --git-dir=%s --work-tree=%s",
|
||||
config.git, config.project
|
||||
).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() {
|
||||
auto file = File(_gitignore, "w");
|
||||
_rules.each!(rule => file.writeln(rule));
|
||||
file.close();
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
restoreUntracked();
|
||||
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");
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue