mirror of
https://github.com/sbrow/envr.git
synced 2026-06-27 18:48:33 -04:00
Compare commits
2 Commits
f6cfb4a98d
...
4f3beb4b64
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4f3beb4b64 | ||
| ba647f51c1 |
@@ -5,7 +5,7 @@
|
|||||||
|
|
||||||
### Features
|
### Features
|
||||||
|
|
||||||
* Replaced `fd` with custom internals. ([1fc5f82](https://github.com/sbrow/envr/commit/1fc5f8280e4a67b67bc14c08eb50ec4334e09cda))
|
* Replaced `fd` with custom internals. ([ba647f5](https://github.com/sbrow/envr/commit/ba647f51c17b694033b4f13c06b38071305cc09d))
|
||||||
|
|
||||||
## [0.3.0](https://github.com/sbrow/envr/compare/v0.2.1...v0.3.0) (2026-06-16)
|
## [0.3.0](https://github.com/sbrow/envr/compare/v0.2.1...v0.3.0) (2026-06-16)
|
||||||
|
|
||||||
|
|||||||
@@ -3,12 +3,7 @@ package findr
|
|||||||
import "core:fmt"
|
import "core:fmt"
|
||||||
import "core:os"
|
import "core:os"
|
||||||
import "core:strings"
|
import "core:strings"
|
||||||
import "core:sync"
|
|
||||||
import "core:sys/linux"
|
import "core:sys/linux"
|
||||||
import "core:thread"
|
|
||||||
|
|
||||||
FINDR_PARALLEL :: #config(FINDR_PARALLEL, false)
|
|
||||||
FINDR_THREADS :: #config(FINDR_THREADS, 8)
|
|
||||||
|
|
||||||
RawEntry :: struct {
|
RawEntry :: struct {
|
||||||
name: string,
|
name: string,
|
||||||
@@ -16,25 +11,28 @@ RawEntry :: struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
walk :: proc(root: string, results: ^[dynamic]string) {
|
walk :: proc(root: string, results: ^[dynamic]string) {
|
||||||
when FINDR_PARALLEL {
|
walk_dir(root, results)
|
||||||
walk_parallel(root, results)
|
|
||||||
} else {
|
|
||||||
walk_dir_serial(root, results)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
read_dir_entries :: proc(dir_path: string, has_git: ^bool) -> [dynamic]RawEntry {
|
walk_dir :: proc(dir_path: string, results: ^[dynamic]string) {
|
||||||
entries := make([dynamic]RawEntry)
|
|
||||||
|
|
||||||
cpath := strings.clone_to_cstring(dir_path)
|
cpath := strings.clone_to_cstring(dir_path)
|
||||||
if cpath == nil do return entries
|
if cpath == nil do return
|
||||||
|
defer delete(cpath)
|
||||||
|
|
||||||
fd, err := linux.open(cpath, {.DIRECTORY, .CLOEXEC})
|
fd, err := linux.open(cpath, {.DIRECTORY, .CLOEXEC})
|
||||||
delete(cpath)
|
if err != .NONE do return
|
||||||
if err != .NONE do return entries
|
defer linux.close(fd)
|
||||||
|
|
||||||
buf: [8192]u8
|
buf: [8192]u8
|
||||||
has_git^ = false
|
has_git := false
|
||||||
|
|
||||||
|
entries := make([dynamic]RawEntry)
|
||||||
|
defer {
|
||||||
|
for &entry in entries {
|
||||||
|
delete(entry.name)
|
||||||
|
}
|
||||||
|
delete(entries)
|
||||||
|
}
|
||||||
|
|
||||||
for {
|
for {
|
||||||
n, errno := linux.getdents(fd, buf[:])
|
n, errno := linux.getdents(fd, buf[:])
|
||||||
@@ -46,7 +44,7 @@ read_dir_entries :: proc(dir_path: string, has_git: ^bool) -> [dynamic]RawEntry
|
|||||||
if name == "." || name == ".." do continue
|
if name == "." || name == ".." do continue
|
||||||
|
|
||||||
if name == ".git" && d.type == .DIR {
|
if name == ".git" && d.type == .DIR {
|
||||||
has_git^ = true
|
has_git = true
|
||||||
}
|
}
|
||||||
|
|
||||||
cloned := strings.clone(name)
|
cloned := strings.clone(name)
|
||||||
@@ -54,22 +52,6 @@ read_dir_entries :: proc(dir_path: string, has_git: ^bool) -> [dynamic]RawEntry
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
linux.close(fd)
|
|
||||||
return entries
|
|
||||||
}
|
|
||||||
|
|
||||||
free_entries :: proc(entries: ^[dynamic]RawEntry) {
|
|
||||||
for &entry in entries {
|
|
||||||
delete(entry.name)
|
|
||||||
}
|
|
||||||
delete(entries^)
|
|
||||||
}
|
|
||||||
|
|
||||||
walk_dir_serial :: proc(dir_path: string, results: ^[dynamic]string) {
|
|
||||||
has_git := false
|
|
||||||
entries := read_dir_entries(dir_path, &has_git)
|
|
||||||
defer free_entries(&entries)
|
|
||||||
|
|
||||||
if has_git {
|
if has_git {
|
||||||
gi := load_gitignore(dir_path)
|
gi := load_gitignore(dir_path)
|
||||||
defer if gi != nil {
|
defer if gi != nil {
|
||||||
@@ -89,7 +71,7 @@ walk_dir_serial :: proc(dir_path: string, results: ^[dynamic]string) {
|
|||||||
}
|
}
|
||||||
if is_dir {
|
if is_dir {
|
||||||
child_path := join_path(dir_path, entry.name)
|
child_path := join_path(dir_path, entry.name)
|
||||||
walk_dir_serial(child_path, results)
|
walk_dir(child_path, results)
|
||||||
delete(child_path)
|
delete(child_path)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -97,7 +79,7 @@ walk_dir_serial :: proc(dir_path: string, results: ^[dynamic]string) {
|
|||||||
for entry in entries {
|
for entry in entries {
|
||||||
if entry.type == .DIR {
|
if entry.type == .DIR {
|
||||||
child_path := join_path(dir_path, entry.name)
|
child_path := join_path(dir_path, entry.name)
|
||||||
walk_dir_serial(child_path, results)
|
walk_dir(child_path, results)
|
||||||
delete(child_path)
|
delete(child_path)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -132,129 +114,3 @@ join_path :: proc(parent, child: string) -> string {
|
|||||||
result, _ := strings.clone(s)
|
result, _ := strings.clone(s)
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
when FINDR_PARALLEL {
|
|
||||||
WalkerPool :: struct {
|
|
||||||
queue: [dynamic]string,
|
|
||||||
queue_mutex: sync.Mutex,
|
|
||||||
queue_sema: sync.Atomic_Sema,
|
|
||||||
results: ^[dynamic]string,
|
|
||||||
results_mutex: sync.Mutex,
|
|
||||||
active: i64,
|
|
||||||
done: sync.One_Shot_Event,
|
|
||||||
threads: [dynamic]^thread.Thread,
|
|
||||||
}
|
|
||||||
|
|
||||||
walk_parallel :: proc(root: string, results: ^[dynamic]string) {
|
|
||||||
pool := new(WalkerPool)
|
|
||||||
pool.queue = make([dynamic]string)
|
|
||||||
pool.results = results
|
|
||||||
pool.active = 1
|
|
||||||
pool.threads = make([dynamic]^thread.Thread)
|
|
||||||
|
|
||||||
root_clone, _ := strings.clone(root)
|
|
||||||
append(&pool.queue, root_clone)
|
|
||||||
sync.atomic_sema_post(&pool.queue_sema)
|
|
||||||
|
|
||||||
num_threads := FINDR_THREADS
|
|
||||||
for i in 0..<num_threads {
|
|
||||||
t := thread.create(walk_worker)
|
|
||||||
t.data = rawptr(pool)
|
|
||||||
t.init_context = context
|
|
||||||
thread.start(t)
|
|
||||||
append(&pool.threads, t)
|
|
||||||
}
|
|
||||||
|
|
||||||
sync.one_shot_event_wait(&pool.done)
|
|
||||||
|
|
||||||
for _ in 0..<num_threads {
|
|
||||||
sync.atomic_sema_post(&pool.queue_sema)
|
|
||||||
}
|
|
||||||
|
|
||||||
for t in pool.threads {
|
|
||||||
thread.destroy(t)
|
|
||||||
}
|
|
||||||
delete(pool.threads)
|
|
||||||
for path in pool.queue {
|
|
||||||
delete(path)
|
|
||||||
}
|
|
||||||
delete(pool.queue)
|
|
||||||
free(pool)
|
|
||||||
}
|
|
||||||
|
|
||||||
push_work :: proc(pool: ^WalkerPool, path: string) {
|
|
||||||
sync.atomic_add_explicit(&pool.active, 1, .Relaxed)
|
|
||||||
sync.mutex_lock(&pool.queue_mutex)
|
|
||||||
append(&pool.queue, path)
|
|
||||||
sync.mutex_unlock(&pool.queue_mutex)
|
|
||||||
sync.atomic_sema_post(&pool.queue_sema)
|
|
||||||
}
|
|
||||||
|
|
||||||
process_dir_parallel :: proc(pool: ^WalkerPool, dir_path: string) {
|
|
||||||
has_git := false
|
|
||||||
entries := read_dir_entries(dir_path, &has_git)
|
|
||||||
defer free_entries(&entries)
|
|
||||||
|
|
||||||
if has_git {
|
|
||||||
gi := load_gitignore(dir_path)
|
|
||||||
defer if gi != nil {
|
|
||||||
destroy(gi)
|
|
||||||
free(gi)
|
|
||||||
}
|
|
||||||
|
|
||||||
for entry in entries {
|
|
||||||
if entry.name == ".git" do continue
|
|
||||||
is_dir := entry.type == .DIR
|
|
||||||
if gi != nil && is_ignored(gi, entry.name, is_dir) {
|
|
||||||
if !is_dir {
|
|
||||||
full_path := join_path(dir_path, entry.name)
|
|
||||||
sync.mutex_lock(&pool.results_mutex)
|
|
||||||
append(pool.results, full_path)
|
|
||||||
sync.mutex_unlock(&pool.results_mutex)
|
|
||||||
}
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if is_dir {
|
|
||||||
child_path := join_path(dir_path, entry.name)
|
|
||||||
push_work(pool, child_path)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
for entry in entries {
|
|
||||||
if entry.type == .DIR {
|
|
||||||
child_path := join_path(dir_path, entry.name)
|
|
||||||
push_work(pool, child_path)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
walk_worker :: proc(t: ^thread.Thread) {
|
|
||||||
pool := cast(^WalkerPool) t.data
|
|
||||||
|
|
||||||
for {
|
|
||||||
sync.atomic_sema_wait(&pool.queue_sema)
|
|
||||||
|
|
||||||
sync.mutex_lock(&pool.queue_mutex)
|
|
||||||
if len(pool.queue) == 0 {
|
|
||||||
sync.mutex_unlock(&pool.queue_mutex)
|
|
||||||
if sync.atomic_load_explicit(&pool.active, .Acquire) == 0 {
|
|
||||||
sync.one_shot_event_signal(&pool.done)
|
|
||||||
}
|
|
||||||
break
|
|
||||||
}
|
|
||||||
last := len(pool.queue) - 1
|
|
||||||
dir_path := pool.queue[last]
|
|
||||||
ordered_remove(&pool.queue, last)
|
|
||||||
sync.mutex_unlock(&pool.queue_mutex)
|
|
||||||
|
|
||||||
process_dir_parallel(pool, dir_path)
|
|
||||||
delete(dir_path)
|
|
||||||
|
|
||||||
old := sync.atomic_sub_explicit(&pool.active, 1, .Release)
|
|
||||||
if old == 1 {
|
|
||||||
sync.one_shot_event_signal(&pool.done)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
Reference in New Issue
Block a user