Skip to content

Commit

Permalink
feat(Config): Generate JSOn Schema and expose on CLI and in Node.js b…
Browse files Browse the repository at this point in the history
…indings
  • Loading branch information
nokome committed Apr 22, 2021
1 parent 08e7608 commit 7869a92
Show file tree
Hide file tree
Showing 14 changed files with 160 additions and 53 deletions.
44 changes: 43 additions & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

41 changes: 17 additions & 24 deletions cli/main.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
use stencila::{
anyhow::{Error, Result},
config, logging, plugins,
config, convert, inspect, logging, open, plugins,
regex::Regex,
tokio, tracing,
serve, tokio, tracing, upgrade,
};
use structopt::StructOpt;

Expand Down Expand Up @@ -50,25 +50,25 @@ pub const GLOBAL_ARGS: [&str; 6] = ["--debug", "--info", "--warn", "--error", "-
)]
pub enum Command {
#[cfg(feature = "open")]
Open(stencila::open::cli::Args),
Open(open::cli::Args),

#[cfg(feature = "convert")]
Convert(stencila::convert::cli::Args),
Convert(convert::cli::Args),

#[cfg(feature = "serve")]
Serve(stencila::serve::cli::Args),
Serve(serve::cli::Args),

#[cfg(feature = "plugins")]
Plugins(stencila::plugins::cli::Args),
Plugins(plugins::cli::Args),

#[cfg(feature = "config")]
Config(stencila::config::cli::Args),
Config(config::cli::Args),

#[cfg(feature = "upgrade")]
Upgrade(stencila::upgrade::cli::Args),
Upgrade(upgrade::cli::Args),

#[cfg(feature = "inspect")]
Inspect(stencila::inspect::cli::Args),
Inspect(inspect::cli::Args),
}

#[tracing::instrument(skip(config, plugins))]
Expand All @@ -80,32 +80,25 @@ pub async fn run_command(
) -> Result<()> {
match command {
#[cfg(feature = "open")]
Command::Open(args) => stencila::open::cli::run(args).await,
Command::Open(args) => open::cli::run(args).await,

#[cfg(feature = "convert")]
Command::Convert(args) => stencila::convert::cli::run(args),
Command::Convert(args) => convert::cli::run(args),

#[cfg(feature = "serve")]
Command::Serve(args) => stencila::serve::cli::run(args, &config.serve).await,
Command::Serve(args) => serve::cli::run(args, &config.serve).await,

#[cfg(feature = "plugins")]
Command::Plugins(args) => stencila::plugins::cli::run(args, &config.plugins, plugins).await,
Command::Plugins(args) => plugins::cli::run(args, &config.plugins, plugins).await,

#[cfg(feature = "upgrade")]
Command::Upgrade(args) => stencila::upgrade::cli::run(args, &config.upgrade, plugins).await,
Command::Upgrade(args) => upgrade::cli::run(args, &config.upgrade, plugins).await,

#[cfg(feature = "config")]
Command::Config(args) => match config::cli::run(args, &config) {
Ok(config_changed) => {
// Update the configuration (may have been changed by `set` and `reset`)
*config = config_changed;
Ok(())
}
Err(err) => Err(err),
},
Command::Config(args) => config::cli::run(args, config),

#[cfg(feature = "inspect")]
Command::Inspect(args) => stencila::inspect::cli::run(args, plugins).await,
Command::Inspect(args) => inspect::cli::run(args, plugins).await,
}
}

