refactor: Removed PascalCase names.

This commit is contained in:
2026-06-24 17:06:02 -04:00
parent bd39e93785
commit 5bc776dd70
8 changed files with 99 additions and 103 deletions

View File

@@ -2,8 +2,6 @@
1. Commands are still leaking.
2. **db.odin** — Inconsistencies in how struct vs sqlite are named.
3. Add color flag and support non colored output.
4. Rewrite `write_command_help` to use text/tables
@@ -26,8 +24,6 @@
19. Replace `testing.expect` calls with `testing.expect_value` calls where appropriate.
20. Change struct field names from PascalCase to snake_case.
21. procedures should be ordered by use, main at the top, then in the order they are called from main.
22. Shell completion

View File

@@ -7,7 +7,7 @@ import "core:testing"
@(test)
test_find_unbacked_finds_missing :: proc(t: ^testing.T) {
local := []string{"/a/.env", "/b/.env", "/c/.env"}
db := []EnvFile{{Path = "/a/.env"}, {Path = "/b/.env"}}
db := []EnvFile{{path = "/a/.env"}, {path = "/b/.env"}}
result := find_unbacked(local, db[:])
testing.expect(t, len(result) == 1, fmt.tprintf("expected 1 unbacked, got %d", len(result)))
@@ -23,7 +23,7 @@ test_find_unbacked_finds_missing :: proc(t: ^testing.T) {
@(test)
test_find_unbacked_all_backed :: proc(t: ^testing.T) {
local := []string{"/a/.env", "/b/.env"}
db := []EnvFile{{Path = "/a/.env"}, {Path = "/b/.env"}}
db := []EnvFile{{path = "/a/.env"}, {path = "/b/.env"}}
result := find_unbacked(local, db[:])
testing.expect(t, len(result) == 0, fmt.tprintf("expected 0 unbacked, got %d", len(result)))
@@ -32,7 +32,7 @@ test_find_unbacked_all_backed :: proc(t: ^testing.T) {
@(test)
test_find_unbacked_no_local :: proc(t: ^testing.T) {
local: []string
db := []EnvFile{{Path = "/a/.env"}}
db := []EnvFile{{path = "/a/.env"}}
result := find_unbacked(local, db[:])
testing.expect(t, len(result) == 0, fmt.tprintf("expected 0 unbacked, got %d", len(result)))

View File

@@ -9,8 +9,8 @@ import "core:terminal"
import "core:text/table"
ListEntry :: struct {
Directory: string `json:"directory"`,
Path: string `json:"path"`,
dir: string `json:"directory"`,
path: string `json:"path"`,
}
// TODO: Support --format flag
@@ -40,10 +40,10 @@ cmd_list :: proc(cmd: ^Command) {
for row in rows {
dir_str := strings.concatenate(
{row.Dir, os.Path_Separator_String},
{row.dir, os.Path_Separator_String},
context.temp_allocator,
)
filename := filepath.base(row.Path)
filename := filepath.base(row.path)
table.row(&t, dir_str, filename)
}
@@ -53,12 +53,12 @@ cmd_list :: proc(cmd: ^Command) {
// TODO: Should we instead print full entries here?
entries: [dynamic]ListEntry
for row in rows {
filename := filepath.base(row.Path)
filename := filepath.base(row.path)
append(
&entries,
ListEntry {
Directory = strings.concatenate({row.Dir, "/"}, context.temp_allocator),
Path = filename,
dir = strings.concatenate({row.dir, "/"}, context.temp_allocator),
path = filename,
},
)
}

View File

@@ -34,20 +34,20 @@ cmd_restore :: proc(cmd: ^Command) {
return
}
dir := filepath.dir(file.Path)
dir := filepath.dir(file.path)
if err := os.mkdir_all(dir); err != nil {
fmt.wprintf(cmd.err, "Failed to create directory: %v\n", err, flush = false)
return
}
write_err := os.write_entire_file(file.Path, file.contents)
write_err := os.write_entire_file(file.path, file.contents)
if write_err != nil {
fmt.wprintf(cmd.err, "Error writing file: %v\n", write_err, flush = false)
return
}
fmt.wprintf(cmd.out, "Restored %s\n", file.Path, flush = false)
fmt.wprintf(cmd.out, "Restored %s\n", file.path, flush = false)
}

View File

@@ -7,8 +7,8 @@ import "core:terminal"
import "core:text/table"
SyncEntry :: struct {
Path: string `json:"path"`,
Status: string `json:"status"`,
path: string `json:"path"`,
status: string `json:"status"`,
}
// TODO: Check for quiet failures.
@@ -44,8 +44,8 @@ cmd_sync :: proc(cmd: ^Command) {
}
results[i] = SyncEntry {
Path = file.Path,
Status = status,
path = file.path,
status = status,
}
}
@@ -62,7 +62,7 @@ cmd_sync :: proc(cmd: ^Command) {
)
for res in results {
table.row(&t, res.Path, res.Status)
table.row(&t, res.path, res.status)
}
table.write_decorated_table(cmd.out, &t, decorations, ansi_aware_width)

78
db.odin
View File

@@ -39,21 +39,21 @@ Db :: struct {
}
EnvFile :: struct {
Path: string,
Dir: string,
Remotes: [dynamic]string,
Sha256: string,
path: string,
dir: string,
remotes: [dynamic]string,
sha256: string,
contents: string,
}
@(deprecated = "call db_close to clean up EnvFiles")
delete_envfile :: proc(f: ^EnvFile) {
delete(f.Path)
for &remote in f.Remotes {
delete(f.path)
for &remote in f.remotes {
delete(remote)
}
delete(f.Remotes)
delete(f.Sha256)
delete(f.remotes)
delete(f.sha256)
delete(f.contents)
}
@@ -230,10 +230,10 @@ db_list :: proc(db: ^Db) -> ([]EnvFile, bool) {
append(
&results,
EnvFile {
Path = path,
Dir = filepath.dir(path),
Remotes = remotes,
Sha256 = clone_cstring(sqlite.column_text(stmt, 2), allocator),
path = path,
dir = filepath.dir(path),
remotes = remotes,
sha256 = clone_cstring(sqlite.column_text(stmt, 2), allocator),
contents = clone_cstring(sqlite.column_text(stmt, 3), allocator),
},
)
@@ -244,7 +244,7 @@ db_list :: proc(db: ^Db) -> ([]EnvFile, bool) {
// TODO: Should we use context.temp_allocator for proc scoped lifetimes?
db_insert :: proc(db: ^Db, file: EnvFile) -> bool {
remotes_json, marshal_err := json.marshal(file.Remotes, allocator = context.temp_allocator)
remotes_json, marshal_err := json.marshal(file.remotes, allocator = context.temp_allocator)
if marshal_err != nil {
fmt.printf("Error marshaling remotes: %v\n", marshal_err)
return false
@@ -262,7 +262,7 @@ db_insert :: proc(db: ^Db, file: EnvFile) -> bool {
defer sqlite.finalize(stmt)
// TODO: deal with elsewhere?
cpath := to_cstring(file.Path)
cpath := to_cstring(file.path)
defer delete(cpath)
rc = sqlite.bind_text(stmt, 1, cpath, -1, nil)
if rc != sqlite.OK {
@@ -278,7 +278,7 @@ db_insert :: proc(db: ^Db, file: EnvFile) -> bool {
return false
}
csha := to_cstring(file.Sha256)
csha := to_cstring(file.sha256)
defer delete(csha)
rc = sqlite.bind_text(stmt, 3, csha, -1, nil)
if rc != sqlite.OK {
@@ -350,10 +350,10 @@ db_fetch :: proc(db: ^Db, path: string) -> (EnvFile, bool) {
file_path := clone_cstring(sqlite.column_text(stmt, 0), allocator)
return EnvFile {
Path = file_path,
Dir = filepath.dir(file_path),
Remotes = remotes,
Sha256 = clone_cstring(sqlite.column_text(stmt, 2), allocator),
path = file_path,
dir = filepath.dir(file_path),
remotes = remotes,
sha256 = clone_cstring(sqlite.column_text(stmt, 2), allocator),
contents = clone_cstring(sqlite.column_text(stmt, 3), allocator),
},
true
@@ -413,10 +413,10 @@ new_env_file :: proc(path: string) -> (EnvFile, bool) {
digest := hash.hash_bytes(hash.Algorithm.SHA256, data, context.temp_allocator)
hex_bytes := hex.encode(digest, context.allocator)
return EnvFile {
Path = abs_path,
Dir = dir,
Remotes = remotes,
Sha256 = string(hex_bytes),
path = abs_path,
dir = dir,
remotes = remotes,
sha256 = string(hex_bytes),
contents = string(data),
},
true
@@ -426,9 +426,9 @@ new_env_file :: proc(path: string) -> (EnvFile, bool) {
db_sync :: proc(db: ^Db, f: ^EnvFile) -> (SyncFlag, SyncError) {
allocator := db_allocator(db)
result: SyncFlag = {}
old_path := f.Path
old_path := f.path
if !os.exists(f.Dir) {
if !os.exists(f.dir) {
moved, err := try_move_dir(db, f, allocator)
if !moved {
return {}, err
@@ -436,10 +436,10 @@ db_sync :: proc(db: ^Db, f: ^EnvFile) -> (SyncFlag, SyncError) {
result += {.DirUpdated}
}
if !os.exists(f.Path) {
write_err := os.write_entire_file(f.Path, f.contents)
if !os.exists(f.path) {
write_err := os.write_entire_file(f.path, f.contents)
if write_err != nil {
fmt.eprintf("db_sync: failed to write %s: %v\n", f.Path, write_err)
fmt.eprintf("db_sync: failed to write %s: %v\n", f.path, write_err)
return result, .WriteFailed
}
@@ -449,9 +449,9 @@ db_sync :: proc(db: ^Db, f: ^EnvFile) -> (SyncFlag, SyncError) {
return result + {.Restored}, .None
}
data, read_err := os.read_entire_file_from_path(f.Path, allocator)
data, read_err := os.read_entire_file_from_path(f.path, allocator)
if read_err != nil {
fmt.eprintf("db_sync: failed to read %s: %v\n", f.Path, read_err)
fmt.eprintf("db_sync: failed to read %s: %v\n", f.path, read_err)
return result, .ReadFailed
}
@@ -459,7 +459,7 @@ db_sync :: proc(db: ^Db, f: ^EnvFile) -> (SyncFlag, SyncError) {
hex_bytes := hex.encode(digest, allocator)
current_sha := string(hex_bytes)
if current_sha == f.Sha256 {
if current_sha == f.sha256 {
if !db_persist(db, f, old_path) {
return result, .DbFailed
}
@@ -467,7 +467,7 @@ db_sync :: proc(db: ^Db, f: ^EnvFile) -> (SyncFlag, SyncError) {
}
f.contents = string(data)
f.Sha256 = current_sha
f.sha256 = current_sha
if !db_persist(db, f, old_path) {
return result, .DbFailed
}
@@ -475,7 +475,7 @@ db_sync :: proc(db: ^Db, f: ^EnvFile) -> (SyncFlag, SyncError) {
}
db_persist :: proc(db: ^Db, f: ^EnvFile, old_path: string) -> bool {
if f.Path != old_path {
if f.path != old_path {
if !db_delete(db, old_path) {
return false
}
@@ -509,11 +509,11 @@ try_move_dir :: proc(db: ^Db, f: ^EnvFile, allocator: mem.Allocator) -> (bool, S
case 0:
return false, .DirMissing
case 1:
f.Dir, _ = strings.clone(matched_dir, allocator)
base := filepath.base(f.Path)
new_path, _ := filepath.join({f.Dir, base}, allocator)
f.Path = new_path
f.Remotes = get_git_remotes(f.Dir, allocator)
f.dir, _ = strings.clone(matched_dir, allocator)
base := filepath.base(f.path)
new_path, _ := filepath.join({f.dir, base}, allocator)
f.path = new_path
f.remotes = get_git_remotes(f.dir, allocator)
return true, .None
case:
return false, .MultipleDirs
@@ -521,7 +521,7 @@ try_move_dir :: proc(db: ^Db, f: ^EnvFile, allocator: mem.Allocator) -> (bool, S
}
shares_remote :: proc(f: ^EnvFile, remotes: []string) -> bool {
for r1 in f.Remotes {
for r1 in f.remotes {
for r2 in remotes {
if r1 == r2 {
return true

View File

@@ -13,14 +13,14 @@ import "sqlite"
make_test_env_file :: proc(path, sha, contents: string, remotes: []string = {}) -> EnvFile {
f := EnvFile {
Path = path,
Dir = "",
Sha256 = sha,
path = path,
dir = "",
sha256 = sha,
contents = contents,
Remotes = make([dynamic]string, 0, len(remotes), context.temp_allocator),
remotes = make([dynamic]string, 0, len(remotes), context.temp_allocator),
}
for r in remotes {
append(&f.Remotes, r)
append(&f.remotes, r)
}
return f
}
@@ -37,7 +37,7 @@ test_db_insert_and_fetch :: proc(t: ^testing.T) {
contents := "SECRET=value"
f := make_test_env_file(path, sha, contents, []string{"git@github.com:user/repo.git"})
defer delete(f.Remotes)
defer delete(f.remotes)
testing.expect(t, db_insert(&db, f), "insert should succeed")
@@ -46,11 +46,11 @@ test_db_insert_and_fetch :: proc(t: ^testing.T) {
testing.expect(t, fetch_ok, "fetch should succeed")
if !fetch_ok do return
testing.expect_value(t, fetched.Path, path)
testing.expect_value(t, fetched.Sha256, sha)
testing.expect_value(t, fetched.path, path)
testing.expect_value(t, fetched.sha256, sha)
testing.expect_value(t, fetched.contents, contents)
testing.expect_value(t, len(fetched.Remotes), 1)
testing.expect_value(t, fetched.Remotes[0], "git@github.com:user/repo.git")
testing.expect_value(t, len(fetched.remotes), 1)
testing.expect_value(t, fetched.remotes[0], "git@github.com:user/repo.git")
}
@(test)
@@ -71,11 +71,11 @@ test_db_insert_or_replace :: proc(t: ^testing.T) {
testing.expect(t, ok, "failed to create test db")
f1 := make_test_env_file("/project/.env", "sha1", "KEY=old")
defer delete(f1.Remotes)
defer delete(f1.remotes)
testing.expect(t, db_insert(&db, f1), "first insert should succeed")
f2 := make_test_env_file("/project/.env", "sha2", "KEY=new")
defer delete(f2.Remotes)
defer delete(f2.remotes)
testing.expect(t, db_insert(&db, f2), "second insert should succeed")
results, list_ok := db_list(&db)
@@ -89,7 +89,7 @@ test_db_insert_or_replace :: proc(t: ^testing.T) {
// defer delete_envfile(&fetched)
testing.expect_value(t, fetched.contents, "KEY=new")
testing.expect_value(t, fetched.Sha256, "sha2")
testing.expect_value(t, fetched.sha256, "sha2")
}
@(test)
@@ -100,7 +100,7 @@ test_db_delete_existing :: proc(t: ^testing.T) {
defer db_close(&db)
f := make_test_env_file("/project/.env", "sha", "KEY=val")
defer delete(f.Remotes)
defer delete(f.remotes)
db_insert(&db, f)
testing.expect(t, db_delete(&db, "/project/.env"), "delete should return true")
@@ -126,9 +126,9 @@ test_db_list_multiple :: proc(t: ^testing.T) {
defer db_close(&db)
f1 := make_test_env_file("/proj1/.env", "sha1", "A=1", []string{"git@github.com:a/repo.git"})
defer delete(f1.Remotes)
defer delete(f1.remotes)
f2 := make_test_env_file("/proj2/.env", "sha2", "B=2", []string{"git@github.com:b/repo.git"})
defer delete(f2.Remotes)
defer delete(f2.remotes)
f3 := make_test_env_file("/proj3/.env", "sha3", "C=3")
db_insert(&db, f1)
@@ -162,7 +162,7 @@ test_db_insert_sets_changed :: proc(t: ^testing.T) {
testing.expect(t, !db.changed, "changed should start false")
f := make_test_env_file("/project/.env", "sha", "KEY=val")
defer delete(f.Remotes)
defer delete(f.remotes)
db_insert(&db, f)
testing.expect(t, db.changed, "changed should be true after insert")
@@ -176,7 +176,7 @@ test_db_delete_sets_changed :: proc(t: ^testing.T) {
defer db_close(&db)
f := make_test_env_file("/project/.env", "sha", "KEY=val")
defer delete(f.Remotes)
defer delete(f.remotes)
db_insert(&db, f)
db.changed = false
@@ -192,7 +192,7 @@ test_db_serialize :: proc(t: ^testing.T) {
defer db_close(&db)
f := make_test_env_file("/project/.env", "sha", "KEY=val")
defer delete(f.Remotes)
defer delete(f.remotes)
db_insert(&db, f)
sz: i64
@@ -207,10 +207,10 @@ test_db_serialize :: proc(t: ^testing.T) {
@(test)
test_shares_remote_overlap :: proc(t: ^testing.T) {
f := EnvFile {
Remotes = make([dynamic]string, 2, context.temp_allocator),
remotes = make([dynamic]string, 2, context.temp_allocator),
}
append(&f.Remotes, "git@github.com:user/repo.git")
append(&f.Remotes, "git@gitlab.com:user/repo.git")
append(&f.remotes, "git@github.com:user/repo.git")
append(&f.remotes, "git@gitlab.com:user/repo.git")
remotes := []string{"git@github.com:user/repo.git"}
testing.expect(t, shares_remote(&f, remotes), "should share remote")
@@ -219,9 +219,9 @@ test_shares_remote_overlap :: proc(t: ^testing.T) {
@(test)
test_shares_remote_no_overlap :: proc(t: ^testing.T) {
f := EnvFile {
Remotes = make([dynamic]string, 1, context.temp_allocator),
remotes = make([dynamic]string, 1, context.temp_allocator),
}
append(&f.Remotes, "git@github.com:user/repo.git")
append(&f.remotes, "git@github.com:user/repo.git")
remotes := []string{"git@github.com:other/repo.git"}
testing.expect(t, !shares_remote(&f, remotes), "should not share remote")
@@ -230,7 +230,7 @@ test_shares_remote_no_overlap :: proc(t: ^testing.T) {
@(test)
test_shares_remote_empty_file_remotes :: proc(t: ^testing.T) {
f := EnvFile {
Remotes = make([dynamic]string, 0, context.temp_allocator),
remotes = make([dynamic]string, 0, context.temp_allocator),
}
remotes := []string{"git@github.com:user/repo.git"}
@@ -240,9 +240,9 @@ test_shares_remote_empty_file_remotes :: proc(t: ^testing.T) {
@(test)
test_shares_remote_empty_check_remotes :: proc(t: ^testing.T) {
f := EnvFile {
Remotes = make([dynamic]string, 1, context.temp_allocator),
remotes = make([dynamic]string, 1, context.temp_allocator),
}
append(&f.Remotes, "git@github.com:user/repo.git")
append(&f.remotes, "git@github.com:user/repo.git")
remotes: []string
testing.expect(t, !shares_remote(&f, remotes), "empty check remotes should not share")
@@ -251,7 +251,7 @@ test_shares_remote_empty_check_remotes :: proc(t: ^testing.T) {
@(test)
test_shares_remote_both_empty :: proc(t: ^testing.T) {
f := EnvFile {
Remotes = make([dynamic]string, 0),
remotes = make([dynamic]string, 0),
}
remotes: []string
@@ -344,14 +344,14 @@ test_new_env_file :: proc(t: ^testing.T) {
testing.expect(t, ok, "new_env_file should succeed")
if !ok do return
defer delete(file.contents)
defer delete(file.Remotes)
defer delete(file.Sha256)
defer delete(file.Path)
defer delete(file.remotes)
defer delete(file.sha256)
defer delete(file.path)
testing.expect(t, filepath.is_abs(file.Path), "path should be absolute")
testing.expect(t, strings.has_suffix(file.Path, "/.env"), "path should end with /.env")
testing.expect(t, filepath.is_abs(file.path), "path should be absolute")
testing.expect(t, strings.has_suffix(file.path, "/.env"), "path should end with /.env")
testing.expect(t, file.contents == "SECRET=value\n", "contents mismatch")
testing.expect(t, len(file.Sha256) == 64, "sha256 should be 64 hex chars")
testing.expect(t, len(file.sha256) == 64, "sha256 should be 64 hex chars")
}
@(test)
@@ -403,7 +403,7 @@ test_open_existing_db_has_no_leaks :: proc(t: ^testing.T) {
"SECRET=value",
[]string{"git@github.com:user/repo.git"},
)
defer delete(f.Remotes)
defer delete(f.remotes)
testing.expect(t, db_insert(&db, f), "insert should succeed")
db_close(&db)
@@ -437,7 +437,7 @@ test_db_sync_noop :: proc(t: ^testing.T) {
defer db_close(&db)
f := make_test_env_file(env_path, sha, content)
f.Dir = base
f.dir = base
db_insert(&db, f)
result, sync_err := db_sync(&db, &f)
@@ -460,7 +460,7 @@ test_db_sync_backed_up :: proc(t: ^testing.T) {
defer db_close(&db)
f := make_test_env_file(env_path, "old_sha", "KEY=original")
f.Dir = base
f.dir = base
db_insert(&db, f)
result, sync_err := db_sync(&db, &f)
@@ -480,8 +480,8 @@ test_db_sync_restored :: proc(t: ^testing.T) {
defer db_close(&db)
f := make_test_env_file(env_path, "some_sha", "SECRET=value")
f.Dir = base
defer delete(f.Remotes)
f.dir = base
defer delete(f.remotes)
db_insert(&db, f)
result, err := db_sync(&db, &f)
@@ -546,8 +546,8 @@ test_db_sync_moved :: proc(t: ^testing.T) {
testing.expect(t, .Restored in result, "should have Restored flag")
expected_path := fmt.tprintf("%s/.env", repo_dir)
testing.expect_value(t, f.Path, expected_path)
testing.expect_value(t, f.Dir, repo_dir)
testing.expect_value(t, f.path, expected_path)
testing.expect_value(t, f.dir, repo_dir)
_, old_exists := db_fetch(&db, "/old/nonexistent/path/.env")
testing.expect(t, !old_exists, "old path should be deleted from db")

View File

@@ -19,7 +19,7 @@ scan_path :: proc(search_path: string, cfg: Config) -> (paths: [dynamic]string,
find_unbacked :: proc(local_files: []string, db_files: []EnvFile) -> []string {
backed_set := make(map[string]bool, len(db_files), context.temp_allocator)
for file in db_files {
backed_set[file.Path] = true
backed_set[file.path] = true
}
unbacked := make([dynamic]string, 0, len(db_files) / 2, context.temp_allocator)