Добавлена новая команда diff для просмотра внесенных изменений на текущий момент.
Добавлена возможность установки комментария, имени автора, электронной почты при создании снимка. Функции проверок через регулярные выражения перенесены в новый модуль lib.
This commit is contained in:
		
							parent
							
								
									eff4fa2fe6
								
							
						
					
					
						commit
						4301c27ca9
					
				
					 8 changed files with 90 additions and 36 deletions
				
			
		| 
						 | 
				
			
			@ -2,7 +2,7 @@
 | 
			
		|||
	"git": "/tmp/testgit",
 | 
			
		||||
	"project": "/tmp/test",
 | 
			
		||||
	"email": "user@site.domain",
 | 
			
		||||
	"user": "snag",
 | 
			
		||||
	"author": "snag",
 | 
			
		||||
	"presnag": [
 | 
			
		||||
		"/usr/bin/ls",
 | 
			
		||||
		"/usr/local/bin/script.sh"
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										44
									
								
								source/app.d
									
										
									
									
									
								
							
							
						
						
									
										44
									
								
								source/app.d
									
										
									
									
									
								
							| 
						 | 
				
			
			@ -11,14 +11,37 @@ int main(string[] args)
 | 
			
		|||
	auto argumets = new Program(programName, snagVersion)
 | 
			
		||||
		.add(new Command("init", "Initializing the repository for storing snapshots"))
 | 
			
		||||
		.add(new Command("status", "Checking the status of tracked files"))
 | 
			
		||||
		.add(new Command("create", "Create a new backup"))
 | 
			
		||||
		.add(new Command("list", "List of backups")
 | 
			
		||||
		.add(new Command("diff", "Show changed data"))
 | 
			
		||||
		.add(new Command("create", "Create a new snapshot")
 | 
			
		||||
			.add(new Option("c", "comment", "Specify comment")
 | 
			
		||||
				.optional
 | 
			
		||||
				.validateEachWith(
 | 
			
		||||
					opt => opt.length > 0,
 | 
			
		||||
					"cannot be empty"
 | 
			
		||||
				)
 | 
			
		||||
			)
 | 
			
		||||
			.add(new Option("a", "author", "Specify author")
 | 
			
		||||
				.optional
 | 
			
		||||
				.validateEachWith(
 | 
			
		||||
					opt => opt.length > 0,
 | 
			
		||||
					"cannot be empty"
 | 
			
		||||
				)
 | 
			
		||||
			)
 | 
			
		||||
			.add(new Option("e", "email", "Specify email")
 | 
			
		||||
				.optional
 | 
			
		||||
				.validateEachWith(
 | 
			
		||||
					opt => opt.isValidEmail,
 | 
			
		||||
					"must contain an email address"
 | 
			
		||||
				)
 | 
			
		||||
			)
 | 
			
		||||
		)
 | 
			
		||||
		.add(new Command("list", "List of snapshots")
 | 
			
		||||
			.add(new Flag("c", "comment", "Show comment")
 | 
			
		||||
				.name("comment")
 | 
			
		||||
				.optional
 | 
			
		||||
			)
 | 
			
		||||
			.add(new Flag("u", "user", "Show user")
 | 
			
		||||
				.name("user")
 | 
			
		||||
			.add(new Flag("a", "author", "Show author")
 | 
			
		||||
				.name("author")
 | 
			
		||||
				.optional
 | 
			
		||||
			)
 | 
			
		||||
			.add(new Flag("e", "email", "Show email")
 | 
			
		||||
| 
						 | 
				
			
			@ -33,7 +56,7 @@ int main(string[] args)
 | 
			
		|||
			.optional
 | 
			
		||||
			.validateEachWith(
 | 
			
		||||
				opt => opt.exists && opt.isFile,
 | 
			
		||||
				"A JSON file path must be provided"
 | 
			
		||||
				"must specify the path to the JSON file"
 | 
			
		||||
			)
 | 
			
		||||
		)
 | 
			
		||||
		.parse(args);
 | 
			
		||||
| 
						 | 
				
			
			@ -56,16 +79,23 @@ int main(string[] args)
 | 
			
		|||
			.on("init", init =>
 | 
			
		||||
				snag.initialize()
 | 
			
		||||
			)
 | 
			
		||||
			.on("diff", diff =>
 | 
			
		||||
				snag.diff()
 | 
			
		||||
			)
 | 
			
		||||
			.on("status", status =>
 | 
			
		||||
				snag.status()
 | 
			
		||||
			)
 | 
			
		||||
			.on("create", create =>
 | 
			
		||||
				snag.create()
 | 
			
		||||
				snag.create(
 | 
			
		||||
					create.option("comment", ""),
 | 
			
		||||
					create.option("author", ""),
 | 
			
		||||
					create.option("email", "")
 | 
			
		||||
				)
 | 
			
		||||
			)
 | 
			
		||||
			.on("list", list =>
 | 
			
		||||
				snag.list(
 | 
			
		||||
					list.flag("comment"),
 | 
			
		||||
					list.flag("user"),
 | 
			
		||||
					list.flag("author"),
 | 
			
		||||
					list.flag("email")
 | 
			
		||||
				)
 | 
			
		||||
			)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -3,8 +3,8 @@ module snag.config.config;
 | 
			
		|||
import std.json;
 | 
			
		||||
import std.file;
 | 
			
		||||
import std.path;
 | 
			
		||||
import std.regex;
 | 
			
		||||
import std.string;
 | 
			
		||||
import snag.lib;
 | 
			
		||||
 | 
			
		||||
import snag.config.exception;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -12,12 +12,7 @@ class SnagConfig {
 | 
			
		|||
	private string _git;
 | 
			
		||||
	private string _project;
 | 
			
		||||
	private string _email;
 | 
			
		||||
	private string _user;
 | 
			
		||||
 | 
			
		||||
	private bool isValidEmail(string email) {
 | 
			
		||||
		auto emailPattern = ctRegex!r"^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$";
 | 
			
		||||
		return !matchFirst(email, emailPattern).empty;
 | 
			
		||||
	}
 | 
			
		||||
	private string _author;
 | 
			
		||||
 | 
			
		||||
	this(string configFile) {
 | 
			
		||||
		string jsonText;
 | 
			
		||||
| 
						 | 
				
			
			@ -87,21 +82,21 @@ class SnagConfig {
 | 
			
		|||
				~ _email
 | 
			
		||||
			);
 | 
			
		||||
		
 | 
			
		||||
		if ("user" !in jsonData)
 | 
			
		||||
		if ("author" !in jsonData)
 | 
			
		||||
			throw new SnagConfigException(
 | 
			
		||||
				"The configuration file is missing the \"user\" parameter"
 | 
			
		||||
				"The configuration file is missing the \"author\" parameter"
 | 
			
		||||
			);
 | 
			
		||||
 | 
			
		||||
		_user = jsonData["user"].str;
 | 
			
		||||
		_author = jsonData["author"].str;
 | 
			
		||||
 | 
			
		||||
		if (!_user.length)
 | 
			
		||||
		if (!_author.length)
 | 
			
		||||
			throw new SnagConfigException(
 | 
			
		||||
				"The \"user\" parameter must contain an user name"
 | 
			
		||||
				"The \"author\" parameter must contain an author name"
 | 
			
		||||
			);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	@property string git() const { return _git; }
 | 
			
		||||
	@property string project() const { return _project; }
 | 
			
		||||
	@property string email() const { return _email; }
 | 
			
		||||
	@property string user() const { return _user; }
 | 
			
		||||
	@property string author() const { return _author; }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -8,8 +8,8 @@ import std.array;
 | 
			
		|||
import std.process;
 | 
			
		||||
import std.algorithm;
 | 
			
		||||
import std.string;
 | 
			
		||||
import std.regex;
 | 
			
		||||
 | 
			
		||||
import snag.lib;
 | 
			
		||||
import snag.core.exception;
 | 
			
		||||
 | 
			
		||||
class Snag {
 | 
			
		||||
| 
						 | 
				
			
			@ -17,11 +17,6 @@ class Snag {
 | 
			
		|||
	private SnagConfig _config;
 | 
			
		||||
	private string _date;
 | 
			
		||||
 | 
			
		||||
	private bool isValidHash(string hash) {
 | 
			
		||||
		auto hashPattern = ctRegex!r"^[a-fA-F0-9]{7}$";
 | 
			
		||||
		return !matchFirst(hash, hashPattern).empty;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	this(SnagConfig config) {
 | 
			
		||||
		_baseCommand = format(
 | 
			
		||||
			"git --git-dir=%s --work-tree=%s",
 | 
			
		||||
| 
						 | 
				
			
			@ -58,7 +53,7 @@ class Snag {
 | 
			
		|||
			"A Git repository initialization error occurred"
 | 
			
		||||
		);
 | 
			
		||||
		git(
 | 
			
		||||
			["config", "user.name", _config.user],
 | 
			
		||||
			["config", "user.name", _config.author],
 | 
			
		||||
			"A Git repository initialization error occurred"
 | 
			
		||||
		);
 | 
			
		||||
		writeln(
 | 
			
		||||
| 
						 | 
				
			
			@ -84,7 +79,7 @@ class Snag {
 | 
			
		|||
		});
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void create() {
 | 
			
		||||
	void create(string comment, string author, string email) {
 | 
			
		||||
		auto result = git(
 | 
			
		||||
			["status", "--porcelain"],
 | 
			
		||||
			"An error occurred while checking the file tracking status"
 | 
			
		||||
| 
						 | 
				
			
			@ -96,11 +91,16 @@ class Snag {
 | 
			
		|||
				"Current file state doesn't need to be archived again"
 | 
			
		||||
			);
 | 
			
		||||
 | 
			
		||||
		author.length && (environment["GIT_AUTHOR_NAME"] = author);
 | 
			
		||||
		email.length && (environment["GIT_AUTHOR_EMAIL"] = email);
 | 
			
		||||
 | 
			
		||||
		string message = comment.length ? comment : "Standard snapshot creation";
 | 
			
		||||
 | 
			
		||||
		result = execute(_baseCommand ~ ["rev-parse", "--short", "HEAD"]);
 | 
			
		||||
		if (result.status == 128) {
 | 
			
		||||
			// Если это самый первый коммит после инициализации репозитория
 | 
			
		||||
			git(["add", "."], "Failed to prepare files for archiving");
 | 
			
		||||
			git(["commit", "-m", "test"], "Failed to create a backup");
 | 
			
		||||
			git(["commit", "-m"] ~ message, "Failed to create a backup");
 | 
			
		||||
			writeln("Backup was created successfully");
 | 
			
		||||
			return;
 | 
			
		||||
		} else if (result.status != 0)
 | 
			
		||||
| 
						 | 
				
			
			@ -139,7 +139,7 @@ class Snag {
 | 
			
		|||
				"Failed to prepare files for archiving"
 | 
			
		||||
			);
 | 
			
		||||
			git(
 | 
			
		||||
				["commit", "-m", "test"],
 | 
			
		||||
				["commit", "-m"] ~ message,
 | 
			
		||||
				"Failed to create a backup"
 | 
			
		||||
			);
 | 
			
		||||
			newSnapshot = git(
 | 
			
		||||
| 
						 | 
				
			
			@ -153,7 +153,7 @@ class Snag {
 | 
			
		|||
				"Failed to prepare files for archiving"
 | 
			
		||||
			);
 | 
			
		||||
			git(
 | 
			
		||||
				["commit", "-m", "test"],
 | 
			
		||||
				["commit", "-m"] ~ message,
 | 
			
		||||
				"Failed to create a backup"
 | 
			
		||||
			);
 | 
			
		||||
			newSnapshot = git(
 | 
			
		||||
| 
						 | 
				
			
			@ -172,7 +172,7 @@ class Snag {
 | 
			
		|||
		writeln("Backup was created successfully: ", newSnapshot);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void list(bool comment, bool user, bool email) {
 | 
			
		||||
	void list(bool comment, bool author, bool email) {
 | 
			
		||||
		string currentSnapshot = git(
 | 
			
		||||
			["rev-parse", "--short", "HEAD"],
 | 
			
		||||
			"Failed to retrieve current snapshot information"
 | 
			
		||||
| 
						 | 
				
			
			@ -181,7 +181,7 @@ class Snag {
 | 
			
		|||
		string format = "format:%h\t%ad";
 | 
			
		||||
 | 
			
		||||
		comment && (format ~= "\t%s");
 | 
			
		||||
		user && (format ~= "\t%an");
 | 
			
		||||
		author && (format ~= "\t%an");
 | 
			
		||||
		email && (format ~= "\t%ae");
 | 
			
		||||
 | 
			
		||||
		git(
 | 
			
		||||
| 
						 | 
				
			
			@ -227,4 +227,16 @@ class Snag {
 | 
			
		|||
		);
 | 
			
		||||
		writeln("Backup was restored successfully: ", hash);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void diff() {
 | 
			
		||||
		auto result = git(
 | 
			
		||||
			["diff"],
 | 
			
		||||
			"Failed to retrieve changes"
 | 
			
		||||
		);
 | 
			
		||||
		if (result.output.length) {
 | 
			
		||||
			result.output.write;
 | 
			
		||||
			return;
 | 
			
		||||
		}
 | 
			
		||||
		writeln("No changes at the moment");
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										13
									
								
								source/snag/lib/lib.d
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								source/snag/lib/lib.d
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,13 @@
 | 
			
		|||
module snag.lib.lib;
 | 
			
		||||
 | 
			
		||||
import std.regex;
 | 
			
		||||
 | 
			
		||||
bool isValidHash(string hash) {
 | 
			
		||||
	auto hashPattern = ctRegex!r"^[a-fA-F0-9]{7}$";
 | 
			
		||||
	return !matchFirst(hash, hashPattern).empty;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool isValidEmail(string email) {
 | 
			
		||||
	auto emailPattern = ctRegex!r"^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$";
 | 
			
		||||
	return !matchFirst(email, emailPattern).empty;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										3
									
								
								source/snag/lib/package.d
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								source/snag/lib/package.d
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,3 @@
 | 
			
		|||
module snag.lib;
 | 
			
		||||
 | 
			
		||||
public import snag.lib.lib;
 | 
			
		||||
| 
						 | 
				
			
			@ -1,5 +1,6 @@
 | 
			
		|||
module snag;
 | 
			
		||||
 | 
			
		||||
public import snag.version_;
 | 
			
		||||
public import snag.lib;
 | 
			
		||||
public import snag.config;
 | 
			
		||||
public import snag.core;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,3 +1,3 @@
 | 
			
		|||
module snag.version_;
 | 
			
		||||
 | 
			
		||||
enum snagVersion = "0.0.7";
 | 
			
		||||
enum snagVersion = "0.0.8";
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue