feat: added a simple filesystem tree walk and the status cli command to get a list of untracked files
This commit is contained in:
parent
8b862f8b87
commit
c372a5f8bc
5 changed files with 174 additions and 7 deletions
|
|
@ -14,15 +14,15 @@ typedef enum {
|
||||||
// Represents a deletion or insertion into the files text
|
// Represents a deletion or insertion into the files text
|
||||||
typedef struct {
|
typedef struct {
|
||||||
ActionType type;
|
ActionType type;
|
||||||
uint64_t line_original;
|
size_t line_original;
|
||||||
uint64_t line_changed;
|
size_t line_changed;
|
||||||
} Action;
|
} Action;
|
||||||
|
|
||||||
// Dynamic array of Actions
|
// Dynamic array of Actions
|
||||||
typedef struct {
|
typedef struct {
|
||||||
Action* actions;
|
Action* actions;
|
||||||
uint64_t capacity;
|
size_t capacity;
|
||||||
uint64_t len;
|
size_t len;
|
||||||
} ActionList;
|
} ActionList;
|
||||||
|
|
||||||
ActionList* new_list();
|
ActionList* new_list();
|
||||||
|
|
|
||||||
24
include/tree.h
Normal file
24
include/tree.h
Normal file
|
|
@ -0,0 +1,24 @@
|
||||||
|
#ifndef TREE_H
|
||||||
|
#define TREE_H
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <dirent.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
char** paths;
|
||||||
|
size_t len;
|
||||||
|
size_t capacity;
|
||||||
|
} PathBuffer;
|
||||||
|
|
||||||
|
PathBuffer* new_path_buffer();
|
||||||
|
void add_path(PathBuffer*, char*);
|
||||||
|
void free_path_buffer(PathBuffer*);
|
||||||
|
char* find_root(const char*);
|
||||||
|
void walk(const char*, const char*, PathBuffer*);
|
||||||
|
|
||||||
|
#endif // TREE_H
|
||||||
|
|
@ -25,7 +25,7 @@ void add_action(ActionList* list, Action action) {
|
||||||
|
|
||||||
// Concatenate two ActionLists. Modifies list1 in place
|
// Concatenate two ActionLists. Modifies list1 in place
|
||||||
void append_list(ActionList* list1, ActionList* list2) {
|
void append_list(ActionList* list1, ActionList* list2) {
|
||||||
uint64_t available_space = list1->capacity - list1->len;
|
size_t available_space = list1->capacity - list1->len;
|
||||||
if (available_space < list2->len) {
|
if (available_space < list2->len) {
|
||||||
list1->capacity += list2->capacity;
|
list1->capacity += list2->capacity;
|
||||||
list1->actions = realloc(list1->actions, list1->capacity*sizeof(Action));
|
list1->actions = realloc(list1->actions, list1->capacity*sizeof(Action));
|
||||||
|
|
|
||||||
25
src/main.c
25
src/main.c
|
|
@ -9,6 +9,7 @@
|
||||||
#include "file.h"
|
#include "file.h"
|
||||||
#include "myers.h"
|
#include "myers.h"
|
||||||
#include "utilities.h"
|
#include "utilities.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");
|
||||||
|
|
@ -22,7 +23,7 @@ int main(int argc, char **argv) {
|
||||||
|
|
||||||
const char* subcmd = argv[1];
|
const char* subcmd = argv[1];
|
||||||
|
|
||||||
if (strcmp(subcmd, "diff") != 0 && strcmp(subcmd, "init") != 0) {
|
if (strcmp(subcmd, "diff") != 0 && strcmp(subcmd, "init") != 0 && strcmp(subcmd, "status") != 0) {
|
||||||
fprintf(stderr, "ERROR: Unknown subcommand: '%s'\n", subcmd);
|
fprintf(stderr, "ERROR: Unknown subcommand: '%s'\n", subcmd);
|
||||||
usage(2);
|
usage(2);
|
||||||
}
|
}
|
||||||
|
|
@ -55,7 +56,7 @@ int main(int argc, char **argv) {
|
||||||
// Prints out a visual representation of the diff of the files provided
|
// Prints out a visual representation of the diff of the files provided
|
||||||
else if (strcmp(subcmd, "diff") == 0) {
|
else if (strcmp(subcmd, "diff") == 0) {
|
||||||
if (argc != 4) {
|
if (argc != 4) {
|
||||||
printf("ERROR: too many/too little arguments given!\n");
|
printf("ERROR: too many/little arguments given!\n");
|
||||||
printf("Usage: merk diff <PATH> <PATH>");
|
printf("Usage: merk diff <PATH> <PATH>");
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
@ -82,6 +83,26 @@ 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 filesystem
|
||||||
|
else if (strcmp(subcmd, "status") == 0) {
|
||||||
|
if (argc != 2) {
|
||||||
|
printf("ERROR: too many arguments given!\n");
|
||||||
|
printf("Usage: merk status");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("Untracked files:\n\n");
|
||||||
|
PathBuffer* files = new_path_buffer();
|
||||||
|
walk(".", "./", files);
|
||||||
|
|
||||||
|
for (size_t i = 0; i < files->len; i++) {
|
||||||
|
printf("%s\n", files->paths[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
free_path_buffer(files);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
else {
|
else {
|
||||||
usage(1);
|
usage(1);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
122
src/tree.c
Normal file
122
src/tree.c
Normal file
|
|
@ -0,0 +1,122 @@
|
||||||
|
#include "tree.h"
|
||||||
|
|
||||||
|
PathBuffer* new_path_buffer() {
|
||||||
|
PathBuffer* buffer = calloc(1, sizeof(PathBuffer));
|
||||||
|
if (!buffer) {
|
||||||
|
perror("ERROR: Failed to allocate PathBuffer");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
buffer->capacity = 10;
|
||||||
|
buffer->len = 0;
|
||||||
|
|
||||||
|
buffer->paths = calloc(buffer->capacity, sizeof(char*));
|
||||||
|
if (!buffer->paths) {
|
||||||
|
perror("ERROR: Failed to allocate paths array");
|
||||||
|
free(buffer);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
void add_path(PathBuffer* buffer, char* path) {
|
||||||
|
if (buffer->len >= buffer->capacity) {
|
||||||
|
buffer->capacity *= 2;
|
||||||
|
char** new_paths = realloc(buffer->paths, buffer->capacity * sizeof(char*));
|
||||||
|
if (!new_paths) {
|
||||||
|
perror("ERROR: PathBuffer realloc failed!");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
buffer->paths = new_paths;
|
||||||
|
}
|
||||||
|
|
||||||
|
char* path_copy = strdup(path);
|
||||||
|
if (!path_copy) {
|
||||||
|
perror("ERROR: strdup failed in add_path!");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
buffer->paths[buffer->len++] = path_copy;
|
||||||
|
}
|
||||||
|
|
||||||
|
void free_path_buffer(PathBuffer* buffer) {
|
||||||
|
if (buffer) {
|
||||||
|
for (size_t i = 0; i < buffer->len; i++) {
|
||||||
|
free(buffer->paths[i]);
|
||||||
|
}
|
||||||
|
free(buffer->paths);
|
||||||
|
free(buffer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int is_dot_or_dotdot(const char* s) {
|
||||||
|
return (s[0] == '.' && (s[1] == '\0' || (s[1] == '.' && s[2] == '\0')));
|
||||||
|
}
|
||||||
|
|
||||||
|
static char* join_path(const char* a, const char* b) {
|
||||||
|
size_t la = strlen(a);
|
||||||
|
size_t lb = strlen(b);
|
||||||
|
int need_sep = (la > 0 && a[la - 1] != '/');
|
||||||
|
|
||||||
|
char* s = calloc(la + (need_sep ? 1 : 0) + lb + 1, sizeof(char));
|
||||||
|
if (!s) {
|
||||||
|
perror("ERROR: calloc failed in join_path!");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(s, a, la);
|
||||||
|
size_t p = la;
|
||||||
|
if (need_sep) s[p++] = '/';
|
||||||
|
memcpy(s + p, b, lb + 1);
|
||||||
|
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
void walk(const char* base, const char* rel, PathBuffer* paths) {
|
||||||
|
char* dir_full = rel[0] ? join_path(base, rel) : strdup(base);
|
||||||
|
if (!dir_full) {
|
||||||
|
perror("ERROR: memory allocation failed in walk!");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
DIR* dir = opendir(dir_full);
|
||||||
|
if (!dir) {
|
||||||
|
free(dir_full);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct dirent* de;
|
||||||
|
while ((de = readdir(dir)) != NULL) {
|
||||||
|
if (is_dot_or_dotdot(de->d_name)) continue;
|
||||||
|
|
||||||
|
char* child_rel = rel[0] ? join_path(rel, de->d_name) : strdup(de->d_name);
|
||||||
|
if (!child_rel) {
|
||||||
|
perror("ERROR: memory allocation failed in walk!");
|
||||||
|
closedir(dir);
|
||||||
|
free(dir_full);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
char* child_full = join_path(base, child_rel);
|
||||||
|
|
||||||
|
struct stat st;
|
||||||
|
if (lstat(child_full, &st) != 0) {
|
||||||
|
free(child_full);
|
||||||
|
free(child_rel);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (S_ISDIR(st.st_mode)) {
|
||||||
|
walk(base, child_rel, paths);
|
||||||
|
} else {
|
||||||
|
add_path(paths, child_rel);
|
||||||
|
}
|
||||||
|
|
||||||
|
free(child_rel);
|
||||||
|
free(child_full);
|
||||||
|
}
|
||||||
|
|
||||||
|
closedir(dir);
|
||||||
|
free(dir_full);
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue