refactor(cli): moved all commands to seperate functions
This commit is contained in:
parent
0e0d1fa1ef
commit
bb961f0437
1 changed files with 332 additions and 304 deletions
636
src/main.c
636
src/main.c
|
|
@ -21,264 +21,221 @@ static void usage(int exitcode) {
|
||||||
exit(exitcode);
|
exit(exitcode);
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, char** argv) {
|
static int init() {
|
||||||
if (argc == 2 && (!strcmp(argv[1], "-h") || !strcmp(argv[1], "--help"))) {
|
if (mkdir(".merk", 0755) == 0) {
|
||||||
usage(0);
|
printf("Initialized merk repository\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
const char* subcmd = argv[1];
|
if (errno == EEXIST) {
|
||||||
|
struct stat st;
|
||||||
if (strcmp(subcmd, "diff") != 0 &&
|
if (stat(".merk", &st) == 0 && S_ISDIR(st.st_mode)) {
|
||||||
strcmp(subcmd, "init") != 0 &&
|
printf("This directory is already a merk repository\n");
|
||||||
strcmp(subcmd, "status") != 0 &&
|
|
||||||
strcmp(subcmd, "commit") != 0 &&
|
|
||||||
strcmp(subcmd, "log") != 0 &&
|
|
||||||
strcmp(subcmd, "test") != 0
|
|
||||||
) {
|
|
||||||
fprintf(stderr, "ERROR: Unknown subcommand: '%s'\n", subcmd);
|
|
||||||
usage(2);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Initializes a merk repository in the current directory
|
|
||||||
if (strcmp(subcmd, "init") == 0) {
|
|
||||||
if (argc != 2) {
|
|
||||||
printf("ERROR: too many agruments given!\n");
|
|
||||||
printf("Usage: merk init");
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mkdir(".merk", 0755) == 0) {
|
|
||||||
printf("Initialized merk repository\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (errno == EEXIST) {
|
|
||||||
struct stat st;
|
|
||||||
if (stat(".merk", &st) == 0 && S_ISDIR(st.st_mode)) {
|
|
||||||
printf("This directory is already a merk repository\n");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int branch = open(".merk/BRANCH", O_WRONLY | O_CREAT, 0666);
|
|
||||||
if (branch < 0) return -1;
|
|
||||||
write(branch, "main", 4);
|
|
||||||
close(branch);
|
|
||||||
|
|
||||||
mkdir(".merk/objects", 0755);
|
|
||||||
mkdir(".merk/refs", 0755);
|
|
||||||
mkdir(".merk/refs/branches", 0755);
|
|
||||||
mkdir(".merk/info", 0755);
|
|
||||||
mkdir(".merk/logs", 0755);
|
|
||||||
mkdir(".merk/logs/branches", 0755);
|
|
||||||
|
|
||||||
int main_branch = open(".merk/refs/branches/main", O_WRONLY | O_CREAT, 0666);
|
|
||||||
if (main_branch < 0) return -1;
|
|
||||||
close(main_branch);
|
|
||||||
|
|
||||||
int main_info = open(".merk/info/main", O_WRONLY | O_CREAT, 0666);
|
|
||||||
if (main_info < 0) return -1;
|
|
||||||
close(main_info);
|
|
||||||
|
|
||||||
int main_log = open(".merk/logs/branches/main", O_WRONLY | O_CREAT, 0666);
|
|
||||||
if (main_log < 0) return -1;
|
|
||||||
close(main_log);
|
|
||||||
|
|
||||||
CommitLog* empty = commit_log_new();
|
|
||||||
if (!empty) { perror("ERROR: failed to create commit log for branch main!"); return -1; }
|
|
||||||
if (!write_commit_log(empty, ".merk/logs/branches/main")) { perror("ERROR: failed to write initial main commit log!"); commit_log_free(empty); return -1; }
|
|
||||||
|
|
||||||
commit_log_free(empty);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Prints out a visual representation of the diff of the files provided
|
|
||||||
else if (strcmp(subcmd, "diff") == 0) {
|
|
||||||
if (argc != 4) {
|
|
||||||
printf("ERROR: too many/little arguments given!\n");
|
|
||||||
printf("Usage: merk diff <PATH> <PATH>");
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
File* file1;
|
|
||||||
switch (get_path_type(argv[2])) {
|
|
||||||
case PT_FILE: file1 = new_file(argv[2]); break;
|
|
||||||
case PT_DIR: file1 = NULL; printf("ERROR: first path is a directory and no file!"); break;
|
|
||||||
case PT_NOEXIST: file1 = NULL; printf("ERROR: first path does not exist!"); break;
|
|
||||||
default: file1 = NULL; printf("ERROR: unknown first path!");
|
|
||||||
}
|
|
||||||
if (!file1) exit(1);
|
|
||||||
|
|
||||||
File* file2;
|
|
||||||
switch (get_path_type(argv[3])) {
|
|
||||||
case PT_FILE: file2 = new_file(argv[3]); break;
|
|
||||||
case PT_DIR: file2 = NULL; printf("ERROR: second path is a directory and no file!"); break;
|
|
||||||
case PT_NOEXIST: file2 = NULL; printf("ERROR: second path does not exist!"); break;
|
|
||||||
default: file2 = NULL; printf("ERROR: unknown second path!");
|
|
||||||
}
|
|
||||||
if (!file2) exit(1);
|
|
||||||
|
|
||||||
ActionList* actions = myers_diff(file1, file2, 0, 0);
|
|
||||||
if (!actions) printf("ERROR: something went wrong while taking the diff!");
|
|
||||||
else visualize_diff(file1, file2, actions);
|
|
||||||
}
|
|
||||||
// Gives a list of untracked files in the repo as well as meta information
|
|
||||||
else if (strcmp(subcmd, "status") == 0) {
|
|
||||||
if (argc != 2) {
|
|
||||||
printf("ERROR: too many arguments given!\n");
|
|
||||||
printf("Usage: merk status");
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
FileInfoBuffer* files = file_info_buffer_new();
|
|
||||||
char relative[PATH_MAX] = "";
|
|
||||||
char* root = find_root(relative);
|
|
||||||
if (!root) {
|
|
||||||
list_free(files);
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
walk(root, relative, relative, files, 0, root);
|
|
||||||
file_info_buffer_sort(files);
|
|
||||||
|
|
||||||
char branch_path[PATH_MAX];
|
|
||||||
snprintf(branch_path, sizeof(branch_path), "%s/.merk/BRANCH", root);
|
|
||||||
char* branch = get_file_content(branch_path);
|
|
||||||
char info_path[PATH_MAX];
|
|
||||||
snprintf(info_path, sizeof(info_path), "%s/.merk/info/%s", root, branch);
|
|
||||||
|
|
||||||
char log_path[PATH_MAX];
|
|
||||||
snprintf(log_path, sizeof(log_path), "%s/.merk/logs/branches/%s", root, branch);
|
|
||||||
|
|
||||||
CommitLog* log = commit_log_new();
|
|
||||||
read_commit_log(log, log_path);
|
|
||||||
char* last_tree_hash = NULL;
|
|
||||||
if (log->len != 0) {
|
|
||||||
last_tree_hash = ((Commit*)log->items + (log->len))->tree_hash;
|
|
||||||
}
|
|
||||||
|
|
||||||
BaseFileBuffer* tracked_list = base_file_buffer_new();
|
|
||||||
read_base_file_list(tracked_list, info_path);
|
|
||||||
|
|
||||||
StringBuffer* modified_files = string_buffer_new();
|
|
||||||
StringBuffer* deleted_files = string_buffer_new();
|
|
||||||
StringBuffer* untracked_files = string_buffer_new();
|
|
||||||
|
|
||||||
Changes* changes = calloc(1, sizeof(Changes));
|
|
||||||
if (!changes) {
|
|
||||||
printf("ERROR: unable to allocate memory for changes!\n");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
changes->insertions = 0;
|
|
||||||
changes->deletions = 0;
|
|
||||||
|
|
||||||
for (size_t idx = 0; idx < files->len; idx++) {
|
|
||||||
char* file_name = ((FileInfo*)files->items + idx)->name;
|
|
||||||
if (base_file_buffer_search(tracked_list, file_name)) continue;
|
|
||||||
string_buffer_push(untracked_files, file_name);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (size_t idx = 0; idx < files->len; idx++) {
|
|
||||||
char* file_name = ((FileInfo*)files->items + idx)->name;
|
|
||||||
if (base_file_buffer_search(tracked_list, file_name)) {
|
|
||||||
BaseFileInfo* base_file = base_file_buffer_search(tracked_list, file_name);
|
|
||||||
char base_file_hash[41];
|
|
||||||
char id[2 + snprintf(NULL, 0, "%d", base_file->base_num) + strlen(file_name)];
|
|
||||||
snprintf(id, sizeof(id), "%s %d", file_name, base_file->base_num);
|
|
||||||
object_hash(BaseFileObject, id, base_file_hash);
|
|
||||||
File* basefile = parse_object(base_file_hash, BaseFileObject, NULL, NULL);
|
|
||||||
if (!basefile) {
|
|
||||||
printf("ERROR: unable to parse base file %s!\n", file_name);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
File* modified_file = new_file(file_name);
|
|
||||||
if (!modified_file) {
|
|
||||||
printf("ERROR: unable to read modified file %s!\n", file_name);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
File* comparison_file = basefile;
|
|
||||||
|
|
||||||
// If there are previous diffs, we need to compare against the last committed version
|
|
||||||
if (base_file->diff_num > 0) {
|
|
||||||
size_t prev_diff = base_file->diff_num - 1;
|
|
||||||
char prev_diff_hash[41];
|
|
||||||
char id2[2 + snprintf(NULL, 0, "%zu", prev_diff) + strlen(file_name)];
|
|
||||||
snprintf(id2, sizeof(id2), "%s %zu", file_name, prev_diff);
|
|
||||||
object_hash(FileDiffObject, id2, prev_diff_hash);
|
|
||||||
char hash[41];
|
|
||||||
ActionList* last_diff = parse_object(prev_diff_hash, FileDiffObject, NULL, hash);
|
|
||||||
if (last_diff) {
|
|
||||||
File* last_version = apply_diff(basefile, last_diff);
|
|
||||||
if (last_version) {
|
|
||||||
comparison_file = last_version;
|
|
||||||
}
|
|
||||||
free_action_list(last_diff);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ActionList* diff = myers_diff(comparison_file, modified_file, 0, 0);
|
|
||||||
if (!diff) {
|
|
||||||
printf("ERROR: unable to compute diff for file %s!\n", file_name);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (diff->len != 0) {
|
|
||||||
for (size_t idx = 0; idx < diff->len; idx++) {
|
|
||||||
Action action = diff->actions[idx];
|
|
||||||
if (action.type == DELETE) {
|
|
||||||
changes->deletions++;
|
|
||||||
} else if (action.type == INSERT) {
|
|
||||||
changes->insertions++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
string_buffer_push(modified_files, file_name);
|
|
||||||
}
|
|
||||||
|
|
||||||
free_action_list(diff);
|
|
||||||
free_file(modified_file);
|
|
||||||
if (comparison_file != basefile) {
|
|
||||||
free_file(comparison_file);
|
|
||||||
}
|
|
||||||
free_file(basefile);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (size_t idx = 0; idx < tracked_list->len; idx++) {
|
|
||||||
char* file_name = ((BaseFileInfo*)tracked_list->items + idx)->name;
|
|
||||||
if (file_info_buffer_search(files, file_name)) continue;
|
|
||||||
else string_buffer_push(deleted_files, file_name);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (size_t idx = 0; idx < modified_files->len; idx++) {
|
|
||||||
printf("\x1b[36;1mM\x1b[0m \x1b[36m%s\x1b[0m\n", modified_files->items[idx]);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (size_t idx = 0; idx < deleted_files->len; idx++) {
|
|
||||||
printf("\x1b[31;4mD\x1b[0m \x1b[31;9m%s\x1b[0m\n", deleted_files->items[idx]);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (modified_files->len != 0 || deleted_files->len != 0) printf("\n");
|
|
||||||
|
|
||||||
for (size_t idx = 0; idx < untracked_files->len; idx++) {
|
|
||||||
printf("\x1b[31;1mU\x1b[0m \x1b[31m%s\x1b[0m\n", untracked_files->items[idx]);
|
|
||||||
}
|
|
||||||
|
|
||||||
printf("\n\x1b[32;1m%d+\x1b[0m \x1b[31;1m%d-\x1b[0m on branch \x1b[39;1;4m%s\x1b[0m with %d commits\n", changes->insertions, changes->deletions, branch, log->len);
|
|
||||||
|
|
||||||
file_info_buffer_free(files);
|
|
||||||
free(root);
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
// Commits changes to the repo
|
|
||||||
else if (strcmp(subcmd, "commit") == 0) {
|
|
||||||
if (argc < 3) {
|
|
||||||
printf("ERROR: too little arguments given!\n");
|
|
||||||
printf("Usage: merk commit [-m <COMMIT MESSAGE>] <FILE> ...\n");
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
char* commit_message = NULL;
|
int branch = open(".merk/BRANCH", O_WRONLY | O_CREAT, 0666);
|
||||||
|
if (branch < 0) return 0;
|
||||||
|
write(branch, "main", 4);
|
||||||
|
close(branch);
|
||||||
|
|
||||||
|
mkdir(".merk/objects", 0755);
|
||||||
|
mkdir(".merk/refs", 0755);
|
||||||
|
mkdir(".merk/refs/branches", 0755);
|
||||||
|
mkdir(".merk/info", 0755);
|
||||||
|
mkdir(".merk/logs", 0755);
|
||||||
|
mkdir(".merk/logs/branches", 0755);
|
||||||
|
|
||||||
|
int main_branch = open(".merk/refs/branches/main", O_WRONLY | O_CREAT, 0666);
|
||||||
|
if (main_branch < 0) return 0;
|
||||||
|
close(main_branch);
|
||||||
|
|
||||||
|
int main_info = open(".merk/info/main", O_WRONLY | O_CREAT, 0666);
|
||||||
|
if (main_info < 0) return 0;
|
||||||
|
close(main_info);
|
||||||
|
|
||||||
|
int main_log = open(".merk/logs/branches/main", O_WRONLY | O_CREAT, 0666);
|
||||||
|
if (main_log < 0) return 0;
|
||||||
|
close(main_log);
|
||||||
|
|
||||||
|
CommitLog* empty = commit_log_new();
|
||||||
|
if (!empty) { perror("ERROR: failed to create commit log for branch main!"); return 0; }
|
||||||
|
if (!write_commit_log(empty, ".merk/logs/branches/main")) { perror("ERROR: failed to write initial main commit log!"); commit_log_free(empty); return 0; }
|
||||||
|
|
||||||
|
commit_log_free(empty);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int diff(char* file1_path, char* file2_path) {
|
||||||
|
File* file1;
|
||||||
|
switch (get_path_type(file1_path)) {
|
||||||
|
case PT_FILE: file1 = new_file(file1_path); break;
|
||||||
|
case PT_DIR: file1 = NULL; printf("ERROR: first path is a directory and no file!"); break;
|
||||||
|
case PT_NOEXIST: file1 = NULL; printf("ERROR: first path does not exist!"); break;
|
||||||
|
default: file1 = NULL; printf("ERROR: unknown first path!");
|
||||||
|
}
|
||||||
|
if (!file1) exit(1);
|
||||||
|
|
||||||
|
File* file2;
|
||||||
|
switch (get_path_type(file2_path)) {
|
||||||
|
case PT_FILE: file2 = new_file(file2_path); break;
|
||||||
|
case PT_DIR: file2 = NULL; printf("ERROR: second path is a directory and no file!"); break;
|
||||||
|
case PT_NOEXIST: file2 = NULL; printf("ERROR: second path does not exist!"); break;
|
||||||
|
default: file2 = NULL; printf("ERROR: unknown second path!");
|
||||||
|
}
|
||||||
|
if (!file2) exit(1);
|
||||||
|
|
||||||
|
ActionList* actions = myers_diff(file1, file2, 0, 0);
|
||||||
|
if (!actions) printf("ERROR: something went wrong while taking the diff!");
|
||||||
|
else visualize_diff(file1, file2, actions);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int status() {
|
||||||
|
FileInfoBuffer* files = file_info_buffer_new();
|
||||||
|
char relative[PATH_MAX] = "";
|
||||||
|
char* root = find_root(relative);
|
||||||
|
if (!root) {
|
||||||
|
list_free(files);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
walk(root, relative, relative, files, 0, root);
|
||||||
|
file_info_buffer_sort(files);
|
||||||
|
|
||||||
|
char branch_path[PATH_MAX];
|
||||||
|
snprintf(branch_path, sizeof(branch_path), "%s/.merk/BRANCH", root);
|
||||||
|
char* branch = get_file_content(branch_path);
|
||||||
|
char info_path[PATH_MAX];
|
||||||
|
snprintf(info_path, sizeof(info_path), "%s/.merk/info/%s", root, branch);
|
||||||
|
|
||||||
|
char log_path[PATH_MAX];
|
||||||
|
snprintf(log_path, sizeof(log_path), "%s/.merk/logs/branches/%s", root, branch);
|
||||||
|
|
||||||
|
CommitLog* log = commit_log_new();
|
||||||
|
read_commit_log(log, log_path);
|
||||||
|
char* last_tree_hash = NULL;
|
||||||
|
if (log->len != 0) {
|
||||||
|
last_tree_hash = ((Commit*)log->items + (log->len))->tree_hash;
|
||||||
|
}
|
||||||
|
|
||||||
|
BaseFileBuffer* tracked_list = base_file_buffer_new();
|
||||||
|
read_base_file_list(tracked_list, info_path);
|
||||||
|
|
||||||
|
StringBuffer* modified_files = string_buffer_new();
|
||||||
|
StringBuffer* deleted_files = string_buffer_new();
|
||||||
|
StringBuffer* untracked_files = string_buffer_new();
|
||||||
|
|
||||||
|
Changes* changes = calloc(1, sizeof(Changes));
|
||||||
|
if (!changes) {
|
||||||
|
printf("ERROR: unable to allocate memory for changes!\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
changes->insertions = 0;
|
||||||
|
changes->deletions = 0;
|
||||||
|
|
||||||
|
for (size_t idx = 0; idx < files->len; idx++) {
|
||||||
|
char* file_name = ((FileInfo*)files->items + idx)->name;
|
||||||
|
if (base_file_buffer_search(tracked_list, file_name)) continue;
|
||||||
|
string_buffer_push(untracked_files, file_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (size_t idx = 0; idx < files->len; idx++) {
|
||||||
|
char* file_name = ((FileInfo*)files->items + idx)->name;
|
||||||
|
if (base_file_buffer_search(tracked_list, file_name)) {
|
||||||
|
BaseFileInfo* base_file = base_file_buffer_search(tracked_list, file_name);
|
||||||
|
char base_file_hash[41];
|
||||||
|
char id[2 + snprintf(NULL, 0, "%d", base_file->base_num) + strlen(file_name)];
|
||||||
|
snprintf(id, sizeof(id), "%s %d", file_name, base_file->base_num);
|
||||||
|
object_hash(BaseFileObject, id, base_file_hash);
|
||||||
|
File* basefile = parse_object(base_file_hash, BaseFileObject, NULL, NULL);
|
||||||
|
if (!basefile) {
|
||||||
|
printf("ERROR: unable to parse base file %s!\n", file_name);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
File* modified_file = new_file(file_name);
|
||||||
|
if (!modified_file) {
|
||||||
|
printf("ERROR: unable to read modified file %s!\n", file_name);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
File* comparison_file = basefile;
|
||||||
|
|
||||||
|
if (base_file->diff_num > 0) {
|
||||||
|
size_t prev_diff = base_file->diff_num - 1;
|
||||||
|
char prev_diff_hash[41];
|
||||||
|
char id2[2 + snprintf(NULL, 0, "%zu", prev_diff) + strlen(file_name)];
|
||||||
|
snprintf(id2, sizeof(id2), "%s %zu", file_name, prev_diff);
|
||||||
|
object_hash(FileDiffObject, id2, prev_diff_hash);
|
||||||
|
char hash[41];
|
||||||
|
ActionList* last_diff = parse_object(prev_diff_hash, FileDiffObject, NULL, hash);
|
||||||
|
if (last_diff) {
|
||||||
|
File* last_version = apply_diff(basefile, last_diff);
|
||||||
|
if (last_version) {
|
||||||
|
comparison_file = last_version;
|
||||||
|
}
|
||||||
|
free_action_list(last_diff);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ActionList* diff = myers_diff(comparison_file, modified_file, 0, 0);
|
||||||
|
if (!diff) {
|
||||||
|
printf("ERROR: unable to compute diff for file %s!\n", file_name);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (diff->len != 0) {
|
||||||
|
for (size_t idx = 0; idx < diff->len; idx++) {
|
||||||
|
Action action = diff->actions[idx];
|
||||||
|
if (action.type == DELETE) {
|
||||||
|
changes->deletions++;
|
||||||
|
} else if (action.type == INSERT) {
|
||||||
|
changes->insertions++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
string_buffer_push(modified_files, file_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
free_action_list(diff);
|
||||||
|
free_file(modified_file);
|
||||||
|
if (comparison_file != basefile) {
|
||||||
|
free_file(comparison_file);
|
||||||
|
}
|
||||||
|
free_file(basefile);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (size_t idx = 0; idx < tracked_list->len; idx++) {
|
||||||
|
char* file_name = ((BaseFileInfo*)tracked_list->items + idx)->name;
|
||||||
|
if (file_info_buffer_search(files, file_name)) continue;
|
||||||
|
else string_buffer_push(deleted_files, file_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (size_t idx = 0; idx < modified_files->len; idx++) {
|
||||||
|
printf("\x1b[36;1mM\x1b[0m \x1b[36m%s\x1b[0m\n", modified_files->items[idx]);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (size_t idx = 0; idx < deleted_files->len; idx++) {
|
||||||
|
printf("\x1b[31;4mD\x1b[0m \x1b[31;9m%s\x1b[0m\n", deleted_files->items[idx]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (modified_files->len != 0 || deleted_files->len != 0) printf("\n");
|
||||||
|
|
||||||
|
for (size_t idx = 0; idx < untracked_files->len; idx++) {
|
||||||
|
printf("\x1b[31;1mU\x1b[0m \x1b[31m%s\x1b[0m\n", untracked_files->items[idx]);
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("\n\x1b[32;1m%d+\x1b[0m \x1b[31;1m%d-\x1b[0m on branch \x1b[39;1;4m%s\x1b[0m with %d commits\n", changes->insertions, changes->deletions, branch, log->len);
|
||||||
|
|
||||||
|
file_info_buffer_free(files);
|
||||||
|
free(root);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int commit(int argc, char** argv) {
|
||||||
|
char* commit_message = NULL;
|
||||||
int file_start_index = 2;
|
int file_start_index = 2;
|
||||||
|
|
||||||
if (argc >= 4 && strcmp(argv[2], "-m") == 0) {
|
if (argc >= 4 && strcmp(argv[2], "-m") == 0) {
|
||||||
|
|
@ -297,7 +254,6 @@ int main(int argc, char** argv) {
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ensure files to commit are correctly identified
|
|
||||||
for (int i = file_start_index; i < argc; i++) {
|
for (int i = file_start_index; i < argc; i++) {
|
||||||
if (strcmp(argv[i], "-m") == 0) {
|
if (strcmp(argv[i], "-m") == 0) {
|
||||||
printf("ERROR: Unexpected -m flag in file list!\n");
|
printf("ERROR: Unexpected -m flag in file list!\n");
|
||||||
|
|
@ -731,67 +687,139 @@ int main(int argc, char** argv) {
|
||||||
free(root);
|
free(root);
|
||||||
free_config(&config);
|
free_config(&config);
|
||||||
free(commit_message);
|
free(commit_message);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int commit_log() {
|
||||||
|
CommitLog* log = commit_log_new();
|
||||||
|
if (!log) return 0;
|
||||||
|
|
||||||
|
char* root = find_root(NULL);
|
||||||
|
if (!root) {
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
else if (strcmp(subcmd, "log") == 0) {
|
|
||||||
CommitLog* log = commit_log_new();
|
|
||||||
if (!log) return 1;
|
|
||||||
|
|
||||||
char* root = find_root(NULL);
|
char branch_path[PATH_MAX];
|
||||||
if (!root) {
|
snprintf(branch_path, sizeof(branch_path), "%s/.merk/BRANCH", root);
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
char branch_path[PATH_MAX];
|
char* branch = get_file_content(branch_path);
|
||||||
snprintf(branch_path, sizeof(branch_path), "%s/.merk/BRANCH", root);
|
if (!branch) {
|
||||||
|
free(root);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
char* branch = get_file_content(branch_path);
|
char log_path[PATH_MAX];
|
||||||
if (!branch) {
|
snprintf(log_path, sizeof(log_path), "%s/.merk/logs/branches/%s", root, branch);
|
||||||
free(root);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
char log_path[PATH_MAX];
|
read_commit_log(log, log_path);
|
||||||
snprintf(log_path, sizeof(log_path), "%s/.merk/logs/branches/%s", root, branch);
|
|
||||||
|
|
||||||
read_commit_log(log, log_path);
|
char ref_path[PATH_MAX];
|
||||||
|
snprintf(ref_path, sizeof(ref_path), "%s/.merk/refs/branches/%s", root, branch);
|
||||||
char ref_path[PATH_MAX];
|
|
||||||
snprintf(ref_path, sizeof(ref_path), "%s/.merk/refs/branches/%s", root, branch);
|
|
||||||
|
|
||||||
int ref = open(ref_path, O_RDONLY);
|
|
||||||
if (ref < 0) {
|
|
||||||
free(branch);
|
|
||||||
free(root);
|
|
||||||
commit_log_free(log);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
char head[41] = "";
|
|
||||||
read(ref, head, 40);
|
|
||||||
close(ref);
|
|
||||||
|
|
||||||
for (size_t i = log->len; i != 0; i--) {
|
|
||||||
Commit* commit = (Commit*)log->items + i - 1;
|
|
||||||
char human_readable_time[32];
|
|
||||||
time_t timestamp = atol(commit->committer.timestamp);
|
|
||||||
strftime(human_readable_time, sizeof(human_readable_time), "%Y-%m-%d %H:%M:%S %z", localtime(×tamp));
|
|
||||||
|
|
||||||
char* marker = (strcmp(commit->hash, head) == 0) ? "\x1b[32m@\x1b[0m" : "\x1b[34m◯\x1b[0m";
|
|
||||||
|
|
||||||
printf("%s \x1b[33;1m%.7s\x1b[0m: %s\n│ %s <\x1b[38;5;240m\x1b]8;;mailto:%s\x1b\\%s\x1b]8;;\x1b\\\x1b[0m> (\x1b[36m%s\x1b[0m)\n│\n",
|
|
||||||
marker,
|
|
||||||
commit->hash,
|
|
||||||
commit->message,
|
|
||||||
commit->committer.name,
|
|
||||||
commit->committer.email,
|
|
||||||
commit->committer.email,
|
|
||||||
human_readable_time
|
|
||||||
);
|
|
||||||
}
|
|
||||||
if (log->len != 0) printf("┴\n");
|
|
||||||
|
|
||||||
|
int ref = open(ref_path, O_RDONLY);
|
||||||
|
if (ref < 0) {
|
||||||
free(branch);
|
free(branch);
|
||||||
free(root);
|
free(root);
|
||||||
commit_log_free(log);
|
commit_log_free(log);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
char head[41] = "";
|
||||||
|
read(ref, head, 40);
|
||||||
|
close(ref);
|
||||||
|
|
||||||
|
for (size_t i = log->len; i != 0; i--) {
|
||||||
|
Commit* commit = (Commit*)log->items + i - 1;
|
||||||
|
char human_readable_time[32];
|
||||||
|
time_t timestamp = atol(commit->committer.timestamp);
|
||||||
|
strftime(human_readable_time, sizeof(human_readable_time), "%Y-%m-%d %H:%M:%S %z", localtime(×tamp));
|
||||||
|
|
||||||
|
char* marker = (strcmp(commit->hash, head) == 0) ? "\x1b[32m@\x1b[0m" : "\x1b[34m◯\x1b[0m";
|
||||||
|
|
||||||
|
printf("%s \x1b[33;1m%.7s\x1b[0m: %s\n│ %s <\x1b[38;5;240m\x1b]8;;mailto:%s\x1b\\%s\x1b]8;;\x1b\\\x1b[0m> (\x1b[36m%s\x1b[0m)\n│\n",
|
||||||
|
marker,
|
||||||
|
commit->hash,
|
||||||
|
commit->message,
|
||||||
|
commit->committer.name,
|
||||||
|
commit->committer.email,
|
||||||
|
commit->committer.email,
|
||||||
|
human_readable_time
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (log->len != 0) printf("┴\n");
|
||||||
|
|
||||||
|
free(branch);
|
||||||
|
free(root);
|
||||||
|
commit_log_free(log);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char** argv) {
|
||||||
|
if (argc == 2 && (!strcmp(argv[1], "-h") || !strcmp(argv[1], "--help"))) {
|
||||||
|
usage(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* subcmd = argv[1];
|
||||||
|
|
||||||
|
if (strcmp(subcmd, "diff") != 0 &&
|
||||||
|
strcmp(subcmd, "init") != 0 &&
|
||||||
|
strcmp(subcmd, "status") != 0 &&
|
||||||
|
strcmp(subcmd, "commit") != 0 &&
|
||||||
|
strcmp(subcmd, "log") != 0 &&
|
||||||
|
strcmp(subcmd, "test") != 0
|
||||||
|
) {
|
||||||
|
fprintf(stderr, "ERROR: Unknown subcommand: '%s'\n", subcmd);
|
||||||
|
usage(2);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initializes a merk repository in the current directory
|
||||||
|
if (strcmp(subcmd, "init") == 0) {
|
||||||
|
if (argc != 2) {
|
||||||
|
printf("ERROR: too many arguments given!\n");
|
||||||
|
printf("Usage: merk init");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
init();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Prints out a visual representation of the diff of the files provided
|
||||||
|
else if (strcmp(subcmd, "diff") == 0) {
|
||||||
|
if (argc != 4) {
|
||||||
|
printf("ERROR: too many/little arguments given!\n");
|
||||||
|
printf("Usage: merk diff <PATH> <PATH>");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
diff(argv[2], argv[3]);
|
||||||
|
}
|
||||||
|
// Gives a list of untracked files in the repo as well as meta information
|
||||||
|
else if (strcmp(subcmd, "status") == 0) {
|
||||||
|
if (argc != 2) {
|
||||||
|
printf("ERROR: too many arguments given!\n");
|
||||||
|
printf("Usage: merk status");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
status();
|
||||||
|
}
|
||||||
|
// Commits changes to the repo
|
||||||
|
else if (strcmp(subcmd, "commit") == 0) {
|
||||||
|
if (argc < 3) {
|
||||||
|
printf("ERROR: too little arguments given!\n");
|
||||||
|
printf("Usage: merk commit [-m <COMMIT MESSAGE>] <FILE> ...\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
commit(argc, argv);
|
||||||
|
}
|
||||||
|
else if (strcmp(subcmd, "log") == 0) {
|
||||||
|
if (argc != 2) {
|
||||||
|
printf("ERROR: too many arguments given!\n");
|
||||||
|
printf("Usage: merk log");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
commit_log();
|
||||||
}
|
}
|
||||||
else if (strcmp(subcmd, "test") == 0) {}
|
else if (strcmp(subcmd, "test") == 0) {}
|
||||||
else {
|
else {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue