mirror of
https://github.com/sbrow/envr.git
synced 2026-06-28 02:58:33 -04:00
Compare commits
1 Commits
427a67dcb4
...
a28b8d10bc
| Author | SHA1 | Date | |
|---|---|---|---|
| a28b8d10bc |
@@ -6,6 +6,8 @@ import "core:path/filepath"
|
|||||||
import "core:strings"
|
import "core:strings"
|
||||||
|
|
||||||
cmd_check :: proc(cmd: ^Command) {
|
cmd_check :: proc(cmd: ^Command) {
|
||||||
|
feats := check_features()
|
||||||
|
|
||||||
check_path: string
|
check_path: string
|
||||||
if len(cmd.args) > 0 {
|
if len(cmd.args) > 0 {
|
||||||
check_path = cmd.args[0]
|
check_path = cmd.args[0]
|
||||||
@@ -41,8 +43,10 @@ cmd_check :: proc(cmd: ^Command) {
|
|||||||
files_in_path: [dynamic]string
|
files_in_path: [dynamic]string
|
||||||
|
|
||||||
if is_dir {
|
if is_dir {
|
||||||
if !can_scan() {
|
if cant_scan(feats) {
|
||||||
fmt.println("Error: please install fd to use the check command (https://github.com/sharkdp/fd)")
|
fmt.println(
|
||||||
|
"Error: please install fd to use the check command (https://github.com/sharkdp/fd)",
|
||||||
|
)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -77,3 +81,4 @@ cmd_check :: proc(cmd: ^Command) {
|
|||||||
fmt.println("\nRun 'envr sync' to back up these files.")
|
fmt.println("\nRun 'envr sync' to back up these files.")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -11,7 +11,11 @@ test_find_unbacked_finds_missing :: proc(t: ^testing.T) {
|
|||||||
result := find_unbacked(local, db[:])
|
result := find_unbacked(local, db[:])
|
||||||
testing.expect(t, len(result) == 1, fmt.aprintf("expected 1 unbacked, got %d", len(result)))
|
testing.expect(t, len(result) == 1, fmt.aprintf("expected 1 unbacked, got %d", len(result)))
|
||||||
if len(result) > 0 {
|
if len(result) > 0 {
|
||||||
testing.expect(t, result[0] == "/c/.env", fmt.aprintf("expected /c/.env, got %s", result[0]))
|
testing.expect(
|
||||||
|
t,
|
||||||
|
result[0] == "/c/.env",
|
||||||
|
fmt.aprintf("expected /c/.env, got %s", result[0]),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -41,3 +45,4 @@ test_find_unbacked_none_backed :: proc(t: ^testing.T) {
|
|||||||
result := find_unbacked(local, db[:])
|
result := find_unbacked(local, db[:])
|
||||||
testing.expect(t, len(result) == 2, fmt.aprintf("expected 2 unbacked, got %d", len(result)))
|
testing.expect(t, len(result) == 2, fmt.aprintf("expected 2 unbacked, got %d", len(result)))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,7 +4,8 @@ import "core:encoding/json"
|
|||||||
import "core:fmt"
|
import "core:fmt"
|
||||||
|
|
||||||
cmd_scan :: proc(cmd: ^Command) {
|
cmd_scan :: proc(cmd: ^Command) {
|
||||||
if !can_scan() {
|
feats := check_features()
|
||||||
|
if cant_scan(feats) {
|
||||||
fmt.println(
|
fmt.println(
|
||||||
"Error: please install fd to use the scan command (https://github.com/sharkdp/fd)",
|
"Error: please install fd to use the scan command (https://github.com/sharkdp/fd)",
|
||||||
)
|
)
|
||||||
|
|||||||
108
scan.odin
108
scan.odin
@@ -2,23 +2,49 @@ package main
|
|||||||
|
|
||||||
import "core:fmt"
|
import "core:fmt"
|
||||||
import "core:os"
|
import "core:os"
|
||||||
import "core:path/filepath"
|
|
||||||
import "core:strings"
|
import "core:strings"
|
||||||
import "core:sync"
|
import "core:sync"
|
||||||
|
|
||||||
fd_counter: sync.Atomic_Mutex
|
fd_counter: sync.Atomic_Mutex
|
||||||
fd_seq: int
|
fd_seq: int
|
||||||
|
|
||||||
next_fd_tmp_path :: proc() -> string {
|
// Caller is responsible for freeing paths
|
||||||
sync.atomic_mutex_lock(&fd_counter)
|
scan_path :: proc(search_path: string, cfg: Config) -> (paths: [dynamic]string, ok: bool) {
|
||||||
n := fd_seq
|
if is_tty() {
|
||||||
fd_seq += 1
|
fmt.printf("Searching for all files in \"%s\"...\n", search_path)
|
||||||
sync.atomic_mutex_unlock(&fd_counter)
|
}
|
||||||
return fmt.aprintf("/tmp/envr-fd-%d-%d", os.get_pid(), n)
|
all_files, all_ok := run_fd(build_fd_args(search_path, cfg, true))
|
||||||
|
if !all_ok {
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if is_tty() {
|
||||||
|
fmt.printf("Search for unignored fies in \"%s\"...\n", search_path)
|
||||||
|
}
|
||||||
|
unignored_files, unignored_ok := run_fd(build_fd_args(search_path, cfg, false))
|
||||||
|
if !unignored_ok {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
unignored_set := make(map[string]bool, len(unignored_files), context.temp_allocator)
|
||||||
|
for file in unignored_files {
|
||||||
|
unignored_set[file] = true
|
||||||
|
}
|
||||||
|
|
||||||
|
for file in all_files {
|
||||||
|
if !(file in unignored_set) {
|
||||||
|
append(&paths, file)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ok = true
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
@(private = "file")
|
||||||
build_fd_args :: proc(search_path: string, cfg: Config, include_ignored: bool) -> []string {
|
build_fd_args :: proc(search_path: string, cfg: Config, include_ignored: bool) -> []string {
|
||||||
args := make([dynamic]string, 0, 3 + 2 * len(cfg.ScanConfig.Exclude) + 2)
|
args_len := 3 + 2 * len(cfg.ScanConfig.Exclude) + 2
|
||||||
|
args := make([dynamic]string, 0, args_len, context.temp_allocator)
|
||||||
append(&args, "fd")
|
append(&args, "fd")
|
||||||
append(&args, "-a")
|
append(&args, "-a")
|
||||||
append(&args, cfg.ScanConfig.Matcher)
|
append(&args, cfg.ScanConfig.Matcher)
|
||||||
@@ -38,7 +64,7 @@ build_fd_args :: proc(search_path: string, cfg: Config, include_ignored: bool) -
|
|||||||
return args[:]
|
return args[:]
|
||||||
}
|
}
|
||||||
|
|
||||||
run_fd :: proc(args: []string) -> (lines: [dynamic]string, ok: bool) {
|
run_fd :: proc(args: []string) -> (lines: []string, ok: bool) {
|
||||||
tmp_path := next_fd_tmp_path()
|
tmp_path := next_fd_tmp_path()
|
||||||
tmp_file, tmp_err := os.open(tmp_path, os.O_CREATE | os.O_WRONLY | os.O_TRUNC)
|
tmp_file, tmp_err := os.open(tmp_path, os.O_CREATE | os.O_WRONLY | os.O_TRUNC)
|
||||||
if tmp_err != nil {
|
if tmp_err != nil {
|
||||||
@@ -64,7 +90,7 @@ run_fd :: proc(args: []string) -> (lines: [dynamic]string, ok: bool) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
data, read_err := os.read_entire_file_from_path(tmp_path, context.allocator)
|
data, read_err := os.read_entire_file_from_path(tmp_path, context.temp_allocator)
|
||||||
os.remove(tmp_path)
|
os.remove(tmp_path)
|
||||||
if read_err != nil {
|
if read_err != nil {
|
||||||
return
|
return
|
||||||
@@ -77,69 +103,43 @@ run_fd :: proc(args: []string) -> (lines: [dynamic]string, ok: bool) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
raw_lines := strings.split(output, "\n")
|
raw_lines := strings.split(output, "\n", context.temp_allocator)
|
||||||
|
result := make([dynamic]string, 0, len(raw_lines), context.temp_allocator)
|
||||||
for line in raw_lines {
|
for line in raw_lines {
|
||||||
trimmed, _ := strings.clone(strings.trim_space(line))
|
trimmed := strings.trim_space(line)
|
||||||
if len(trimmed) > 0 {
|
if len(trimmed) > 0 {
|
||||||
append(&lines, trimmed)
|
append(&result, trimmed)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ok = true
|
return result[:], true
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
scan_path :: proc(search_path: string, cfg: Config) -> (paths: [dynamic]string, ok: bool) {
|
@(private = "file")
|
||||||
if is_tty() {
|
next_fd_tmp_path :: proc() -> string {
|
||||||
fmt.printf("Searching for all files in \"%s\"...\n", search_path)
|
sync.atomic_mutex_lock(&fd_counter)
|
||||||
}
|
n := fd_seq
|
||||||
all_args := build_fd_args(search_path, cfg, true)
|
fd_seq += 1
|
||||||
all_files, all_ok := run_fd(all_args)
|
sync.atomic_mutex_unlock(&fd_counter)
|
||||||
if !all_ok {
|
return fmt.aprintf("/tmp/envr-fd-%d-%d", os.get_pid(), n, allocator = context.temp_allocator)
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if is_tty() {
|
cant_scan :: proc(feats: AvailableFeatures) -> bool {
|
||||||
fmt.printf("Search for unignored fies in \"%s\"...\n", search_path)
|
return Feature.Fd not_in feats
|
||||||
}
|
|
||||||
unignored_args := build_fd_args(search_path, cfg, false)
|
|
||||||
unignored_files, unignored_ok := run_fd(unignored_args)
|
|
||||||
if !unignored_ok {
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
unignored_set: map[string]bool
|
find_unbacked :: proc(local_files: []string, db_files: []EnvFile) -> []string {
|
||||||
for file in unignored_files {
|
backed_set := make(map[string]bool, len(db_files), context.temp_allocator)
|
||||||
unignored_set[file] = true
|
|
||||||
}
|
|
||||||
|
|
||||||
for file in all_files {
|
|
||||||
if !(file in unignored_set) {
|
|
||||||
append(&paths, file)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ok = true
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
can_scan :: proc() -> bool {
|
|
||||||
feats := check_features()
|
|
||||||
return Feature.Fd in feats
|
|
||||||
}
|
|
||||||
|
|
||||||
find_unbacked :: proc(local_files: []string, db_files: []EnvFile) -> [dynamic]string {
|
|
||||||
backed_set: map[string]bool
|
|
||||||
for file in db_files {
|
for file in db_files {
|
||||||
backed_set[file.Path] = true
|
backed_set[file.Path] = true
|
||||||
}
|
}
|
||||||
|
|
||||||
unbacked: [dynamic]string
|
unbacked := make([dynamic]string, 0, len(db_files) / 2, context.temp_allocator)
|
||||||
for file in local_files {
|
for file in local_files {
|
||||||
if !(file in backed_set) {
|
if !(file in backed_set) {
|
||||||
append(&unbacked, file)
|
append(&unbacked, file)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return unbacked
|
return unbacked[:]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -7,9 +7,8 @@ import "core:testing"
|
|||||||
|
|
||||||
@(test)
|
@(test)
|
||||||
test_scan_path_finds_gitignored_env_files :: proc(t: ^testing.T) {
|
test_scan_path_finds_gitignored_env_files :: proc(t: ^testing.T) {
|
||||||
if !can_scan() {
|
feats := check_features()
|
||||||
return
|
testing.expect(t, cant_scan(feats) == false)
|
||||||
}
|
|
||||||
|
|
||||||
base := fmt.aprintf("/tmp/envr-scan-test-%d", os.get_pid())
|
base := fmt.aprintf("/tmp/envr-scan-test-%d", os.get_pid())
|
||||||
os.mkdir_all(base)
|
os.mkdir_all(base)
|
||||||
@@ -38,14 +37,11 @@ test_scan_path_finds_gitignored_env_files :: proc(t: ^testing.T) {
|
|||||||
_ = os.write_entire_file(fmt.aprintf("%s/config.yaml", base), "key: value")
|
_ = os.write_entire_file(fmt.aprintf("%s/config.yaml", base), "key: value")
|
||||||
|
|
||||||
cfg := Config {
|
cfg := Config {
|
||||||
ScanConfig = ScanConfig{
|
ScanConfig = ScanConfig{Matcher = "\\.env", Exclude = []string{}, Include = []string{}},
|
||||||
Matcher = "\\.env",
|
|
||||||
Exclude = []string{},
|
|
||||||
Include = []string{},
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
results, ok := scan_path(base, cfg)
|
results, ok := scan_path(base, cfg)
|
||||||
|
defer delete(results)
|
||||||
testing.expect(t, ok, "scan_path should succeed")
|
testing.expect(t, ok, "scan_path should succeed")
|
||||||
|
|
||||||
found_env := false
|
found_env := false
|
||||||
@@ -72,23 +68,20 @@ test_scan_path_finds_gitignored_env_files :: proc(t: ^testing.T) {
|
|||||||
|
|
||||||
@(test)
|
@(test)
|
||||||
test_scan_path_empty_dir :: proc(t: ^testing.T) {
|
test_scan_path_empty_dir :: proc(t: ^testing.T) {
|
||||||
if !can_scan() {
|
feats := check_features()
|
||||||
return
|
testing.expect(t, cant_scan(feats) == false)
|
||||||
}
|
|
||||||
|
|
||||||
base := fmt.aprintf("/tmp/envr-scan-empty-%d", os.get_pid())
|
base := fmt.aprintf("/tmp/envr-scan-empty-%d", os.get_pid())
|
||||||
os.mkdir_all(base)
|
os.mkdir_all(base)
|
||||||
defer os.remove_all(base)
|
defer os.remove_all(base)
|
||||||
|
|
||||||
cfg := Config {
|
cfg := Config {
|
||||||
ScanConfig = ScanConfig{
|
ScanConfig = ScanConfig{Matcher = "\\.env", Exclude = []string{}, Include = []string{}},
|
||||||
Matcher = "\\.env",
|
|
||||||
Exclude = []string{},
|
|
||||||
Include = []string{},
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
results, ok := scan_path(base, cfg)
|
results, ok := scan_path(base, cfg)
|
||||||
|
defer delete(results)
|
||||||
testing.expect(t, ok, "scan_path should succeed")
|
testing.expect(t, ok, "scan_path should succeed")
|
||||||
testing.expect(t, len(results) == 0, fmt.aprintf("expected 0 results, got %d", len(results)))
|
testing.expect(t, len(results) == 0, fmt.aprintf("expected 0 results, got %d", len(results)))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user