From 5301062b0ceaae27ebb8c6fe95ab11b31b4a3eee Mon Sep 17 00:00:00 2001 From: lomna-dev Date: Sat, 13 May 2023 17:30:47 +0530 Subject: [PATCH] Initial Commit First commit --- main.tsk | 8 ++ python-script/tasks | 160 +++++++++++++++++++++++++++ src/tasks.c | 255 ++++++++++++++++++++++++++++++++++++++++++++ test.tsk | 15 +++ 4 files changed, 438 insertions(+) create mode 100644 main.tsk create mode 100755 python-script/tasks create mode 100644 src/tasks.c create mode 100644 test.tsk diff --git a/main.tsk b/main.tsk new file mode 100644 index 0000000..594f0c3 --- /dev/null +++ b/main.tsk @@ -0,0 +1,8 @@ +*Compile +#do +gcc -o tasks tasks.c + +*Test +#do +./tasks test.tsk + diff --git a/python-script/tasks b/python-script/tasks new file mode 100755 index 0000000..afb9e0a --- /dev/null +++ b/python-script/tasks @@ -0,0 +1,160 @@ +#!/usr/bin/python3 + +import sys +import os +import hashlib +import pickle +from subprocess import run + +tasks = [] + +class Task: + name = "" + ifchange = [] + commands = [] + + def show(self): + print(self.name) + print(self.ifchange) + print(self.commands) + + +dragon_ascii = """ + ,, +`""*$b.. + ""*$o. + "$$o. + "*$$o. + "$$$o. + "$$$$bo... ..o: + "$$$$$$$$booocS$$$ .. ,. + ". "*$$$$SP V$o..o$$. .$$$b + "$$o. .$$$$$o. ...A$$$$$$$$$$$$$$b + ""bo. "*$$$$$$$$$$$$$$$$$$$$P*$$$$$$$$: + "$$. V$$$$$$$$$P"**""*"' VP * "l + "$$$o.4$$$$$$$$X + "*$$$$$$$$$$$$$AoA$o..oooooo.. .b + .X$$$$$$$$$$$P"" ""*oo,, ,$P + $$P""V$$$$$$$: . ""*****" + .*" A$$$$$$$$o.4; . + .oP"" "$$$$$$b. .$; + A$$$$$$$$$$P + " "$$$$$P" + $$P*" + mls .$" + " +""" + + +help_message = """ +tasks : +A simple way to define tasks and execute them. + +Usage: tasks file +""" +def print_help(): + """ print help and usage """ + print(dragon_ascii) + print(help_message) + +def check_if_file(in_file, check_file): + """ Checks it the given file exists, else print error and exit """ + if os.path.isfile(check_file): + return True + else: + print("In " + in_file + " : " + check_file + " is not a file") + exit(1) + +def getsha1(filename): + """ Return the sha1 value of the given filename """ + with open(filename, 'rb') as file_to_check: + data = file_to_check.read() + sha1_returned = hashlib.sha1(data).hexdigest() + return sha1_returned + +def do_tasks(tasks_file): + """ Do the tasks stored in tasks list """ + stored_entries = {} + if os.path.isfile("." + tasks_file + ".bin"): + stored_entries = pickle.load(open("." + tasks_file + ".bin", 'rb')) + + for task in tasks: + redo_task = False + + """ If change check """ + for f in task.ifchange: + if stored_entries.get(f, "") != getsha1(f): + stored_entries[f] = getsha1(f) + redo_task = True + + """ Update the stored_entries for this tasks file """ + pickle.dump(stored_entries, open("." + tasks_file + ".bin", 'wb')) + + if len(task.ifchange) < 1: + redo_task = True + + if redo_task == False: + continue + + """ Run Commands of the Task """ + for c in task.commands: + print("+ " + c) + p = run(c.split()) + if p.returncode != 0: + print(p) + print("Task Failed : " + task.name , file=sys.stderr ) + exit(p.returncode) + +def get_tasks(filename): + """ Take a tasks file and convert it to Task structures, stored in a global tasks list """ + number_of_tasks = 0 + # Possible sections : comment, ifchange, commands + current_section = "" + + with open(filename, 'r') as f: + for line in f.readlines(): + l = line.strip() + + if len(l) > 0 and l[0] == '*': + number_of_tasks += 1 + tasks.append(Task()) + tasks[number_of_tasks - 1].name = l[1:].strip() + tasks[number_of_tasks - 1].ifchange = [] + tasks[number_of_tasks - 1].commands = [] + current_section = "comment" + continue + elif l == "#ifchange": + current_section = "ifchange" + continue + elif l == "#do": + current_section = "commands" + continue + + if current_section == "ifchange": + for entry in l.split(): + check_if_file(filename, entry) + tasks[number_of_tasks - 1].ifchange.append(entry) + elif current_section == "commands" and len(l) > 0: + tasks[number_of_tasks - 1].commands.append(l) + +def main(): + tasks_file = "main.tasks" + + if len(sys.argv) > 1: + if os.path.isfile(sys.argv[1]): + tasks_file = sys.argv[1] + else: + print_help() + exit(1) + + get_tasks(tasks_file) + print("<-> <-> <-> <-> <-> <-> <-> <-> <-> <-> <-> <-> <-> <-> <-> <->") + for task in tasks: + print("For task named " + task.name) + task.show() + print("<-> <-> <-> <-> <-> <-> <-> <-> <-> <-> <-> <-> <-> <-> <-> <->") + do_tasks(tasks_file) + +if __name__ == "__main__": + main() + pass diff --git a/src/tasks.c b/src/tasks.c new file mode 100644 index 0000000..c5ee4a8 --- /dev/null +++ b/src/tasks.c @@ -0,0 +1,255 @@ +#include +#include +#include +#include +#include + +#define MAX_TASKS 5 + +typedef enum {false, true} bool; + +typedef struct TASKS_str_linked_list{ + char *data; + struct TASKS_str_linked_list *next; +} TASKS_str_linked_list; + +void TASKS_sll_print(TASKS_str_linked_list *list){ + printf("[ "); + while(list != NULL){ + printf(" %s ,", list->data); + list = list->next; + } + printf(" ]\n"); +} + +//* Takes pointer to linked list head *// +void TASKS_sll_add(TASKS_str_linked_list **list, char *s){ + TASKS_str_linked_list *node = (TASKS_str_linked_list *) malloc(sizeof(TASKS_str_linked_list)); + node->data = s; + node->next = *list; + *list = node; +} + +// The length values will also count \0 +typedef struct TASKS_task{ + char name[100]; + TASKS_str_linked_list *ifchange; + TASKS_str_linked_list *commands; +} TASKS_task; + + +TASKS_task TASKS_new_task(char *name){ + TASKS_task r; + strcpy(r.name, name); + r.ifchange = NULL; + r.commands = NULL; + return r; +} + +void TASKS_delete_task(TASKS_task task){ + // TODO : HERE + // This will need to create functions to free TASKS_str_linked_list + // For a task ifchange list and commands list needs to be freed + // For freeing list, we need to free both strings and the nodes +} + +// We currently keeping a global list of tasks. +int number_of_tasks = 0; +TASKS_task tasks[MAX_TASKS]; + +//* Returns the substring from index x to y (both inclusive) *// +//* The returned string needs to be freed by the caller of the function *// +//* Adds the \0 at end *// +char *TASKS_substr(const char *s, int x, int y){ + assert(y >= x); + char *r = (char *) malloc(sizeof(char) * (y - x + 2)); + + int j = 0; + for(int i = x; i <= y; i++){ + r[j++] = s[i]; + } + + r[j] = '\0'; + return r; +} + +//* Checks if file exists by trying to open it *// +bool TASKS_file_exists(char *filename){ + FILE *f = fopen(filename, "r"); + if(errno == ENOENT) + return false; + else{ + fclose(f); + return true; + } +} + +//* Remove white space before and after a line *// +//* This function works straight on the pointer, so keep a copy if you need orignal line. *// +void TASKS_strip_line(char *line){ + int len = 0; + while(line[len] != '\0') len += 1; + + int start = 0; + int end = len; + + for(int i = 0; i < len; i ++){ + if(line[i] != '\n' && line[i] != '\t' && line[i] != ' ') + break; + start += 1; + } + + for(int i = (len-1); i >= 0; i--){ + if(line[i] != '\n' && line[i] != '\t' && line[i] != ' ') + break; + end = i; + } + + int j = 0; + for(int i = start; i <= end; i++) + line[j++] = line[i]; + line[end - start] = '\0'; +} + +//* Returns true if there are more lines to read, else returns false. *// +bool TASKS_get_line(FILE *f, char *line, int *current_line_capacity){ + if(*current_line_capacity > 1) + line[0] = '\0'; + + char c; + int i = 0; + while(true){ + c = fgetc(f); + + if(c == EOF) + return false; + + if(c == '\n'){ + line[i] = '\0'; + return true; + } + + if(i > *current_line_capacity){ + *current_line_capacity *= 2; + int x = *current_line_capacity; + line = (char *) realloc(line, sizeof(char) * x); + } + + line[i++] = c; + } +} + +void TASKS_get_tasks(char *filename){ + char current_section[10] = "comment"; + int current_line_capacity = 100; + char *current_line = (char *) malloc(sizeof(char) * current_line_capacity); + assert(current_line != NULL); + + FILE *f = fopen(filename, "r"); + assert(f != NULL); + + bool semicolon = true; + while(TASKS_get_line(f, current_line, ¤t_line_capacity)){ + TASKS_strip_line(current_line); + + if(current_line[0] == '\0') continue; + + //* Uncomment to print the file read by program line by line *// + //printf("%s\n", current_line); + + // This length includes the \0 + int current_line_len = 0; + while(current_line[current_line_len++] != '\0'); + + // Setting current section + if(current_line[0] != '\0' && current_line[0] == '*'){ + number_of_tasks += 1; + if(number_of_tasks > MAX_TASKS){ + printf("MAX_TASKS exceeded, increase the number of max tasks in the source file"); + exit(1); + } + + tasks[number_of_tasks - 1] = TASKS_new_task(TASKS_substr(current_line,1,current_line_len - 1)); + strcpy(current_section, "comment"); + continue; + }else if(strcmp(current_line, "#ifchange") == 0){ + strcpy(current_section, "ifchange"); + continue; + }else if(strcmp(current_line, "#do") == 0){ + strcpy(current_section, "commands"); + continue; + } + + // parse file based on current section + if(strcmp(current_section, "ifchange") == 0){ + // TODO : ADD '\ ' to support files with spaces + // We use x and y to get substrings from x-y + int x = 0; + int y = 0; + while(current_line[y++] != '\0'){ + if(current_line[y] == '\n' || current_line[y] == '\t' || current_line[y] == ' '){ + char *to_add = TASKS_substr(current_line, x, y); + TASKS_strip_line(to_add); + TASKS_sll_add(&tasks[number_of_tasks - 1].ifchange, to_add); + x = y; + while(current_line[++y] == '\n' || current_line[y] == '\t' || current_line[y] == ' '); + } + } + char *to_add = TASKS_substr(current_line, x, y); + TASKS_strip_line(to_add); + if(to_add[0] == '\0') continue; + else TASKS_sll_add(&tasks[number_of_tasks - 1].ifchange, to_add); + + }else if(strcmp(current_section, "commands") == 0){ + TASKS_sll_add(&tasks[number_of_tasks - 1].commands, TASKS_substr(current_line, 0, current_line_len - 2)); + } + } + + fclose(f); + free(current_line); +} + +void TASKS_do_all_tasks(){ + for(int i = 0; i < number_of_tasks; i++){ + printf("[*] EXECUTING TASK : %s\n", tasks[i].name); + TASKS_str_linked_list *cll = tasks[i].commands; + while(cll != NULL){ + char *cmd = cll->data; + printf("+ %s\n", cmd); + system(cmd); + cll = cll->next; + } + printf("\n"); + } +} + +int main(int argc, char *argv[]){ + char *tasks_file = "main.tsk"; + + if(argc > 1){ + if(TASKS_file_exists(argv[1])) + tasks_file = argv[1]; + else{ + /* Print Help Here */ + printf("File does not exist"); + exit(ENOENT); + } + } + + assert(TASKS_file_exists(tasks_file)); + + printf("Working on tasks file : %s\n", tasks_file); + TASKS_get_tasks(tasks_file); + + for(int i = 0; i < number_of_tasks; i++){ + printf("\n<-> <-> <-> <-> <-> <-> <-> <-> <-> <-> <-> <-> <-> <-> <-> <->\n\n"); + printf("For task named : %s\n", tasks[i].name); + printf("ifchange : "); TASKS_sll_print(tasks[i].ifchange); + printf("Commands : "); TASKS_sll_print(tasks[i].commands); + } + printf("\n<-> <-> <-> <-> <-> <-> <-> <-> <-> <-> <-> <-> <-> <-> <-> <->\n\n"); + + //* From here we just need to execute all tasks *// + TASKS_do_all_tasks(); + return 0; +} diff --git a/test.tsk b/test.tsk new file mode 100644 index 0000000..2d3ca1a --- /dev/null +++ b/test.tsk @@ -0,0 +1,15 @@ +*Task 1 +#ifchange +testfile1 testfile2 + testfile3 testfile4 +testfile5 +#do +echo HELLO WORLD + +*Task 2 +#ifchange +file1 file2 file3 file4 + file5 file6 + file7 +#do +echo HI WORLD