├── .gitignore ├── go.mod ├── README.md ├── main.go └── tasks └── tasks.go /.gitignore: -------------------------------------------------------------------------------- 1 | tasks.json -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/faztweb/go-crud-cli 2 | 3 | go 1.19 4 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Go CLI CRUD 2 | 3 | This is a simple CLI application using Go that stores data in a JSON file, and do some basic operations like create, read, update and delete. 4 | 5 | # Installation 6 | 7 | ``` 8 | git clone https://github.com/fazt/go-cli-crud 9 | cd go-cli-crud 10 | go install 11 | ``` 12 | -------------------------------------------------------------------------------- /main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "bufio" 5 | "encoding/json" 6 | "fmt" 7 | "io" 8 | "os" 9 | "strconv" 10 | "strings" 11 | 12 | task "github.com/faztweb/go-crud-cli/tasks" 13 | ) 14 | 15 | func main() { 16 | // read or create the tasks.json file 17 | file, err := os.OpenFile("tasks.json", os.O_RDWR|os.O_CREATE, 0666) 18 | if err != nil { 19 | panic(err) 20 | } 21 | defer file.Close() 22 | 23 | var tasks []task.Task 24 | 25 | // get file info 26 | info, err := file.Stat() 27 | 28 | if err != nil { 29 | panic(err) 30 | } 31 | 32 | // check the size 33 | if info.Size() != 0 { 34 | bytes, err := io.ReadAll(file) 35 | if err != nil { 36 | panic(err) 37 | } 38 | err = json.Unmarshal(bytes, &tasks) 39 | if err != nil { 40 | panic(err) 41 | } 42 | } else { 43 | tasks = []task.Task{} 44 | } 45 | 46 | // check the user input and print options to choose 47 | if len(os.Args) < 2 { 48 | printUsage() 49 | return 50 | } 51 | 52 | switch os.Args[1] { 53 | case "list": 54 | task.ListTasks(tasks) 55 | case "add": 56 | reader := bufio.NewReader(os.Stdin) 57 | fmt.Println("Nombre de la tarea:") 58 | name, _ := reader.ReadString('\n') 59 | name = strings.TrimSpace(name) 60 | 61 | tasks = task.AddTask(tasks, name) 62 | task.SaveTasks(file, tasks) 63 | case "complete": 64 | if len(os.Args) < 3 { 65 | fmt.Println("Debe proporcionar el ID de la tarea que se completará.") 66 | return 67 | } 68 | id, err := strconv.Atoi(os.Args[2]) 69 | if err != nil { 70 | fmt.Println("El ID debe ser un número entero.") 71 | return 72 | } 73 | tasks = task.CompleteTask(tasks, id) 74 | task.SaveTasks(file, tasks) 75 | case "delete": 76 | if len(os.Args) < 3 { 77 | fmt.Println("Debe proporcionar el ID de la tarea que se eliminará.") 78 | return 79 | } 80 | id, err := strconv.Atoi(os.Args[2]) 81 | if err != nil { 82 | fmt.Println("El ID debe ser un número entero.") 83 | return 84 | } 85 | tasks = task.DeleteTask(tasks, id) 86 | task.SaveTasks(file, tasks) 87 | default: 88 | printUsage() 89 | } 90 | } 91 | 92 | // Imprimir el uso del programa 93 | func printUsage() { 94 | fmt.Println("Uso: todo [list|add|complete|delete]") 95 | } 96 | -------------------------------------------------------------------------------- /tasks/tasks.go: -------------------------------------------------------------------------------- 1 | package task 2 | 3 | import ( 4 | "bufio" 5 | "encoding/json" 6 | "fmt" 7 | "os" 8 | ) 9 | 10 | type Task struct { 11 | ID int `json:"id"` 12 | Name string `json:"name"` 13 | Complete bool `json:"complete"` 14 | } 15 | 16 | // list all tasks from the array with an icon 17 | func ListTasks(tasks []Task) { 18 | if len(tasks) == 0 { 19 | fmt.Println("No hay tareas.") 20 | return 21 | } 22 | 23 | for _, task := range tasks { 24 | status := " " 25 | if task.Complete { 26 | status = "✓" 27 | } 28 | fmt.Printf("[%s] %d: %s\n", status, task.ID, task.Name) 29 | } 30 | } 31 | 32 | // add a new task to the array 33 | func AddTask(tasks []Task, name string) []Task { 34 | newTask := Task{ 35 | ID: GetNextID(tasks), 36 | Name: name, 37 | Complete: false, 38 | } 39 | return append(tasks, newTask) 40 | } 41 | 42 | // search task with id and mark as completed 43 | func CompleteTask(tasks []Task, id int) []Task { 44 | for i, task := range tasks { 45 | if task.ID == id { 46 | tasks[i].Complete = true 47 | break 48 | } 49 | } 50 | return tasks 51 | } 52 | 53 | // Delete a task with an id 54 | func DeleteTask(tasks []Task, id int) []Task { 55 | for i, task := range tasks { 56 | if task.ID == id { 57 | return append(tasks[:i], tasks[i+1:]...) 58 | } 59 | } 60 | return tasks 61 | } 62 | 63 | // get the next available id for the next task 64 | func GetNextID(tasks []Task) int { 65 | if len(tasks) == 0 { 66 | return 1 67 | } 68 | return tasks[len(tasks)-1].ID + 1 69 | } 70 | 71 | // save all tasks in a json file 72 | func SaveTasks(file *os.File, tasks []Task) { 73 | // convert to a json file 74 | bytes, err := json.Marshal(tasks) 75 | if err != nil { 76 | panic(err) 77 | } 78 | 79 | // move the pointer at the start 80 | _, err = file.Seek(0, 0) 81 | if err != nil { 82 | panic(err) 83 | } 84 | 85 | // clean the entier file or delete everything 86 | err = file.Truncate(0) 87 | if err != nil { 88 | panic(err) 89 | } 90 | 91 | // write the file 92 | writer := bufio.NewWriter(file) 93 | _, err = writer.Write(bytes) 94 | if err != nil { 95 | panic(err) 96 | } 97 | 98 | // make sure the content was written 99 | err = writer.Flush() 100 | if err != nil { 101 | panic(err) 102 | } 103 | } 104 | --------------------------------------------------------------------------------