diff --git a/cli.odin b/cli.odin index 37dc0dd..bdb95e3 100644 --- a/cli.odin +++ b/cli.odin @@ -42,6 +42,7 @@ IMPLEMENTED_COMMANDS := []string{ "backup", "add", "remove", + "restore", } parse_args :: proc() -> (cmd: Command, ok: bool) { diff --git a/cmd_restore.odin b/cmd_restore.odin new file mode 100644 index 0000000..dc92517 --- /dev/null +++ b/cmd_restore.odin @@ -0,0 +1,53 @@ +package main + +import "core:fmt" +import "core:os" +import "core:path/filepath" +import "core:strings" + +cmd_restore :: proc(cmd: ^Command) { + if len(cmd.args) != 1 { + fmt.println("Usage: envr restore ") + return + } + + path := cmd.args[0] + if len(strings.trim_space(path)) == 0 { + fmt.println("Error: No path provided") + return + } + + abs_path: string + if filepath.is_abs(path) { + abs_path = path + } else { + resolved, abs_err := filepath.abs(path) + if abs_err != nil { + fmt.printf("Error getting absolute path: %v\n", abs_err) + return + } + abs_path = resolved + } + + db, db_ok := db_open() + if !db_ok { + return + } + defer db_close(&db) + + file, fetch_ok := db_fetch(&db, abs_path) + if !fetch_ok { + return + } + + dir := filepath.dir(file.Path) + os.mkdir_all(dir) + + write_err := os.write_entire_file(file.Path, file.contents) + if write_err != nil { + fmt.printf("Error writing file: %v\n", write_err) + return + } + + fmt.printf("Restored %s\n", file.Path) +} diff --git a/db.odin b/db.odin index 93ce4c1..1dabc1f 100644 --- a/db.odin +++ b/db.odin @@ -392,6 +392,47 @@ db_insert :: proc(d: ^Db, file: EnvFile) -> bool { return true } +db_fetch :: proc(d: ^Db, path: string) -> (EnvFile, bool) { + sql := "SELECT path, remotes, sha256, contents FROM envr_env_files WHERE path = ?" + stmt: ^rawptr + rc := sqlite.prepare_v2(d.db, string_to_cstring(sql), -1, &stmt, nil) + if rc != sqlite.OK { + fmt.printf("Error preparing fetch: %s\n", sqlite.db_errmsg(d.db)) + return EnvFile{}, false + } + defer sqlite.finalize(stmt) + + rc = sqlite.bind_text(stmt, 1, string_to_cstring(path), -1, nil) + rc = sqlite.step(stmt) + if rc == sqlite.DONE { + fmt.printf("No file found with path: %s\n", path) + return EnvFile{}, false + } + if rc != sqlite.ROW { + fmt.printf("Error fetching: %s\n", sqlite.db_errmsg(d.db)) + return EnvFile{}, false + } + + file_path := cstring_to_string(sqlite.column_text(stmt, 0)) + remotes_json := cstring_to_string(sqlite.column_text(stmt, 1)) + sha := cstring_to_string(sqlite.column_text(stmt, 2)) + contents := cstring_to_string(sqlite.column_text(stmt, 3)) + + remotes: [dynamic]string + if len(remotes_json) > 0 { + json.unmarshal_string(remotes_json, &remotes) + } + + cloned_path, _ := strings.clone(file_path) + return EnvFile{ + Path = cloned_path, + Dir = filepath.dir(cloned_path), + Remotes = remotes, + Sha256 = sha, + contents = contents, + }, true +} + db_delete :: proc(d: ^Db, path: string) -> bool { sql := "DELETE FROM envr_env_files WHERE path = ?" stmt: ^rawptr diff --git a/main.odin b/main.odin index 2df6b02..7abe876 100644 --- a/main.odin +++ b/main.odin @@ -27,6 +27,8 @@ main :: proc() { cmd_backup(&cmd) case "remove": cmd_remove(&cmd) + case "restore": + cmd_restore(&cmd) case: fmt.printf("Unknown command: %s\n", cmd.name) print_usage() diff --git a/stubs.odin b/stubs.odin index 43baa01..a3c61f3 100644 --- a/stubs.odin +++ b/stubs.odin @@ -14,10 +14,6 @@ cmd_sync :: proc(cmd: ^Command) { fmt.println("TODO: sync") } -cmd_restore :: proc(cmd: ^Command) { - fmt.println("TODO: restore") -} - cmd_check :: proc(cmd: ^Command) { fmt.println("TODO: check") }