Expand Down Expand Up @@ -190,7 +183,7 @@ pub async fn main() -> Result<()> {
let upgrade_thread = if let Some(Command::Upgrade(_)) = command {
None
} else {
Some(stencila::upgrade::upgrade_auto(&config.upgrade, &plugins))
Some(upgrade::upgrade_auto(&config.upgrade, &plugins))
};

// Get the result of running the command
Expand Down
10 changes: 8 additions & 2 deletions node/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions node/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
},
"devDependencies": {
"@types/jest": "26.0.22",
"@types/json-schema": "7.0.7",
"cargo-cp-artifact": "0.1.4",
"jest": "26.6.3",
"ts-jest": "26.5.5",
Expand Down
5 changes: 5 additions & 0 deletions node/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,11 @@ fn save_then_to_json(cx: FunctionContext, conf: Config) -> JsResult<JsString> {
to_json(cx, guard.to_owned())
}

pub fn schema(mut cx: FunctionContext) -> JsResult<JsString> {
let schema = config::schema();
Ok(cx.string(schema))
}

pub fn read(mut cx: FunctionContext) -> JsResult<JsString> {
match config::read() {
Ok(conf) => save_then_to_json(cx, conf),
Expand Down
19 changes: 18 additions & 1 deletion node/src/config.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,23 @@
import { read, validate, set, reset } from './config'
import { read, validate, set, reset, schema } from './config'

describe('config', () => {
test('schema', () => {
expect(schema()).toEqual(
expect.objectContaining({
$schema: 'http://json-schema.org/draft-07/schema#',
title: 'Config',
type: 'object',
definitions: expect.objectContaining({}),
properties: expect.objectContaining({
logging: expect.objectContaining({}),
plugins: expect.objectContaining({}),
serve: expect.objectContaining({}),
upgrade: expect.objectContaining({}),
}),
})
)
})

const conf = read()

expect(conf).toEqual(
Expand Down
11 changes: 11 additions & 0 deletions node/src/config.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
// Node.js bindings for ../../rust/src/config.rs, see there for more documentation.

import { JSONSchema7 } from 'json-schema'
import { fromJSON, toJSON } from './prelude'

const addon = require('../index.node')
Expand Down Expand Up @@ -33,6 +34,16 @@ export interface Config {
}
}

/**
* Get the JSON schema for the configuration object
*
* @returns A JSON Schema v7 object describing the properties of
* the configuration object
*/
export function schema(): JSONSchema7 {
return fromJSON<JSONSchema7>(addon.configSchema())
}

/**
* Read the configuration from the configuration file
*
Expand Down
1 change: 1 addition & 0 deletions node/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ fn main(mut cx: ModuleContext) -> NeonResult<()> {
cx.export_function("pluginsUpgrade", plugins::upgrade)?;
cx.export_function("pluginsRefresh", plugins::refresh)?;

cx.export_function("configSchema", config::schema)?;
cx.export_function("configRead", config::read)?;
cx.export_function("configWrite", config::write)?;
cx.export_function("configValidate", config::validate)?;
Expand Down
1 change: 1 addition & 0 deletions rust/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@ once_cell = "1.7.2"
rand = "0.8.3"
regex = "1.4.5"
reqwest = { version = "0.11.3", optional = true, features = ["json"] }
schemars = "0.8.3"
self_update = { version = "0.26.0", optional = true, features = [
"archive-tar",
"archive-zip",
Expand Down
47 changes: 31 additions & 16 deletions rust/src/config.rs
Original file line number Diff line number Diff line change
@@ -1,29 +1,36 @@
use crate::util;
use crate::{logging, plugins, serve, upgrade, util};
use anyhow::{bail, Result};
use schemars::{schema_for, JsonSchema};
use serde::{Deserialize, Serialize};
use std::fs;
use std::io::Write;
use std::path::PathBuf;
use validator::Validate;

#[derive(Debug, Default, PartialEq, Clone, Deserialize, Serialize, Validate)]
#[derive(Debug, Default, PartialEq, Clone, JsonSchema, Deserialize, Serialize, Validate)]
#[serde(default)]
pub struct Config {
#[validate]
pub logging: crate::logging::config::Config,
pub logging: logging::config::Config,

#[validate]
pub serve: crate::serve::config::Config,
pub serve: serve::config::Config,

#[validate]
pub plugins: crate::plugins::config::Config,
pub plugins: plugins::config::Config,

#[validate]
pub upgrade: crate::upgrade::config::Config,
pub upgrade: upgrade::config::Config,
}

const CONFIG_FILE: &str = "config.toml";

/// Get the JSON Schema for the configuration
pub fn schema() -> String {
let schema = schema_for!(Config);
serde_json::to_string_pretty(&schema).unwrap()
}

/// Get the path of the configuration file
#[tracing::instrument]
fn path() -> Result<PathBuf> {
Expand Down Expand Up @@ -222,6 +229,12 @@ pub mod cli {
setting = structopt::clap::AppSettings::ColoredHelp
)]
Dirs,

#[structopt(
about = "Get the JSON Schema for the configuration",
setting = structopt::clap::AppSettings::ColoredHelp
)]
Schema,
}

#[derive(Debug, StructOpt)]
Expand Down Expand Up @@ -257,25 +270,23 @@ pub mod cli {
pub property: String,
}

pub fn run(args: Args, config: &Config) -> Result<Config> {
pub fn run(args: Args, config: &mut Config) -> Result<()> {
let Args { action } = args;
match action {
Action::Get(action) => {
let Get { pointer } = action;
println!("{}", super::display(config, pointer)?);
Ok(config.clone())
println!("{}", display(config, pointer)?);
Ok(())
}
Action::Set(action) => {
let Set { pointer, value } = action;
let config = super::set(config, &pointer, &value)?;
write(&config)?;
Ok(config)
*config = set(config, &pointer, &value)?;
write(config)
}
Action::Reset(action) => {
let Reset { property } = action;
let config = super::reset(config, &property)?;
write(&config)?;
Ok(config)
*config = reset(config, &property)?;
write(config)
}
Action::Dirs => {
let config_dir = util::dirs::config(false)?.display().to_string();
Expand All @@ -285,7 +296,11 @@ pub mod cli {
"config: {}\nlogs: {}\nplugins: {}",
config_dir, logs_dir, plugins_dir
);
Ok(config.clone())
Ok(())
}
Action::Schema => {
println!("{}", schema());
Ok(())
}
}
}
Expand Down

0 comments on commit 7869a92

Please sign in to comment.