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:os"
|
||||||
import "core:strings"
|
import "core:strings"
|
||||||
|
|
||||||
|
// -----------------------------------------
|
||||||
|
|
||||||
Options :: struct {
|
Options :: struct {
|
||||||
verbose: bool `args:"name=verbose" usage:"Enable verbose output"`,
|
verbose: bool `args:"name=verbose" usage:"Enable verbose output"`,
|
||||||
compression: u16 `args:"name=compression" usage:"Compression level, 0-12"`,
|
compression: u16 `args:"name=compression" usage:"Compression level, 0-12"`,
|
||||||
@@ -14,25 +16,31 @@ Options :: struct {
|
|||||||
// overflow: [dynamic]string,
|
// overflow: [dynamic]string,
|
||||||
}
|
}
|
||||||
|
|
||||||
parse :: proc(working_dir: string) -> Options {
|
Error :: union #shared_nil {
|
||||||
|
flags.Error,
|
||||||
|
}
|
||||||
|
|
||||||
|
// -----------------------------------------
|
||||||
|
|
||||||
|
parse :: proc(working_dir: string) -> (Options, Error) {
|
||||||
opts: Options
|
opts: Options
|
||||||
|
|
||||||
err := flags.parse(&opts, os.args[1:], .Unix)
|
err := flags.parse(&opts, os.args[1:], .Unix)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
flags.print_errors(typeid_of(Options), err, os.args[0], .Unix)
|
flags.print_errors(typeid_of(Options), err, os.args[0], .Unix)
|
||||||
os.exit(1)
|
return {}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
verify(opts, working_dir)
|
verify(opts, working_dir)
|
||||||
|
|
||||||
return opts
|
return opts, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@(private)
|
@(private)
|
||||||
verify :: proc(opts: Options, working_dir: string) {
|
verify :: proc(opts: Options, working_dir: string) -> Error {
|
||||||
if opts.compression > 12 {
|
if opts.compression > 12 {
|
||||||
throw_error(
|
return throw_error(
|
||||||
`Invalid compression "%d". Compression higher than allowed maximum.`,
|
`Invalid compression "%d". Compression higher than allowed maximum.`,
|
||||||
opts.compression,
|
opts.compression,
|
||||||
)
|
)
|
||||||
@@ -40,13 +48,16 @@ verify :: proc(opts: Options, working_dir: string) {
|
|||||||
|
|
||||||
input_path := os.name(opts.input)
|
input_path := os.name(opts.input)
|
||||||
if !os.is_dir(input_path) {
|
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 {
|
if opts.output != nil {
|
||||||
output_path := os.name(opts.output)
|
output_path := os.name(opts.output)
|
||||||
if !os.is_dir(output_path) {
|
if !os.is_dir(output_path) {
|
||||||
throw_error(
|
return throw_error(
|
||||||
`Invalid output "%v". Should be a directory`,
|
`Invalid output "%v". Should be a directory`,
|
||||||
output_path,
|
output_path,
|
||||||
)
|
)
|
||||||
@@ -54,18 +65,20 @@ verify :: proc(opts: Options, working_dir: string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if !strings.has_prefix(input_path, working_dir) {
|
if !strings.has_prefix(input_path, working_dir) {
|
||||||
throw_error(
|
return throw_error(
|
||||||
`Invalid input "%v". Should be a subdirectory of the working directory.`,
|
`Invalid input "%v". Should be a subdirectory of the working directory.`,
|
||||||
input_path,
|
input_path,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@(private)
|
@(private)
|
||||||
throw_error :: proc(fmt_str: string, args: ..any) {
|
throw_error :: proc(fmt_str: string, args: ..any) -> Error {
|
||||||
err := flags.Validation_Error {
|
err := flags.Validation_Error {
|
||||||
message = fmt.tprintf(fmt_str, ..args),
|
message = fmt.tprintf(fmt_str, ..args),
|
||||||
}
|
}
|
||||||
flags.print_errors(typeid_of(Options), err, os.args[0], .Unix)
|
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)
|
wd, err := os.get_working_directory(allocator)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.eprintln("error: get working directory failed:", err)
|
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,
|
f: ^os.File,
|
||||||
working_dir: string,
|
working_dir: string,
|
||||||
allocator := context.allocator,
|
allocator := context.allocator,
|
||||||
) -> [dynamic]File_Entry {
|
) -> (
|
||||||
|
entries: [dynamic]File_Entry,
|
||||||
|
err: Error,
|
||||||
|
) {
|
||||||
path := os.name(f)
|
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.
|
// 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,
|
path: string,
|
||||||
working_dir: string,
|
working_dir: string,
|
||||||
allocator := context.allocator,
|
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.
|
// Frees every owning relpath string then the dynamic array itself.
|
||||||
@@ -46,10 +62,13 @@ list_dir_recursive_by_path_impl :: proc(
|
|||||||
path: string,
|
path: string,
|
||||||
working_dir: string,
|
working_dir: string,
|
||||||
allocator: runtime.Allocator,
|
allocator: runtime.Allocator,
|
||||||
) -> [dynamic]File_Entry {
|
) -> (
|
||||||
|
[dynamic]File_Entry,
|
||||||
|
Error,
|
||||||
|
) {
|
||||||
if !os.is_dir(path) {
|
if !os.is_dir(path) {
|
||||||
fmt.eprintln("error: path is not a directory:", path)
|
fmt.eprintln("error: path is not a directory:", path)
|
||||||
os.exit(1)
|
return {}, .Not_A_Directory
|
||||||
}
|
}
|
||||||
|
|
||||||
result := make([dynamic]File_Entry, allocator)
|
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)
|
list_dir_queue(&queue, &result, working_dir, allocator)
|
||||||
}
|
}
|
||||||
|
|
||||||
return result // owning [dynamic]
|
return result, nil // owning [dynamic]
|
||||||
}
|
}
|
||||||
|
|
||||||
@(private)
|
@(private)
|
||||||
@@ -71,7 +90,7 @@ list_dir_queue :: proc(
|
|||||||
result: ^[dynamic]File_Entry,
|
result: ^[dynamic]File_Entry,
|
||||||
working_dir: string,
|
working_dir: string,
|
||||||
allocator: runtime.Allocator,
|
allocator: runtime.Allocator,
|
||||||
) {
|
) -> Error {
|
||||||
assert(len(queue) > 0, "queue must not be empty")
|
assert(len(queue) > 0, "queue must not be empty")
|
||||||
|
|
||||||
path := pop(queue)
|
path := pop(queue)
|
||||||
@@ -80,14 +99,14 @@ list_dir_queue :: proc(
|
|||||||
f, open_err := os.open(path, {.Read})
|
f, open_err := os.open(path, {.Read})
|
||||||
if open_err != nil {
|
if open_err != nil {
|
||||||
fmt.eprintln("error: open failed:", open_err)
|
fmt.eprintln("error: open failed:", open_err)
|
||||||
os.exit(1)
|
return open_err
|
||||||
}
|
}
|
||||||
defer os.close(f)
|
defer os.close(f)
|
||||||
|
|
||||||
entries, read_err := os.read_all_directory(f, allocator)
|
entries, read_err := os.read_all_directory(f, allocator)
|
||||||
if read_err != nil {
|
if read_err != nil {
|
||||||
fmt.eprintln("error: read directory failed:", read_err)
|
fmt.eprintln("error: read directory failed:", read_err)
|
||||||
os.exit(1)
|
return read_err
|
||||||
}
|
}
|
||||||
defer os.file_info_slice_delete(entries, allocator)
|
defer os.file_info_slice_delete(entries, allocator)
|
||||||
|
|
||||||
@@ -118,4 +137,6 @@ list_dir_queue :: proc(
|
|||||||
case: // skip other types
|
case: // skip other types
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
+18
-7
@@ -8,39 +8,50 @@ import "src:file"
|
|||||||
|
|
||||||
VERSION :: #config(VERSION, "dev")
|
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() {
|
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)
|
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("verbose:", opts.verbose)
|
||||||
// fmt.println("compression:", opts.compression)
|
// fmt.println("compression:", opts.compression)
|
||||||
// fmt.println("size:", opts.size)
|
// 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)
|
defer file.delete_entries(&entries)
|
||||||
|
|
||||||
w := chunks.writer_init(cast(u64)len(entries))
|
w := chunks.writer_init(cast(u64)len(entries))
|
||||||
defer chunks.writer_destroy(&w)
|
defer chunks.writer_destroy(&w)
|
||||||
|
|
||||||
err := chunks.write_assets(
|
wa_err := chunks.write_assets(
|
||||||
&w,
|
&w,
|
||||||
opts.output,
|
opts.output,
|
||||||
entries[:],
|
entries[:],
|
||||||
opts.size,
|
opts.size,
|
||||||
opts.compression,
|
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,
|
&w,
|
||||||
opts.output,
|
opts.output,
|
||||||
entries[:],
|
entries[:],
|
||||||
opts.size,
|
opts.size,
|
||||||
opts.compression,
|
opts.compression,
|
||||||
)
|
)
|
||||||
if err != nil do os.exit(2)
|
if wm_err != nil do os.exit(WRITE_METADATA_ERR)
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: .chunkignore
|
// TODO: .chunkignore
|
||||||
|
|||||||
Reference in New Issue
Block a user