Better error handling for list dir and cli
This commit is contained in:
+23
-10
@@ -5,6 +5,8 @@ import "core:fmt"
|
||||
import "core:os"
|
||||
import "core:strings"
|
||||
|
||||
// -----------------------------------------
|
||||
|
||||
Options :: struct {
|
||||
verbose: bool `args:"name=verbose" usage:"Enable verbose output"`,
|
||||
compression: u16 `args:"name=compression" usage:"Compression level, 0-12"`,
|
||||
@@ -14,25 +16,31 @@ Options :: struct {
|
||||
// overflow: [dynamic]string,
|
||||
}
|
||||
|
||||
parse :: proc(working_dir: string) -> Options {
|
||||
Error :: union #shared_nil {
|
||||
flags.Error,
|
||||
}
|
||||
|
||||
// -----------------------------------------
|
||||
|
||||
parse :: proc(working_dir: string) -> (Options, Error) {
|
||||
opts: Options
|
||||
|
||||
err := flags.parse(&opts, os.args[1:], .Unix)
|
||||
|
||||
if err != nil {
|
||||
flags.print_errors(typeid_of(Options), err, os.args[0], .Unix)
|
||||
os.exit(1)
|
||||
return {}, err
|
||||
}
|
||||
|
||||
verify(opts, working_dir)
|
||||
|
||||
return opts
|
||||
return opts, nil
|
||||
}
|
||||
|
||||
@(private)
|
||||
verify :: proc(opts: Options, working_dir: string) {
|
||||
verify :: proc(opts: Options, working_dir: string) -> Error {
|
||||
if opts.compression > 12 {
|
||||
throw_error(
|
||||
return throw_error(
|
||||
`Invalid compression "%d". Compression higher than allowed maximum.`,
|
||||
opts.compression,
|
||||
)
|
||||
@@ -40,13 +48,16 @@ verify :: proc(opts: Options, working_dir: string) {
|
||||
|
||||
input_path := os.name(opts.input)
|
||||
if !os.is_dir(input_path) {
|
||||
throw_error(`Invalid input "%v". Should be a directory`, input_path)
|
||||
return throw_error(
|
||||
`Invalid input "%v". Should be a directory`,
|
||||
input_path,
|
||||
)
|
||||
}
|
||||
|
||||
if opts.output != nil {
|
||||
output_path := os.name(opts.output)
|
||||
if !os.is_dir(output_path) {
|
||||
throw_error(
|
||||
return throw_error(
|
||||
`Invalid output "%v". Should be a directory`,
|
||||
output_path,
|
||||
)
|
||||
@@ -54,18 +65,20 @@ verify :: proc(opts: Options, working_dir: string) {
|
||||
}
|
||||
|
||||
if !strings.has_prefix(input_path, working_dir) {
|
||||
throw_error(
|
||||
return throw_error(
|
||||
`Invalid input "%v". Should be a subdirectory of the working directory.`,
|
||||
input_path,
|
||||
)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@(private)
|
||||
throw_error :: proc(fmt_str: string, args: ..any) {
|
||||
throw_error :: proc(fmt_str: string, args: ..any) -> Error {
|
||||
err := flags.Validation_Error {
|
||||
message = fmt.tprintf(fmt_str, ..args),
|
||||
}
|
||||
flags.print_errors(typeid_of(Options), err, os.args[0], .Unix)
|
||||
os.exit(1)
|
||||
return err
|
||||
}
|
||||
|
||||
+17
-3
@@ -5,12 +5,26 @@ import "core:os"
|
||||
|
||||
// -----------------------------------------
|
||||
|
||||
get_working_dir :: proc(allocator := context.allocator) -> string {
|
||||
Error :: union #shared_nil {
|
||||
os.Error,
|
||||
File_Error,
|
||||
}
|
||||
|
||||
File_Error :: enum u8 {
|
||||
None = 0,
|
||||
Not_A_Directory = 1,
|
||||
Unimplemented = 127,
|
||||
Okay = None,
|
||||
}
|
||||
|
||||
// -----------------------------------------
|
||||
|
||||
get_working_dir :: proc(allocator := context.allocator) -> (string, Error) {
|
||||
wd, err := os.get_working_directory(allocator)
|
||||
if err != nil {
|
||||
fmt.eprintln("error: get working directory failed:", err)
|
||||
os.exit(1)
|
||||
return {}, err
|
||||
}
|
||||
|
||||
return wd
|
||||
return wd, nil
|
||||
}
|
||||
|
||||
+31
-10
@@ -19,9 +19,17 @@ list_dir_recursive :: proc(
|
||||
f: ^os.File,
|
||||
working_dir: string,
|
||||
allocator := context.allocator,
|
||||
) -> [dynamic]File_Entry {
|
||||
) -> (
|
||||
entries: [dynamic]File_Entry,
|
||||
err: Error,
|
||||
) {
|
||||
path := os.name(f)
|
||||
return list_dir_recursive_by_path_impl(path, working_dir, allocator)
|
||||
result := list_dir_recursive_by_path_impl(
|
||||
path,
|
||||
working_dir,
|
||||
allocator,
|
||||
) or_return
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// Returning `[dynamic]File_Entry` and each relpath `string` inside it are owned by the caller.
|
||||
@@ -29,8 +37,16 @@ list_dir_recursive_by_path :: proc(
|
||||
path: string,
|
||||
working_dir: string,
|
||||
allocator := context.allocator,
|
||||
) -> [dynamic]File_Entry {
|
||||
return list_dir_recursive_by_path_impl(path, working_dir, allocator)
|
||||
) -> (
|
||||
entries: [dynamic]File_Entry,
|
||||
err: Error,
|
||||
) {
|
||||
result := list_dir_recursive_by_path_impl(
|
||||
path,
|
||||
working_dir,
|
||||
allocator,
|
||||
) or_return
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// Frees every owning relpath string then the dynamic array itself.
|
||||
@@ -46,10 +62,13 @@ list_dir_recursive_by_path_impl :: proc(
|
||||
path: string,
|
||||
working_dir: string,
|
||||
allocator: runtime.Allocator,
|
||||
) -> [dynamic]File_Entry {
|
||||
) -> (
|
||||
[dynamic]File_Entry,
|
||||
Error,
|
||||
) {
|
||||
if !os.is_dir(path) {
|
||||
fmt.eprintln("error: path is not a directory:", path)
|
||||
os.exit(1)
|
||||
return {}, .Not_A_Directory
|
||||
}
|
||||
|
||||
result := make([dynamic]File_Entry, allocator)
|
||||
@@ -62,7 +81,7 @@ list_dir_recursive_by_path_impl :: proc(
|
||||
list_dir_queue(&queue, &result, working_dir, allocator)
|
||||
}
|
||||
|
||||
return result // owning [dynamic]
|
||||
return result, nil // owning [dynamic]
|
||||
}
|
||||
|
||||
@(private)
|
||||
@@ -71,7 +90,7 @@ list_dir_queue :: proc(
|
||||
result: ^[dynamic]File_Entry,
|
||||
working_dir: string,
|
||||
allocator: runtime.Allocator,
|
||||
) {
|
||||
) -> Error {
|
||||
assert(len(queue) > 0, "queue must not be empty")
|
||||
|
||||
path := pop(queue)
|
||||
@@ -80,14 +99,14 @@ list_dir_queue :: proc(
|
||||
f, open_err := os.open(path, {.Read})
|
||||
if open_err != nil {
|
||||
fmt.eprintln("error: open failed:", open_err)
|
||||
os.exit(1)
|
||||
return open_err
|
||||
}
|
||||
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)
|
||||
os.exit(1)
|
||||
return read_err
|
||||
}
|
||||
defer os.file_info_slice_delete(entries, allocator)
|
||||
|
||||
@@ -118,4 +137,6 @@ list_dir_queue :: proc(
|
||||
case: // skip other types
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
+18
-7
@@ -8,39 +8,50 @@ import "src:file"
|
||||
|
||||
VERSION :: #config(VERSION, "dev")
|
||||
|
||||
CLI_ERR :: 1
|
||||
WORKING_DIR_ERR :: 2
|
||||
LIST_DIR_ERR :: 3
|
||||
WRITE_ASSETS_ERR :: 4
|
||||
WRITE_METADATA_ERR :: 5
|
||||
|
||||
// -----------------------------------------
|
||||
|
||||
main :: proc() {
|
||||
working_dir := file.get_working_dir()
|
||||
working_dir, wd_err := file.get_working_dir()
|
||||
if wd_err != nil do os.exit(WORKING_DIR_ERR)
|
||||
defer delete(working_dir)
|
||||
|
||||
opts := cli.parse(working_dir)
|
||||
opts, c_err := cli.parse(working_dir)
|
||||
if c_err != nil do os.exit(CLI_ERR)
|
||||
|
||||
// fmt.println("verbose:", opts.verbose)
|
||||
// fmt.println("compression:", opts.compression)
|
||||
// fmt.println("size:", opts.size)
|
||||
|
||||
entries := file.list_dir_recursive(opts.input, working_dir)
|
||||
entries, e_err := file.list_dir_recursive(opts.input, working_dir)
|
||||
if e_err != nil do os.exit(LIST_DIR_ERR)
|
||||
defer file.delete_entries(&entries)
|
||||
|
||||
w := chunks.writer_init(cast(u64)len(entries))
|
||||
defer chunks.writer_destroy(&w)
|
||||
|
||||
err := chunks.write_assets(
|
||||
wa_err := chunks.write_assets(
|
||||
&w,
|
||||
opts.output,
|
||||
entries[:],
|
||||
opts.size,
|
||||
opts.compression,
|
||||
)
|
||||
if err != nil do os.exit(1)
|
||||
if wa_err != nil do os.exit(WRITE_ASSETS_ERR)
|
||||
|
||||
chunks.write_metadata(
|
||||
wm_err := chunks.write_metadata(
|
||||
&w,
|
||||
opts.output,
|
||||
entries[:],
|
||||
opts.size,
|
||||
opts.compression,
|
||||
)
|
||||
if err != nil do os.exit(2)
|
||||
if wm_err != nil do os.exit(WRITE_METADATA_ERR)
|
||||
}
|
||||
|
||||
// TODO: .chunkignore
|
||||
|
||||
Reference in New Issue
Block a user