diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..9851068 --- /dev/null +++ b/Makefile @@ -0,0 +1,11 @@ +CC := gcc +FILES := src/main.c src/args.c src/new.c src/build.c src/run.c + +build: + gcc -o main $(FILES) + sudo cp main /usr/bin/vendetta + rm -fr main + +run: + vendetta new thing + ls diff --git a/README.md b/README.md index bc03bad..f0484c8 100644 --- a/README.md +++ b/README.md @@ -18,8 +18,8 @@ Vendetta uses **git** as the version control system and **make** as the build sy ## Build a project -`vendetta build ` +`vendetta build` ## Build and run a project -`vendetta run ` +`vendetta run` diff --git a/example_project/Makefile b/example_project/Makefile index e69de29..909b43b 100644 --- a/example_project/Makefile +++ b/example_project/Makefile @@ -0,0 +1,15 @@ +CC := gcc +CFLAGS := -Wall -Werror +LIBSPATH := -L/usr/lib/odweta/ +INCLUDEDIR := -I/usr/include/odweta/ +PATCH := -Wl,-rpath=/usr/lib/odweta/ + +.PHONY: build run + +default: build + +build: src/main.c # add files to compile here + @$(CC) $(CFLAGS) -o ./build/$@ $^ $(PATCH) $(INCLUDEDIR) $(LIBSPATH) $(LIBS) + +run: + @./build/main diff --git a/example_project/README.md b/example_project/README.md index e69de29..4c21c86 100644 --- a/example_project/README.md +++ b/example_project/README.md @@ -0,0 +1,3 @@ +# example_project + +Your project description goes here diff --git a/example_project/src/main.c b/example_project/src/main.c index e69de29..9b216a5 100644 --- a/example_project/src/main.c +++ b/example_project/src/main.c @@ -0,0 +1,5 @@ +#include + +int main() { + printf("Hello, world!\n"); +} diff --git a/include/args.h b/include/args.h new file mode 100644 index 0000000..bc04381 --- /dev/null +++ b/include/args.h @@ -0,0 +1,18 @@ +#ifndef ARGS_H +#define ARGS_H + +typedef enum { + NEW, // create a project + BUILD, // build a project + RUN // build and run a project or run a project (is_built is denoted in .vendettaconfig => if true, just run, otherwise build and run) +} meg_e; // mutually_exclusive_group_e; + +typedef struct { + meg_e main_arg; + char* project_name; +} args_t; + + +args_t parse_args(int argc, char** argv); + +#endif diff --git a/include/build.h b/include/build.h new file mode 100644 index 0000000..bf53444 --- /dev/null +++ b/include/build.h @@ -0,0 +1,6 @@ +#ifndef BUILD_H +#define BUILD_H + +void build_project(); + +#endif diff --git a/include/new.h b/include/new.h new file mode 100644 index 0000000..75b54f0 --- /dev/null +++ b/include/new.h @@ -0,0 +1,6 @@ +#ifndef NEW_H +#define NEW_H + +void new_project(char* name); + +#endif diff --git a/include/run.h b/include/run.h new file mode 100644 index 0000000..40443e5 --- /dev/null +++ b/include/run.h @@ -0,0 +1,6 @@ +#ifndef RUN_H +#define RUN_H + +void run_project(); + +#endif diff --git a/src/args.c b/src/args.c new file mode 100644 index 0000000..2372daf --- /dev/null +++ b/src/args.c @@ -0,0 +1,33 @@ +#include "../include/args.h" + +#include +#include +#include + +args_t parse_args(int argc, char** argv) { + if (argc < 2 || argc > 3) { + fprintf(stderr, "invalid number of arguments\n"); + exit(1); + } + + args_t args; + + if (strcmp(argv[1], "new") == 0) { + args.main_arg = NEW; + if (argc != 3) { + fprintf(stderr, "not enough arguments supplied, supply a project name\n"); + exit(1); + } // TODO: add licenses to newly created projects + args.project_name = (char*)malloc(sizeof(argv[2])); + strcpy(args.project_name, argv[2]); + } else if (strcmp(argv[1], "build") == 0) { + args.main_arg = BUILD; + } else if (strcmp(argv[1], "run") == 0) { + args.main_arg = RUN; + } else { + fprintf(stderr, "invalid argument\n"); + exit(1); + } + + return args; +} diff --git a/src/build.c b/src/build.c new file mode 100644 index 0000000..1c8fe94 --- /dev/null +++ b/src/build.c @@ -0,0 +1,135 @@ +#include "../include/build.h" + +#include +#include +#include +#include +#include + +#define MAX(n) n +int src_files_num; + +int count_src_files(char *src_dir) { + int i = 0; + + DIR *d; + struct dirent *dir; + d = opendir(src_dir); // all source (.c) files + if (d) { + while ((dir = readdir(d)) != NULL) { + if (dir->d_type == DT_REG) { + i++; + } + } + closedir(d); + } + + return i; +} + +void load_filenames(char src_files[][1000], char *src_dir) { + int i = 0; + + DIR *d; + struct dirent *dir; + d = opendir(src_dir); // all source (.c) files + if (d) { + while ((dir = readdir(d)) != NULL) { + if (dir->d_type == DT_REG) { + if (i < src_files_num) { + strcpy(src_files[i++], dir->d_name); + } + } + } + closedir(d); + } +} + +char *create_new_makefile(char src_files[][1000]) { + char makefile[999999]; // idk how many + strcpy(makefile, "\ +CC := gcc\n\ +CFLAGS := -Wall -Werror\n\ +LIBSPATH := -L/usr/lib/odweta/\n\ +INCLUDEDIR := -I/usr/include/odweta/\n\ +PATCH := -Wl,-rpath=/usr/lib/odweta/\n\ +\n\ +.PHONY: build run\n\ +\n\ +default: build\n\ +\n\ +build: "); // src/main.c # add files to compile here\n + for (int i = 0; i < src_files_num; i++) { + strcat(makefile, "src/"); + strcat(makefile, src_files[i]); + strcat(makefile, " "); + } + strcat(makefile, "\n\ +\t@$(CC) $(CFLAGS) -o ./build/main $^ $(PATCH) $(INCLUDEDIR) $(LIBSPATH) $(LIBS)\n\ +\n\ +run:\n\ +\t@./build/main\n"); + + char *ptr = makefile; + + return ptr; +} + +void write_new_makefile(char *makefile) { + FILE *fd = fopen("Makefile", "w"); + + fprintf(fd, "%s", makefile); + + fclose(fd); +} + +void save_build_status(int status_code) { + FILE *fd = fopen("./build/.build_status", "w"); + if (!fd) { + fprintf(stderr, "Invalid permissions. Could not open ./build/.build_status " + "for writing.\n"); + } + + fprintf(fd, "%d", status_code); + + fclose(fd); +} + +void build_project() { + /* iterate through all files in the .//src/ directory + * create a new makefile with these files incuded for compilation + * run make + * if the build was successfull -> print something like 'the build was + * successfull' + */ + + char cwd[2048]; + getcwd(cwd, sizeof(cwd)); + + char src_dir[strlen(cwd) + 4 + 1]; + strcpy(src_dir, cwd); + strcat(src_dir, "/src"); + + src_files_num = count_src_files(src_dir); + // printf("%d file(s) found in %s\n", src_files_num, src_dir); + + char src_files[src_files_num][1000]; + + load_filenames(src_files, src_dir); + + for (int i = 0; i < src_files_num; i++) { + // printf("%s\n", src_files[i]); + } + + char *makefile = create_new_makefile(src_files); + + write_new_makefile(makefile); + + if (system("make") == 0) { + printf("The build was successful!\n"); + save_build_status(0); + } else { + printf("An error occured while building.\n"); + save_build_status(1); + } +} diff --git a/src/main.c b/src/main.c new file mode 100644 index 0000000..cf9ed11 --- /dev/null +++ b/src/main.c @@ -0,0 +1,27 @@ +#include "../include/args.h" +#include "../include/build.h" +#include "../include/new.h" +#include "../include/run.h" + +#include +#include + +int main(int argc, char **argv) { + args_t args = parse_args(argc, argv); + + switch (args.main_arg) { + case NEW: + new_project(args.project_name); + break; + case BUILD: + build_project(); + break; + case RUN: + run_project(); + break; + } + + free(args.project_name); + + return 0; +} diff --git a/src/new.c b/src/new.c new file mode 100644 index 0000000..640f2c8 --- /dev/null +++ b/src/new.c @@ -0,0 +1,203 @@ +#include "../include/new.h" + +#include +#include +#include + +typedef struct { + char *main_c; + char *makefile; + char *readme; +} thing_t; + +void main_c(char *name, char *path) { + FILE *fd = fopen(path, "w"); + if (!fd) { + fprintf(stderr, "could not open main.c\n"); + exit(1); + } + + fprintf(fd, "#include \n\nint main() {\n printf(\"Hello, " + "world!\\n\");\n}\n"); + + fclose(fd); +} + +void makefile(char *name, char *path) { + FILE *fd = fopen(path, "w"); + if (!fd) { + fprintf(stderr, "could not open Makefile\n"); + exit(1); + } + + char *payload = "\ +CC := gcc\n\ +CFLAGS := -Wall -Werror\n\ +LIBSPATH := -L/usr/lib/odweta/\n\ +INCLUDEDIR := -I/usr/include/odweta/\n\ +PATCH := -Wl,-rpath=/usr/lib/odweta/\n\ +\n\ +.PHONY: build run\n\ +\n\ +default: build\n\ +\n\ +build: src/main.c # add files to compile here\n\ +\t@$(CC) $(CFLAGS) -o ./build/$@ $^ $(PATCH) $(INCLUDEDIR) $(LIBSPATH) $(LIBS)\n\ +\n\ +run:\n\ +\t@./build/main\n"; + + fprintf(fd, "%s", payload); + + fclose(fd); +} + +void readme(char *name, char *path) { + FILE *fd = fopen(path, "w"); + if (!fd) { + fprintf(stderr, "could not open README.md\n"); + exit(1); + } + + char readme_text[strlen("# ") + strlen(name) + + strlen("\n\nYour project description goes here\n") + 1]; + strcpy(readme_text, "# "); + strcat(readme_text, name); + strcat(readme_text, "\n\nYour project description goes here\n"); + + fprintf(fd, "%s", readme_text); + + fclose(fd); +} + +void fill_in_files(char *name, thing_t thing) { + main_c(name, thing.main_c); + makefile(name, thing.makefile); + readme(name, thing.readme); + // license(name); +} + +void dirs(char *name) { + char mkdir_str[strlen("mkdir -p ./") + strlen(name) + strlen("/src") + 1]; + strcpy(mkdir_str, "mkdir -p ./"); + strcat(mkdir_str, name); + strcat(mkdir_str, "/src"); + + system(mkdir_str); + + char + mkdir_str2[strlen("mkdir -p ./") + strlen(name) + strlen("/include") + 1]; + strcpy(mkdir_str2, "mkdir -p ./"); + strcat(mkdir_str2, name); + strcat(mkdir_str2, "/include"); + + system(mkdir_str2); + + char mkdir_str3[strlen("mkdir -p ./") + strlen(name) + strlen("/build") + 1]; + strcpy(mkdir_str3, "mkdir -p ./"); + strcat(mkdir_str3, name); + strcat(mkdir_str3, "/build"); + + system(mkdir_str3); +} + +void files(char *name) { + char smain_c[] = "/src/main.c"; + char smakefile[] = "/Makefile"; + char sreadme[] = "/README.md"; + char slicense[] = "/LICENSE"; + char sgitignore[] = "/.gitignore"; + + char touch1[strlen("touch ./") + strlen(name) + strlen(smain_c) + 1]; + char touch2[strlen("touch ./") + strlen(name) + strlen(smakefile) + 1]; + char touch3[strlen("touch ./") + strlen(name) + strlen(sreadme) + 1]; + char touch4[strlen("touch ./") + strlen(name) + strlen(slicense) + 1]; + char touch5[strlen("touch ./") + strlen(name) + strlen(sgitignore) + 1]; + + strcpy(touch1, "touch ./"); + strcat(touch1, name); + strcat(touch1, smain_c); + + strcpy(touch2, "touch ./"); + strcat(touch2, name); + strcat(touch2, smakefile); + + strcpy(touch3, "touch ./"); + strcat(touch3, name); + strcat(touch3, sreadme); + + strcpy(touch4, "touch ./"); + strcat(touch4, name); + strcat(touch4, slicense); + + strcpy(touch5, "touch ./"); + strcat(touch5, name); + strcat(touch5, sgitignore); + + system(touch1); + system(touch2); + system(touch3); + system(touch4); + system(touch5); +} + +thing_t create_files(char *name) { + char main_c_path[2 + strlen(name) + 11 + 1]; + char makefile_path[2 + strlen(name) + 9 + 1]; + char readme_path[2 + strlen(name) + 10 + 1]; + + strcpy(main_c_path, "./"); + strcpy(makefile_path, "./"); + strcpy(readme_path, "./"); + + thing_t thing; + + thing.main_c = (char *)malloc(sizeof(main_c_path)); + thing.makefile = (char *)malloc(sizeof(makefile_path)); + thing.readme = (char *)malloc(sizeof(readme_path)); + + strcat(main_c_path, name); + strcat(main_c_path, "/src/main.c"); + + strcat(makefile_path, name); + strcat(makefile_path, "/Makefile"); + + strcat(readme_path, name); + strcat(readme_path, "/README.md"); + + strcpy(thing.main_c, main_c_path); + strcpy(thing.makefile, makefile_path); + strcpy(thing.readme, readme_path); + + dirs(name); + + files(name); + + return thing; +} + +void new_project(char *name) { + thing_t thing = create_files(name); + + char command[strlen("sudo chmod +w .//src/main.c -R") + strlen(name) + 1]; + strcpy(command, "sudo chmod +w ./"); + strcat(command, name); + strcat(command, "/src/main.c"); + + system(command); + + char command2[strlen("sudo chmod +w .//**") + strlen(name) + 1]; + strcpy(command2, "sudo chmod +w ./"); + strcat(command2, name); + strcat(command2, "/**"); + + system(command2); + + fill_in_files( + name, + thing); // fills in stuff like the Makefile with some boilerplate text + + free(thing.main_c); + free(thing.makefile); + free(thing.readme); +} diff --git a/src/run.c b/src/run.c new file mode 100644 index 0000000..083ed65 --- /dev/null +++ b/src/run.c @@ -0,0 +1,30 @@ +#include "../include/run.h" + +#include +#include + +int get_build_status() { + FILE *fd = fopen("./build/.build_status", "r"); + if (!fd) { + fprintf(stderr, "Build the project before running it.\n"); + exit(1); + } + + int i; + fscanf(fd, "%d", &i); + + fclose(fd); + + return i; // max 10 codes (so far only 2 => 0 -> success, 1 -> failure) +} + +void run_project() { + if (get_build_status() == 0) { // success + // file exists => project has been built + system("make run"); + } else { + // file does not exist => project has not been built + printf("Project not yet built. Build it first with 'vendetta build'.\n"); + exit(1); + } +}