feat: added a more general way to display relative paths for the status cli command
This commit is contained in:
parent
c372a5f8bc
commit
25480fc92f
4 changed files with 143 additions and 25 deletions
|
|
@ -18,7 +18,7 @@ typedef struct {
|
||||||
PathBuffer* new_path_buffer();
|
PathBuffer* new_path_buffer();
|
||||||
void add_path(PathBuffer*, char*);
|
void add_path(PathBuffer*, char*);
|
||||||
void free_path_buffer(PathBuffer*);
|
void free_path_buffer(PathBuffer*);
|
||||||
char* find_root(const char*);
|
char* find_root(char*);
|
||||||
void walk(const char*, const char*, PathBuffer*);
|
void walk(const char*, const char*, const char*, PathBuffer*);
|
||||||
|
|
||||||
#endif // TREE_H
|
#endif // TREE_H
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,13 @@
|
||||||
#ifndef UTILITIES_H
|
#ifndef UTILITIES_H
|
||||||
#define UTILITIES_H
|
#define UTILITIES_H
|
||||||
|
|
||||||
#include <sys/stat.h>
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
#include <dirent.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
#include "file.h"
|
#include "file.h"
|
||||||
#include "action_list.h"
|
#include "action_list.h"
|
||||||
|
|
|
||||||
17
src/main.c
17
src/main.c
|
|
@ -12,7 +12,7 @@
|
||||||
#include "tree.h"
|
#include "tree.h"
|
||||||
|
|
||||||
static void usage(int exitcode) {
|
static void usage(int exitcode) {
|
||||||
printf("usage: merk <command> [<args>]\n\n init Initializes a repository in the current directory\n diff Displays the difference between the given two files\n");
|
printf("usage: merk <command> [<args>]\n\n init Initializes a repository in the current directory\n diff Displays the difference between the given two files\n status Displays a list of modified and untracked files in the repository\n");
|
||||||
exit(exitcode);
|
exit(exitcode);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -83,8 +83,7 @@ int main(int argc, char **argv) {
|
||||||
if (!actions) printf("ERROR: something went wrong while taking the diff!");
|
if (!actions) printf("ERROR: something went wrong while taking the diff!");
|
||||||
else visualize_diff(file1, file2, actions);
|
else visualize_diff(file1, file2, actions);
|
||||||
}
|
}
|
||||||
// TODO: Make it repo specific and not universal
|
// Gives a list of untracked files in the repo
|
||||||
// Gives a list of untracked files in the filesystem
|
|
||||||
else if (strcmp(subcmd, "status") == 0) {
|
else if (strcmp(subcmd, "status") == 0) {
|
||||||
if (argc != 2) {
|
if (argc != 2) {
|
||||||
printf("ERROR: too many arguments given!\n");
|
printf("ERROR: too many arguments given!\n");
|
||||||
|
|
@ -92,15 +91,23 @@ int main(int argc, char **argv) {
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
printf("Untracked files:\n\n");
|
|
||||||
PathBuffer* files = new_path_buffer();
|
PathBuffer* files = new_path_buffer();
|
||||||
walk(".", "./", files);
|
char relative[PATH_MAX] = "";
|
||||||
|
char* root = find_root(relative);
|
||||||
|
if (!root) {
|
||||||
|
free_path_buffer(files);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
walk(root, relative, relative, files);
|
||||||
|
|
||||||
|
printf("Untracked files:\n\n");
|
||||||
for (size_t i = 0; i < files->len; i++) {
|
for (size_t i = 0; i < files->len; i++) {
|
||||||
printf("%s\n", files->paths[i]);
|
printf("%s\n", files->paths[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
free_path_buffer(files);
|
free_path_buffer(files);
|
||||||
|
free(root);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
|
|
||||||
140
src/tree.c
140
src/tree.c
|
|
@ -73,16 +73,97 @@ static char* join_path(const char* a, const char* b) {
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
void walk(const char* base, const char* rel, PathBuffer* paths) {
|
char* find_root(char* relative) {
|
||||||
char* dir_full = rel[0] ? join_path(base, rel) : strdup(base);
|
char* current_dir = calloc(PATH_MAX, sizeof(char));
|
||||||
if (!dir_full) {
|
if (!current_dir) {
|
||||||
perror("ERROR: memory allocation failed in walk!");
|
perror("ERROR: calloc in find_root failed!");
|
||||||
exit(1);
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
DIR* dir = opendir(dir_full);
|
if (!getcwd(current_dir, PATH_MAX)) {
|
||||||
|
perror("ERROR: getcwd in find_root failed!");
|
||||||
|
free(current_dir);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
char* search_dir = strdup(current_dir);
|
||||||
|
if (!search_dir) {
|
||||||
|
perror("ERROR: strdup in find_root failed!");
|
||||||
|
free(current_dir);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
size_t dir_len = strlen(search_dir);
|
||||||
|
size_t merk_path_len = dir_len + strlen("/.merk") + 1;
|
||||||
|
char* merk_path = calloc(merk_path_len, sizeof(char));
|
||||||
|
if (!merk_path) {
|
||||||
|
perror("ERROR: calloc in find_root failed!");
|
||||||
|
free(current_dir);
|
||||||
|
free(search_dir);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
snprintf(merk_path, merk_path_len, "%s/.merk", search_dir);
|
||||||
|
|
||||||
|
struct stat st;
|
||||||
|
if (stat(merk_path, &st) == 0 && S_ISDIR(st.st_mode)) {
|
||||||
|
free(current_dir);
|
||||||
|
free(merk_path);
|
||||||
|
char* result = strdup(search_dir);
|
||||||
|
free(search_dir);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
free(merk_path);
|
||||||
|
|
||||||
|
if (strcmp(search_dir, "/") == 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
char temp[PATH_MAX];
|
||||||
|
snprintf(temp, sizeof(temp), "../%s", relative);
|
||||||
|
strcpy(relative, temp);
|
||||||
|
|
||||||
|
char* parent = strrchr(search_dir, '/');
|
||||||
|
if (parent == search_dir) {
|
||||||
|
search_dir[1] = '\0';
|
||||||
|
} else if (parent) {
|
||||||
|
*parent = '\0';
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
free(current_dir);
|
||||||
|
free(search_dir);
|
||||||
|
printf("ERROR: you are in no merk repository!\nCreate a new repository with merk init\n");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void normalize_path(char* path, char* rel) {
|
||||||
|
if (strlen(rel) == 0) return;
|
||||||
|
|
||||||
|
size_t path_len = strlen(path);
|
||||||
|
size_t rel_len = strlen(rel);
|
||||||
|
int consumers = rel_len / 3;
|
||||||
|
int counter = 0;
|
||||||
|
size_t latest = 0;
|
||||||
|
|
||||||
|
for (size_t idx = rel_len; idx < path_len; idx++) {
|
||||||
|
if (path[idx] == '/') {
|
||||||
|
counter++;
|
||||||
|
latest = idx;
|
||||||
|
if (counter == consumers) break;
|
||||||
|
}
|
||||||
|
if (path[idx] == '\0') break;
|
||||||
|
}
|
||||||
|
|
||||||
|
strcpy(path, path+latest+(counter > 0 ? 1 : 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
void walk(const char* base, const char* base_rel, const char* rel, PathBuffer* paths) {
|
||||||
|
DIR* dir = opendir(base);
|
||||||
if (!dir) {
|
if (!dir) {
|
||||||
free(dir_full);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -90,33 +171,58 @@ void walk(const char* base, const char* rel, PathBuffer* paths) {
|
||||||
while ((de = readdir(dir)) != NULL) {
|
while ((de = readdir(dir)) != NULL) {
|
||||||
if (is_dot_or_dotdot(de->d_name)) continue;
|
if (is_dot_or_dotdot(de->d_name)) continue;
|
||||||
|
|
||||||
char* child_rel = rel[0] ? join_path(rel, de->d_name) : strdup(de->d_name);
|
char* child_full = join_path(base, de->d_name);
|
||||||
if (!child_rel) {
|
if (!child_full) {
|
||||||
perror("ERROR: memory allocation failed in walk!");
|
perror("ERROR: memory allocation failed in walk!");
|
||||||
closedir(dir);
|
closedir(dir);
|
||||||
free(dir_full);
|
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
char* child_full = join_path(base, child_rel);
|
|
||||||
|
|
||||||
struct stat st;
|
struct stat st;
|
||||||
if (lstat(child_full, &st) != 0) {
|
if (lstat(child_full, &st) != 0) {
|
||||||
free(child_full);
|
free(child_full);
|
||||||
free(child_rel);
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (S_ISDIR(st.st_mode)) {
|
if (S_ISDIR(st.st_mode)) {
|
||||||
walk(base, child_rel, paths);
|
char* new_rel;
|
||||||
|
if (rel && rel[0]) {
|
||||||
|
new_rel = join_path(rel, de->d_name);
|
||||||
} else {
|
} else {
|
||||||
add_path(paths, child_rel);
|
new_rel = strdup(de->d_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!new_rel) {
|
||||||
|
perror("ERROR: memory allocation failed in walk!");
|
||||||
|
free(child_full);
|
||||||
|
closedir(dir);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
walk(child_full, base_rel, new_rel, paths);
|
||||||
|
free(new_rel);
|
||||||
|
} else {
|
||||||
|
char* relative_path;
|
||||||
|
if (rel && rel[0]) {
|
||||||
|
relative_path = join_path(rel, de->d_name);
|
||||||
|
} else {
|
||||||
|
relative_path = strdup(de->d_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!relative_path) {
|
||||||
|
perror("ERROR: memory allocation failed in walk!");
|
||||||
|
free(child_full);
|
||||||
|
closedir(dir);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
normalize_path(relative_path, base_rel);
|
||||||
|
add_path(paths, relative_path);
|
||||||
|
free(relative_path);
|
||||||
}
|
}
|
||||||
|
|
||||||
free(child_rel);
|
|
||||||
free(child_full);
|
free(child_full);
|
||||||
}
|
}
|
||||||
|
|
||||||
closedir(dir);
|
closedir(dir);
|
||||||
free(dir_full);
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue