Improve error handling
This commit is contained in:
@@ -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"
|
||||
}
|
||||
|
||||
@@ -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
@@ -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,
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
@@ -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
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user