working parsing of json and stub for parsing commands

This commit is contained in:
Stefan Stefanov 2024-01-18 16:38:37 +02:00
commit 51ec473ee6
7 changed files with 229 additions and 0 deletions

8
.gitignore vendored Normal file
View file

@ -0,0 +1,8 @@
# build and editor ignores
.vscode/
bin/
# Build artefacts
*.exe
*.pdb
*.dSYM

12
Makefile Normal file
View file

@ -0,0 +1,12 @@
build: clean
mkdir -p ./bin/
odin build ./src/ -out:bin/odin_runner.exe -debug
run:
./bin/odin_runner.exe
clean:
rm -rf ./bin/odin_runner.*
nuke:
rm -rf ./bin

40
odin_runner.json Normal file
View file

@ -0,0 +1,40 @@
{
"defaults": {
"collections": [],
"flags": [],
"output_dir": "./bin/",
"binary_name": "binary_name.bin"
},
"configurations": [
{
"release": {
"collections": [
{
"name": "shared",
"path": "./src/"
}
],
"flags": [
"-o:speed",
],
"output_dir": "./bin/release/",
"binary_name": "binary_name_release.bin"
}
},
{
"debug": {
"collections": [
{
"name": "shared",
"path": "./src/"
}
],
"flags": [
"-debug",
],
"output_dir": "./bin/debug/",
"binary_name": "binary_name_debug.bin"
}
}
],
}

11
readme.md Normal file
View file

@ -0,0 +1,11 @@
# Why?
Because I can.
# How to use
Usage:
* `odin_runner` - Run the default command with the defautl configuration (i.e. build with the defaults)
* `odin_runner build` - Same as above
* `odin_runner build debug` - Same as above but with an explicit configuration (`debug`)
* `odin_runner check` - Runs odin check with the defaults
* `odin_runner check debug` - Same as above but with an explicit configuration (`debug`)
* `odin_runner clean debug` - Cleans up build artefacts in the build directory of an explicit configuration (`debug`)

33
src/argument_parser.odin Normal file
View file

@ -0,0 +1,33 @@
package main
import "core:fmt"
import "core:log"
import "core:os"
ECommand :: enum {
BUILD,
CHECK,
CLEAN,
}
BUILD_CMD :: "build"
CHECK_CMD :: "check"
CLEAN_CMD :: "clean"
parse_commands :: proc() {
command : ECommand
args := os.args
binary_name := args[0]
command_string := args[1]
log.infof("args: %v", args)
if command_string == BUILD_CMD {
command = .BUILD
}
if command_string == CHECK_CMD {
command = .CHECK
}
if command_string == CLEAN_CMD {
command = .CLEAN
}
}

114
src/config_parser.odin Normal file
View file

@ -0,0 +1,114 @@
package main
import "core:encoding/json"
import "core:fmt"
import "core:log"
import "core:os"
import "core:strings"
Path :: distinct string // a unix like path (absolute or relative)
CollectionName :: distinct string
TargetName :: distinct string
DEFAULT_TARGET_NAME :: "defaults"
CONFIGURATIONS_KEY :: "configurations"
FLAGS_KEY :: "flags"
OUTPUT_DIR_KEY :: "output_dir"
BINARY_NAME_KEY :: "binary_name"
COLLECTION_NAME_KEY :: "name"
COLLECTION_PATH_KEY :: "path"
// A single config object should hold the configuration for a single target
// i.e. "Release", "Debug", etc...
Config :: struct {
collections: map[CollectionName]Path,
flags: [dynamic]string,
output_dir: Path,
binary_name: string,
configuration_name: TargetName,
}
ConfigurationTargets :: distinct map[TargetName]Config
parse_config :: proc(
config_path: string,
allocator := context.allocator,
) -> (
configs: ConfigurationTargets,
) {
log.infof("Parsing config file: %s", config_path)
ok: bool
settings_json_bytes: []byte
settings_json_bytes, ok = os.read_entire_file(config_path, allocator);if !ok {
log.errorf("Couldn't read settings file: %s", config_path)
return
}
parsed_json_data, parse_err := json.parse(settings_json_bytes);if parse_err != nil {
log.errorf("Failed to parse json data: %v", parse_err)
return
}
root, rok := parsed_json_data.(json.Object);if !rok {
log.errorf("Empty json!")
return
}
defaults_target: json.Object
defaults_target, ok = root[DEFAULT_TARGET_NAME].(json.Object)
if !ok {log.info("No default target in config.")}
configs = make(ConfigurationTargets)
configurations_object, conf_ok := root[CONFIGURATIONS_KEY].(json.Array)
if conf_ok {
for conf_obj in configurations_object {
// log.debugf("Found custom target: %v", conf_obj)
// k: json.String; v: json.Object; conf: json.Object
conf := conf_obj.(json.Object)
for k, v in conf {
conf_name := k
conf_obj_target := v.(json.Object)
configs[TargetName(conf_name)] = parse_target_config(TargetName(conf_name), conf_obj_target)
}
}
} else {log.info("No custom targets in config.")}
// parse the default target configuration
configs[DEFAULT_TARGET_NAME] = parse_target_config(DEFAULT_TARGET_NAME, defaults_target)
return
}
parse_target_config :: proc(name: TargetName, target_obj: json.Object) -> (config: Config) {
log.infof("Parsing custom target: %s", name)
config.configuration_name = name
collections_arr, c_ok := target_obj["collections"].(json.Array)
if c_ok {
for collection in collections_arr {
collection_obj, cc_ok := collection.(json.Object);if cc_ok {
name := collection_obj[COLLECTION_NAME_KEY].(json.String)
path := collection_obj[COLLECTION_PATH_KEY].(json.String)
config.collections[CollectionName(name)] = Path(path)
}
}
}
flags_arr, f_ok := target_obj[FLAGS_KEY].(json.Array)
if f_ok {
for flag in flags_arr {
flag, ff_ok := flag.(json.String);if ff_ok {
append(&config.flags, string(flag))
}
}
}
output_dir, o_ok := target_obj[OUTPUT_DIR_KEY].(json.String)
if o_ok {config.output_dir = Path(output_dir)}
binary_name, b_ok := target_obj[BINARY_NAME_KEY].(json.String)
if b_ok {config.binary_name = binary_name}
return
}

11
src/main.odin Normal file
View file

@ -0,0 +1,11 @@
package main
import "core:log"
main :: proc() {
context.logger = log.create_console_logger()
parse_commands()
targets := parse_config("./odin_runner.json")
log.debug(targets)
}