Improve error handling

This commit is contained in:
Riyyi
2026-08-09 21:06:59 +02:00
parent af5db96962
commit 9a4e61626c
9 changed files with 110 additions and 72 deletions
+25
View File
@@ -1,6 +1,7 @@
package chunks
import "base:runtime"
import "core:fmt"
import "core:io"
import "core:os"
@@ -42,3 +43,27 @@ Error :: union #shared_nil {
Read_Error,
Write_Error,
}
// -----------------------------------------
@(require_results)
format_error :: proc(ferr: Error) -> string {
if ferr == nil do return ""
switch e in ferr {
case nil:
return ""
case runtime.Allocator_Error:
return fmt.tprintf("allocator: {}", e)
case io.Error:
return fmt.tprintf("io: {}", e)
case os.Error:
return fmt.tprintf("os: {}", e)
case Read_Error:
return fmt.tprintf("chunks: {}", read_error_strings[e])
case Write_Error:
return fmt.tprintf("chunks: {}", write_error_strings[e])
}
return "unknown error"
}
+2 -2
View File
@@ -30,7 +30,6 @@ read_file :: proc(
// Check filesystem first, so chunks can be overriden
if os.exists(path) {
// Open file
fmt.println("searching:", path)
file := os.open(path, {.Read}) or_return
defer os.close(file)
@@ -92,5 +91,6 @@ read_file :: proc(
return bytes, nil
}
return nil, .File_Not_Exist
fmt.eprintln("asset: ", path)
return nil, .Asset_Not_Exist
}
+10 -1
View File
@@ -14,13 +14,22 @@ Reader :: struct {
Read_Error :: enum u8 {
None = 0,
File_Not_A_Chunk = 1,
File_Not_Exist = 2,
Asset_Not_Exist = 2,
Unimplemented = 127,
Okay = None,
}
// -----------------------------------------
read_error_strings := #sparse[Read_Error]string { // enumerated array
.None = "",
.File_Not_A_Chunk = "file is not a chunk file",
.Asset_Not_Exist = "asset does not exist",
.Unimplemented = "feature is unimplemented",
}
// -----------------------------------------
reader_init :: proc(
output: ^os.File,
allocator := context.allocator,
+17 -30
View File
@@ -26,8 +26,9 @@ write_assets :: proc(
number_of_assets := len(entries)
if size_per_chunk < w.asset_table.data_offset {
fmt.eprintln(
"error: chunk size too small to hold asset index:",
fmt.eprintf(
"chunk size: {}\nasset index size: {}\n",
size_per_chunk,
w.asset_table.data_offset,
)
return .Chunk_Size_Too_Small
@@ -160,22 +161,13 @@ create_new_chunk :: proc(
) or_return
defer delete(chunk_path, allocator)
if os.exists(chunk_path) {
rm_err := os.remove(chunk_path)
if rm_err != nil {
fmt.eprintln("error: remove old chunk failed:", rm_err)
return {}, rm_err
}
os.remove(chunk_path) or_return
}
if w.chunk_file != nil do os.close(w.chunk_file) // close previous
// Create new chunk
cf_err: os.Error
w.chunk_file, cf_err = os.create(chunk_path)
if cf_err != nil {
fmt.eprintln("error: create new chunk failed:", cf_err)
return {}, cf_err
}
w.chunk_file = os.create(chunk_path) or_return
chunk_stream = os.to_stream(w.chunk_file)
@@ -183,34 +175,29 @@ create_new_chunk :: proc(
}
@(private)
open_asset :: proc(w: ^Writer, path: string) -> (io.Stream, u64, Error) {
open_asset :: proc(
w: ^Writer,
path: string,
) -> (
asset_stream: io.Stream,
asset_size: u64,
err: Error,
) {
if w.asset_file != nil do os.close(w.asset_file) // close previous
// Open asset
asset, open_err := os.open(path, {.Read})
if open_err != nil {
fmt.eprintln("error: asset open failed:", open_err)
return {}, {}, open_err
}
asset := os.open(path, {.Read}) or_return
// Asset size
asset_stream := os.to_stream(asset)
asset_size, size_err := io.size(asset_stream)
if size_err != nil {
fmt.eprintln("error: asset size failed:", size_err)
return {}, {}, size_err
}
asset_stream = os.to_stream(asset)
asset_size = cast(u64)io.size(asset_stream) or_return
return asset_stream, cast(u64)asset_size, nil
}
@(private)
write_chunk :: proc(dst: io.Stream, src: io.Stream, n: u64) -> Error {
w, err := io.copy_n(dst, src, cast(i64)n)
if err != nil {
fmt.eprintln("error: chunk write error:", err)
return err
}
w := io.copy_n(dst, src, cast(i64)n) or_return
return nil
}
+5 -17
View File
@@ -24,11 +24,7 @@ write_metadata :: proc(
chunk_path := compute_chunk_path(output_path, 0, allocator) or_return
defer delete(chunk_path, allocator)
chunk_file, err := os.open(chunk_path, {.Read, .Write})
if err != nil {
fmt.eprintln("error: open chunk failed: ", err)
return err
}
chunk_file := os.open(chunk_path, {.Read, .Write}) or_return
defer os.close(chunk_file)
write_header(w, chunk_file, number_of_assets, size_per_chunk, compression)
@@ -62,11 +58,7 @@ write_header :: proc(
// Write header
header_bytes := mem.ptr_to_bytes(&header)
n, err := os.write_at(chunk_file, header_bytes, 0)
if err != nil {
fmt.eprintln("error: chunk write error:", err)
return err
}
n := os.write_at(chunk_file, header_bytes, 0) or_return
return nil
}
@@ -91,7 +83,7 @@ write_asset_index :: proc(
// TODO: Move to cli validation so it happens sooner
path_length := len(f.relpath)
if path_length > 512 {
fmt.eprintln("error: path exeeds maximum of 512:", f.relpath)
fmt.eprintf("path: {} ({})\n", f.relpath, path_length)
return .Path_Too_Large
}
@@ -107,15 +99,11 @@ write_asset_index :: proc(
assert(len(index_bytes) % size_of(Asset_Index) == 0) // clean multiple
// Write asset index
n, err := os.write_at(
n := os.write_at(
chunk_file,
index_bytes,
cast(i64)w.asset_table.asset_index_offset,
)
if err != nil {
fmt.eprintln("error: chunk write error:", err)
return err
}
) or_return
return nil
}
+12 -7
View File
@@ -24,6 +24,15 @@ Write_Error :: enum u8 {
// -----------------------------------------
write_error_strings := #sparse[Write_Error]string { // enumerated array
.None = "",
.Chunk_Size_Too_Small = "chunk size too small to hold asset index",
.Path_Too_Large = "path exeeds maximum of 512",
.Unimplemented = "feature is unimplemented",
}
// -----------------------------------------
writer_init :: proc(
number_of_assets: u64,
allocator := context.allocator,
@@ -55,8 +64,8 @@ compute_chunk_path :: proc(
chunk_index: int,
allocator: runtime.Allocator,
) -> (
string,
Error,
chunk_path: string,
err: Error,
) {
@(static) buf: [20]u8
@@ -65,11 +74,7 @@ compute_chunk_path :: proc(
chunk_name := strings.concatenate({CHUNK, chunk_index_str}, allocator)
defer delete(chunk_name, allocator)
chunk_path, c_err := os.join_path({output_path, chunk_name}, allocator)
if c_err != nil {
fmt.eprintln("error: chunk join path failed:", c_err)
return {}, c_err
}
chunk_path = os.join_path({output_path, chunk_name}, allocator) or_return
return chunk_path, nil // owning string
}
+22
View File
@@ -17,6 +17,12 @@ File_Error :: enum u8 {
Okay = None,
}
file_error_strings := #sparse[File_Error]string { // enumerated array
.None = "",
.Not_A_Directory = "path is not a directory",
.Unimplemented = "feature is unimplemented",
}
// -----------------------------------------
get_working_dir :: proc(allocator := context.allocator) -> (string, Error) {
@@ -28,3 +34,19 @@ get_working_dir :: proc(allocator := context.allocator) -> (string, Error) {
return wd, nil
}
@(require_results)
format_error :: proc(ferr: Error) -> string {
if ferr == nil do return ""
switch e in ferr {
case nil:
return ""
case os.Error:
return fmt.tprintf("os: {}", e)
case File_Error:
return fmt.tprintf("file: {}", file_error_strings[e])
}
return "unknown error"
}
+3 -11
View File
@@ -67,7 +67,7 @@ list_dir_recursive_by_path_impl :: proc(
Error,
) {
if !os.is_dir(path) {
fmt.eprintln("error: path is not a directory:", path)
fmt.eprintln("path:", path)
return {}, .Not_A_Directory
}
@@ -96,18 +96,10 @@ list_dir_queue :: proc(
path := pop(queue)
defer delete(path, queue^.allocator)
f, open_err := os.open(path, {.Read})
if open_err != nil {
fmt.eprintln("error: open failed:", open_err)
return open_err
}
f := os.open(path, {.Read}) or_return
defer os.close(f)
entries, read_err := os.read_all_directory(f, allocator)
if read_err != nil {
fmt.eprintln("error: read directory failed:", read_err)
return read_err
}
entries := os.read_all_directory(f, allocator) or_return
defer os.file_info_slice_delete(entries, allocator)
// Reserve space for new entries, minor waste as directories are also counted.
+14 -4
View File
@@ -1,5 +1,6 @@
package main
import "core:fmt"
import "core:os"
import "src:chunks"
@@ -28,8 +29,11 @@ main :: proc() {
// fmt.println("compression:", opts.compression)
// fmt.println("size:", opts.size)
entries, e_err := file.list_dir_recursive(opts.input, working_dir)
if e_err != nil do os.exit(LIST_DIR_ERR)
entries, ld_err := file.list_dir_recursive(opts.input, working_dir)
if ld_err != nil {
fmt.eprintln("error:", file.format_error(ld_err))
os.exit(LIST_DIR_ERR)
}
defer file.delete_entries(&entries)
w := chunks.writer_init(cast(u64)len(entries))
@@ -42,7 +46,10 @@ main :: proc() {
opts.size,
opts.compression,
)
if wa_err != nil do os.exit(WRITE_ASSETS_ERR)
if wa_err != nil {
fmt.eprintln("error:", chunks.format_error(wa_err))
os.exit(WRITE_ASSETS_ERR)
}
wm_err := chunks.write_metadata(
&w,
@@ -51,7 +58,10 @@ main :: proc() {
opts.size,
opts.compression,
)
if wm_err != nil do os.exit(WRITE_METADATA_ERR)
if wm_err != nil {
fmt.eprintln("error:", chunks.format_error(wm_err))
os.exit(WRITE_METADATA_ERR)
}
}
// TODO: .chunkignore