2017-07-11 20:29:54 -05:00
|
|
|
// Copyright 2017 Jeremy Wall <jeremy@marzhillstudios.com>
|
|
|
|
//
|
|
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
// you may not use this file except in compliance with the License.
|
|
|
|
// You may obtain a copy of the License at
|
|
|
|
//
|
|
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
//
|
|
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
// See the License for the specific language governing permissions and
|
|
|
|
// limitations under the License.
|
2017-08-12 14:48:28 -05:00
|
|
|
#[macro_use]
|
|
|
|
extern crate clap;
|
2017-05-05 22:33:25 -05:00
|
|
|
extern crate ucglib;
|
|
|
|
|
2018-08-13 23:11:35 -05:00
|
|
|
use std::cell::RefCell;
|
2017-11-15 22:41:55 -06:00
|
|
|
use std::fs::File;
|
|
|
|
use std::io;
|
2018-05-30 22:07:25 -05:00
|
|
|
use std::path::PathBuf;
|
2017-11-15 22:41:55 -06:00
|
|
|
use std::process;
|
2018-05-14 21:34:38 -05:00
|
|
|
use std::rc::Rc;
|
2017-11-15 22:41:55 -06:00
|
|
|
|
2017-08-12 14:48:28 -05:00
|
|
|
use ucglib::build;
|
2018-08-13 23:11:35 -05:00
|
|
|
use ucglib::build::assets::MemoryCache;
|
2018-05-14 21:34:38 -05:00
|
|
|
use ucglib::build::Val;
|
2018-06-18 22:07:18 -05:00
|
|
|
use ucglib::convert::traits;
|
2017-11-15 22:41:55 -06:00
|
|
|
use ucglib::convert::ConverterRunner;
|
2017-08-12 14:48:28 -05:00
|
|
|
|
2017-11-15 22:41:55 -06:00
|
|
|
// TODO(jwall): List the target output types automatically.
|
2017-08-12 14:48:28 -05:00
|
|
|
fn do_flags<'a>() -> clap::ArgMatches<'a> {
|
|
|
|
clap_app!(
|
|
|
|
ucg =>
|
|
|
|
(version: crate_version!())
|
|
|
|
(author: crate_authors!())
|
|
|
|
(about: "Universal Configuration Grammar compiler.")
|
2018-08-15 18:22:05 -05:00
|
|
|
(@subcommand inspect =>
|
|
|
|
(about: "Inspect a specific symbol in a ucg file.")
|
|
|
|
(@arg sym: --sym +takes_value +required "Specify a specific binding in the ucg file to output.")
|
|
|
|
(@arg target: --format +required +takes_value "Inspect output type. (flags, json, env, exec)")
|
|
|
|
(@arg INPUT: +required "Input ucg file to inspect symbol from.")
|
|
|
|
)
|
2017-08-12 14:48:28 -05:00
|
|
|
(@subcommand build =>
|
2018-08-15 18:22:05 -05:00
|
|
|
(about: "Build a specific ucg file.")
|
2017-11-15 22:41:55 -06:00
|
|
|
(@arg out: --out -o +takes_value "Output file to write to.")
|
2018-08-15 18:22:05 -05:00
|
|
|
(@arg INPUT: ... +required "Input ucg files to build.")
|
2017-08-12 14:48:28 -05:00
|
|
|
)
|
|
|
|
(@subcommand validate =>
|
|
|
|
(about: "Check a specific ucg file for errors.")
|
2018-08-15 18:22:05 -05:00
|
|
|
(@arg INPUT: ... +required "Input ucg files to validate.")
|
2017-08-12 14:48:28 -05:00
|
|
|
)
|
2018-02-12 22:52:47 -06:00
|
|
|
).get_matches()
|
2017-08-12 14:48:28 -05:00
|
|
|
}
|
|
|
|
|
2018-06-18 22:07:18 -05:00
|
|
|
fn run_converter(c: ConverterRunner, v: Rc<Val>, f: Option<&str>) -> traits::Result {
|
2018-03-11 08:53:09 -05:00
|
|
|
let file: Box<std::io::Write> = match f {
|
2018-08-15 18:22:05 -05:00
|
|
|
Some(f) => {
|
|
|
|
let mut path_buf = PathBuf::from(f);
|
|
|
|
path_buf.set_extension(c.ext());
|
|
|
|
let new_path = path_buf.to_str().unwrap();
|
|
|
|
Box::new(try!(File::create(&new_path)))
|
|
|
|
}
|
2018-03-11 08:53:09 -05:00
|
|
|
None => Box::new(io::stdout()),
|
|
|
|
};
|
|
|
|
c.convert(v, file)
|
2017-11-15 22:41:55 -06:00
|
|
|
}
|
|
|
|
|
2017-05-05 22:33:25 -05:00
|
|
|
fn main() {
|
2017-08-12 14:48:28 -05:00
|
|
|
let app = do_flags();
|
2018-08-14 16:10:25 -05:00
|
|
|
let cache = Rc::new(RefCell::new(MemoryCache::new()));
|
2018-08-15 18:22:05 -05:00
|
|
|
if let Some(matches) = app.subcommand_matches("inspect") {
|
2017-08-12 14:48:28 -05:00
|
|
|
let file = matches.value_of("INPUT").unwrap();
|
2017-11-15 22:41:55 -06:00
|
|
|
let sym = matches.value_of("sym");
|
|
|
|
let target = matches.value_of("target").unwrap();
|
2018-05-30 22:07:25 -05:00
|
|
|
let root = PathBuf::from(file);
|
2018-08-13 23:11:35 -05:00
|
|
|
let mut builder = build::Builder::new(root.parent().unwrap(), cache);
|
2017-11-29 18:42:33 -06:00
|
|
|
match ConverterRunner::new(target) {
|
2017-11-15 22:41:55 -06:00
|
|
|
Ok(converter) => {
|
2018-08-15 18:49:11 -05:00
|
|
|
// TODO(jwall): We should warn if this is a test file.
|
2017-11-15 22:41:55 -06:00
|
|
|
let result = builder.build_file(file);
|
|
|
|
if !result.is_ok() {
|
2018-05-30 22:07:25 -05:00
|
|
|
eprintln!("{:?}", result.err().unwrap());
|
2017-11-15 22:41:55 -06:00
|
|
|
process::exit(1);
|
|
|
|
}
|
|
|
|
let val = match sym {
|
|
|
|
Some(sym_name) => builder.get_out_by_name(sym_name),
|
|
|
|
None => builder.last,
|
|
|
|
};
|
|
|
|
match val {
|
|
|
|
Some(value) => {
|
2018-08-15 18:22:05 -05:00
|
|
|
// We use None here because we always output to stdout for an inspect.
|
|
|
|
run_converter(converter, value, None).unwrap();
|
2018-03-11 08:53:09 -05:00
|
|
|
eprintln!("Build successful");
|
2017-11-15 22:41:55 -06:00
|
|
|
process::exit(0);
|
|
|
|
}
|
|
|
|
None => {
|
|
|
|
eprintln!("Build results in no value.");
|
|
|
|
process::exit(1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Err(msg) => {
|
|
|
|
eprintln!("{}", msg);
|
|
|
|
process::exit(1);
|
|
|
|
}
|
2017-11-29 18:42:33 -06:00
|
|
|
}
|
2018-08-15 18:22:05 -05:00
|
|
|
} else if let Some(matches) = app.subcommand_matches("build") {
|
|
|
|
let files = matches.values_of("INPUT").unwrap();
|
|
|
|
for file in files {
|
|
|
|
let root = PathBuf::from(file);
|
|
|
|
let mut builder = build::Builder::new(root.parent().unwrap(), cache);
|
|
|
|
let result = builder.build_file(file);
|
|
|
|
if !result.is_ok() {
|
|
|
|
eprintln!("{:?}", result.err().unwrap());
|
|
|
|
process::exit(1);
|
|
|
|
}
|
|
|
|
let (typ, val) = match builder.out_lock {
|
|
|
|
Some((ref typ, ref val)) => (typ, val.clone()),
|
|
|
|
None => {
|
|
|
|
eprintln!("Build results in no value.");
|
|
|
|
process::exit(1);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
match ConverterRunner::new(typ) {
|
|
|
|
Ok(converter) => {
|
|
|
|
run_converter(converter, val, Some(file)).unwrap();
|
|
|
|
eprintln!("Build successful");
|
|
|
|
process::exit(0);
|
|
|
|
}
|
|
|
|
Err(msg) => {
|
|
|
|
eprintln!("{}", msg);
|
|
|
|
process::exit(1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2017-08-12 14:48:28 -05:00
|
|
|
} else if let Some(matches) = app.subcommand_matches("validate") {
|
2018-08-15 18:22:05 -05:00
|
|
|
let files = matches.values_of("INPUT").unwrap();
|
2018-08-13 23:11:35 -05:00
|
|
|
let mut builder = build::Builder::new(std::env::current_dir().unwrap(), cache);
|
2018-06-04 22:22:44 -05:00
|
|
|
builder.enable_validate_mode();
|
2018-08-15 18:22:05 -05:00
|
|
|
for file in files {
|
|
|
|
builder.build_file(file).unwrap();
|
|
|
|
println!("File Validates");
|
|
|
|
}
|
2017-11-15 22:41:55 -06:00
|
|
|
process::exit(0);
|
2017-08-12 14:48:28 -05:00
|
|
|
}
|
2017-05-05 22:33:25 -05:00
|
|
|
}
|