Improve error handling
This commit is contained in:
@@ -1,6 +1,7 @@
|
|||||||
package chunks
|
package chunks
|
||||||
|
|
||||||
import "base:runtime"
|
import "base:runtime"
|
||||||
|
import "core:fmt"
|
||||||
import "core:io"
|
import "core:io"
|
||||||
import "core:os"
|
import "core:os"
|
||||||
|
|
||||||
@@ -42,3 +43,27 @@ Error :: union #shared_nil {
|
|||||||
Read_Error,
|
Read_Error,
|
||||||
Write_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
|
// Check filesystem first, so chunks can be overriden
|
||||||
if os.exists(path) {
|
if os.exists(path) {
|
||||||
// Open file
|
// Open file
|
||||||
fmt.println("searching:", path)
|
|
||||||
file := os.open(path, {.Read}) or_return
|
file := os.open(path, {.Read}) or_return
|
||||||
defer os.close(file)
|
defer os.close(file)
|
||||||
|
|
||||||
@@ -92,5 +91,6 @@ read_file :: proc(
|
|||||||
return bytes, nil
|
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 {
|
Read_Error :: enum u8 {
|
||||||
None = 0,
|
None = 0,
|
||||||
File_Not_A_Chunk = 1,
|
File_Not_A_Chunk = 1,
|
||||||
File_Not_Exist = 2,
|
Asset_Not_Exist = 2,
|
||||||
Unimplemented = 127,
|
Unimplemented = 127,
|
||||||
Okay = None,
|
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(
|
reader_init :: proc(
|
||||||
output: ^os.File,
|
output: ^os.File,
|
||||||
allocator := context.allocator,
|
allocator := context.allocator,
|
||||||
|
|||||||
@@ -26,8 +26,9 @@ write_assets :: proc(
|
|||||||
number_of_assets := len(entries)
|
number_of_assets := len(entries)
|
||||||
|
|
||||||
if size_per_chunk < w.asset_table.data_offset {
|
if size_per_chunk < w.asset_table.data_offset {
|
||||||
fmt.eprintln(
|
fmt.eprintf(
|
||||||
"error: chunk size too small to hold asset index:",
|
"chunk size: {}\nasset index size: {}\n",
|
||||||
|
size_per_chunk,
|
||||||
w.asset_table.data_offset,
|
w.asset_table.data_offset,
|
||||||
)
|
)
|
||||||
return .Chunk_Size_Too_Small
|
return .Chunk_Size_Too_Small
|
||||||
@@ -160,22 +161,13 @@ create_new_chunk :: proc(
|
|||||||
) or_return
|
) or_return
|
||||||
defer delete(chunk_path, allocator)
|
defer delete(chunk_path, allocator)
|
||||||
if os.exists(chunk_path) {
|
if os.exists(chunk_path) {
|
||||||
rm_err := os.remove(chunk_path)
|
os.remove(chunk_path) or_return
|
||||||
if rm_err != nil {
|
|
||||||
fmt.eprintln("error: remove old chunk failed:", rm_err)
|
|
||||||
return {}, rm_err
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if w.chunk_file != nil do os.close(w.chunk_file) // close previous
|
if w.chunk_file != nil do os.close(w.chunk_file) // close previous
|
||||||
|
|
||||||
// Create new chunk
|
// Create new chunk
|
||||||
cf_err: os.Error
|
w.chunk_file = os.create(chunk_path) or_return
|
||||||
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
|
|
||||||
}
|
|
||||||
|
|
||||||
chunk_stream = os.to_stream(w.chunk_file)
|
chunk_stream = os.to_stream(w.chunk_file)
|
||||||
|
|
||||||
@@ -183,34 +175,29 @@ create_new_chunk :: proc(
|
|||||||
}
|
}
|
||||||
|
|
||||||
@(private)
|
@(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
|
if w.asset_file != nil do os.close(w.asset_file) // close previous
|
||||||
|
|
||||||
// Open asset
|
// Open asset
|
||||||
asset, open_err := os.open(path, {.Read})
|
asset := os.open(path, {.Read}) or_return
|
||||||
if open_err != nil {
|
|
||||||
fmt.eprintln("error: asset open failed:", open_err)
|
|
||||||
return {}, {}, open_err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Asset size
|
// Asset size
|
||||||
asset_stream := os.to_stream(asset)
|
asset_stream = os.to_stream(asset)
|
||||||
asset_size, size_err := io.size(asset_stream)
|
asset_size = cast(u64)io.size(asset_stream) or_return
|
||||||
if size_err != nil {
|
|
||||||
fmt.eprintln("error: asset size failed:", size_err)
|
|
||||||
return {}, {}, size_err
|
|
||||||
}
|
|
||||||
|
|
||||||
return asset_stream, cast(u64)asset_size, nil
|
return asset_stream, cast(u64)asset_size, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@(private)
|
@(private)
|
||||||
write_chunk :: proc(dst: io.Stream, src: io.Stream, n: u64) -> Error {
|
write_chunk :: proc(dst: io.Stream, src: io.Stream, n: u64) -> Error {
|
||||||
w, err := io.copy_n(dst, src, cast(i64)n)
|
w := io.copy_n(dst, src, cast(i64)n) or_return
|
||||||
if err != nil {
|
|
||||||
fmt.eprintln("error: chunk write error:", err)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,11 +24,7 @@ write_metadata :: proc(
|
|||||||
|
|
||||||
chunk_path := compute_chunk_path(output_path, 0, allocator) or_return
|
chunk_path := compute_chunk_path(output_path, 0, allocator) or_return
|
||||||
defer delete(chunk_path, allocator)
|
defer delete(chunk_path, allocator)
|
||||||
chunk_file, err := os.open(chunk_path, {.Read, .Write})
|
chunk_file := os.open(chunk_path, {.Read, .Write}) or_return
|
||||||
if err != nil {
|
|
||||||
fmt.eprintln("error: open chunk failed: ", err)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
defer os.close(chunk_file)
|
defer os.close(chunk_file)
|
||||||
|
|
||||||
write_header(w, chunk_file, number_of_assets, size_per_chunk, compression)
|
write_header(w, chunk_file, number_of_assets, size_per_chunk, compression)
|
||||||
@@ -62,11 +58,7 @@ write_header :: proc(
|
|||||||
|
|
||||||
// Write header
|
// Write header
|
||||||
header_bytes := mem.ptr_to_bytes(&header)
|
header_bytes := mem.ptr_to_bytes(&header)
|
||||||
n, err := os.write_at(chunk_file, header_bytes, 0)
|
n := os.write_at(chunk_file, header_bytes, 0) or_return
|
||||||
if err != nil {
|
|
||||||
fmt.eprintln("error: chunk write error:", err)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -91,7 +83,7 @@ write_asset_index :: proc(
|
|||||||
// TODO: Move to cli validation so it happens sooner
|
// TODO: Move to cli validation so it happens sooner
|
||||||
path_length := len(f.relpath)
|
path_length := len(f.relpath)
|
||||||
if path_length > 512 {
|
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
|
return .Path_Too_Large
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -107,15 +99,11 @@ write_asset_index :: proc(
|
|||||||
assert(len(index_bytes) % size_of(Asset_Index) == 0) // clean multiple
|
assert(len(index_bytes) % size_of(Asset_Index) == 0) // clean multiple
|
||||||
|
|
||||||
// Write asset index
|
// Write asset index
|
||||||
n, err := os.write_at(
|
n := os.write_at(
|
||||||
chunk_file,
|
chunk_file,
|
||||||
index_bytes,
|
index_bytes,
|
||||||
cast(i64)w.asset_table.asset_index_offset,
|
cast(i64)w.asset_table.asset_index_offset,
|
||||||
)
|
) or_return
|
||||||
if err != nil {
|
|
||||||
fmt.eprintln("error: chunk write error:", err)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
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(
|
writer_init :: proc(
|
||||||
number_of_assets: u64,
|
number_of_assets: u64,
|
||||||
allocator := context.allocator,
|
allocator := context.allocator,
|
||||||
@@ -55,8 +64,8 @@ compute_chunk_path :: proc(
|
|||||||
chunk_index: int,
|
chunk_index: int,
|
||||||
allocator: runtime.Allocator,
|
allocator: runtime.Allocator,
|
||||||
) -> (
|
) -> (
|
||||||
string,
|
chunk_path: string,
|
||||||
Error,
|
err: Error,
|
||||||
) {
|
) {
|
||||||
|
|
||||||
@(static) buf: [20]u8
|
@(static) buf: [20]u8
|
||||||
@@ -65,11 +74,7 @@ compute_chunk_path :: proc(
|
|||||||
chunk_name := strings.concatenate({CHUNK, chunk_index_str}, allocator)
|
chunk_name := strings.concatenate({CHUNK, chunk_index_str}, allocator)
|
||||||
defer delete(chunk_name, allocator)
|
defer delete(chunk_name, allocator)
|
||||||
|
|
||||||
chunk_path, c_err := os.join_path({output_path, chunk_name}, allocator)
|
chunk_path = os.join_path({output_path, chunk_name}, allocator) or_return
|
||||||
if c_err != nil {
|
|
||||||
fmt.eprintln("error: chunk join path failed:", c_err)
|
|
||||||
return {}, c_err
|
|
||||||
}
|
|
||||||
|
|
||||||
return chunk_path, nil // owning string
|
return chunk_path, nil // owning string
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,6 +17,12 @@ File_Error :: enum u8 {
|
|||||||
Okay = None,
|
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) {
|
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
|
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,
|
Error,
|
||||||
) {
|
) {
|
||||||
if !os.is_dir(path) {
|
if !os.is_dir(path) {
|
||||||
fmt.eprintln("error: path is not a directory:", path)
|
fmt.eprintln("path:", path)
|
||||||
return {}, .Not_A_Directory
|
return {}, .Not_A_Directory
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -96,18 +96,10 @@ list_dir_queue :: proc(
|
|||||||
path := pop(queue)
|
path := pop(queue)
|
||||||
defer delete(path, queue^.allocator)
|
defer delete(path, queue^.allocator)
|
||||||
|
|
||||||
f, open_err := os.open(path, {.Read})
|
f := os.open(path, {.Read}) or_return
|
||||||
if open_err != nil {
|
|
||||||
fmt.eprintln("error: open failed:", open_err)
|
|
||||||
return open_err
|
|
||||||
}
|
|
||||||
defer os.close(f)
|
defer os.close(f)
|
||||||
|
|
||||||
entries, read_err := os.read_all_directory(f, allocator)
|
entries := os.read_all_directory(f, allocator) or_return
|
||||||
if read_err != nil {
|
|
||||||
fmt.eprintln("error: read directory failed:", read_err)
|
|
||||||
return read_err
|
|
||||||
}
|
|
||||||
defer os.file_info_slice_delete(entries, allocator)
|
defer os.file_info_slice_delete(entries, allocator)
|
||||||
|
|
||||||
// Reserve space for new entries, minor waste as directories are also counted.
|
// Reserve space for new entries, minor waste as directories are also counted.
|
||||||
|
|||||||
+14
-4
@@ -1,5 +1,6 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
|
import "core:fmt"
|
||||||
import "core:os"
|
import "core:os"
|
||||||
|
|
||||||
import "src:chunks"
|
import "src:chunks"
|
||||||
@@ -28,8 +29,11 @@ main :: proc() {
|
|||||||
// fmt.println("compression:", opts.compression)
|
// fmt.println("compression:", opts.compression)
|
||||||
// fmt.println("size:", opts.size)
|
// fmt.println("size:", opts.size)
|
||||||
|
|
||||||
entries, e_err := file.list_dir_recursive(opts.input, working_dir)
|
entries, ld_err := file.list_dir_recursive(opts.input, working_dir)
|
||||||
if e_err != nil do os.exit(LIST_DIR_ERR)
|
if ld_err != nil {
|
||||||
|
fmt.eprintln("error:", file.format_error(ld_err))
|
||||||
|
os.exit(LIST_DIR_ERR)
|
||||||
|
}
|
||||||
defer file.delete_entries(&entries)
|
defer file.delete_entries(&entries)
|
||||||
|
|
||||||
w := chunks.writer_init(cast(u64)len(entries))
|
w := chunks.writer_init(cast(u64)len(entries))
|
||||||
@@ -42,7 +46,10 @@ main :: proc() {
|
|||||||
opts.size,
|
opts.size,
|
||||||
opts.compression,
|
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(
|
wm_err := chunks.write_metadata(
|
||||||
&w,
|
&w,
|
||||||
@@ -51,7 +58,10 @@ main :: proc() {
|
|||||||
opts.size,
|
opts.size,
|
||||||
opts.compression,
|
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
|
// TODO: .chunkignore
|
||||||
|
|||||||
Reference in New Issue
Block a user