Skip to content

Commit

Permalink
feat: jsonschema
Browse files Browse the repository at this point in the history
  • Loading branch information
aatifsyed committed Dec 3, 2024
1 parent 7b1323c commit d192ffe
Show file tree
Hide file tree
Showing 7 changed files with 195 additions and 7 deletions.
64 changes: 62 additions & 2 deletions Cargo.lock

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

3 changes: 3 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,9 @@ dunce = "1.0.2"
filetime = "0.2.9"
flate2 = { version = "1.0.33", features = ["rust_backend"], default-features = false }
fs2 = "0.4"
schemars = "0.8.21"
serde = { version = "1.0.185", features = ["derive", "rc"] }
serde_json = "1.0.133"
serde_jsonrc = "0.1"
sha2 = "0.10.6"
tar = "0.4.43"
Expand All @@ -40,6 +42,7 @@ zstd = { version = "0.13", features = ["experimental", "zstdmt"] }
[dev-dependencies]
assert_matches = "1.5"
buck-resources = "1"
expect-test = "1.5.0"
snapbox = { version = "0.6.18", features = ["color-auto", "diff", "json", "regex"], default-features = false }

[target.'cfg(target_os = "linux")'.dependencies]
Expand Down
3 changes: 2 additions & 1 deletion src/artifact_path.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,15 @@ use std::path::Component;
use std::path::Path;
use std::str::FromStr;

use schemars::JsonSchema;
use serde::Deserialize;
use serde::Serialize;
use thiserror::Error;

/// `ArtifactPath` is a newtype type for `String` rather than `PathBuf` because
/// we want it to be unambiguously represented with forward slashes on all
/// platforms.
#[derive(Debug, Deserialize, Serialize, PartialEq, Eq, Clone)]
#[derive(Debug, Deserialize, Serialize, PartialEq, Eq, Clone, JsonSchema)]
#[serde(try_from = "String")]
pub struct ArtifactPath(String);

Expand Down
41 changes: 39 additions & 2 deletions src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,13 @@
* of this source tree.
*/

use std::borrow::Cow;
use std::collections::HashMap;

use anyhow::Context as _;
use schemars::gen::SchemaGenerator;
use schemars::schema::Schema;
use schemars::JsonSchema;
use serde::Deserialize;
use serde::Serialize;
use serde_jsonrc::value::Value;
Expand All @@ -24,7 +28,7 @@ use crate::fetch_method::ArtifactFormat;
/// all of the DotSlash files in the repo.
pub const REQUIRED_HEADER: &str = "#!/usr/bin/env dotslash";

#[derive(Deserialize, Debug, PartialEq)]
#[derive(Deserialize, Debug, PartialEq, JsonSchema)]
pub struct ConfigFile {
pub name: String,
pub platforms: HashMap<String, ArtifactEntry>,
Expand All @@ -43,6 +47,32 @@ pub struct ArtifactEntry<Format = ArtifactFormat> {
pub readonly: bool,
}

impl JsonSchema for ArtifactEntry {
fn schema_name() -> String {
String::from("ArtifactEntry")
}
fn json_schema(gen: &mut SchemaGenerator) -> Schema {
#[derive(JsonSchema)]
#[allow(dead_code)]
pub struct _ArtifactEntry {
pub size: u64,
pub hash: HashAlgorithm,
pub digest: Digest,
#[serde(default)]
pub format: ArtifactFormat,
pub path: ArtifactPath,
#[schemars(with = "Vec<serde_json::Value>")]
pub providers: Vec<Value>,
#[serde(default = "readonly_default_as_true", skip_serializing_if = "is_true")]
pub readonly: bool,
}
_ArtifactEntry::json_schema(gen)
}
fn schema_id() -> Cow<'static, str> {
Cow::Borrowed(std::concat!(std::module_path!(), "::", "ArtifactEntry"))
}
}

/// While having a boolean that defaults to `true` is somewhat undesirable,
/// the alternative would be to name the field "writable", which is too easy
/// to misspell as "writeable" (which would be ignored), so "readonly" it is.
Expand All @@ -55,7 +85,7 @@ fn is_true(b: &bool) -> bool {
*b
}

#[derive(Deserialize, Serialize, Debug, PartialEq, Eq)]
#[derive(Deserialize, Serialize, Debug, PartialEq, Eq, JsonSchema)]
pub enum HashAlgorithm {
#[serde(rename = "blake3")]
Blake3,
Expand Down Expand Up @@ -88,6 +118,13 @@ mod tests {
use crate::config::ArtifactPath;
use crate::fetch_method::ArtifactFormat;

#[test]
fn json_schema() {
let schema = schemars::schema_for!(ConfigFile);
let expected = serde_json::to_string_pretty(&schema).unwrap();
expect_test::expect_file!["schema.json"].assert_eq(&expected);
}

fn parse_file_string(json: &str) -> anyhow::Result<ConfigFile> {
Ok(parse_file(json)?.1)
}
Expand Down
3 changes: 2 additions & 1 deletion src/digest.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

use std::fmt;

use schemars::JsonSchema;
use serde::Deserialize;
use serde::Serialize;
use thiserror::Error;
Expand All @@ -22,7 +23,7 @@ pub enum DigestError {
InvalidHashLength(String),
}

#[derive(Debug, Deserialize, Serialize, PartialEq, Eq, Clone)]
#[derive(Debug, Deserialize, Serialize, PartialEq, Eq, Clone, JsonSchema)]
#[serde(try_from = "String")]
pub struct Digest(String);

Expand Down
3 changes: 2 additions & 1 deletion src/fetch_method.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,11 @@
* of this source tree.
*/

use schemars::JsonSchema;
use serde::Deserialize;
use serde::Serialize;

#[derive(Copy, Clone, Default, Deserialize, Serialize, Debug, PartialEq, Eq)]
#[derive(Copy, Clone, Default, Deserialize, Serialize, Debug, PartialEq, Eq, JsonSchema)]
pub enum ArtifactFormat {
/// Artifact is a single file with no compression applied.
#[default]
Expand Down
85 changes: 85 additions & 0 deletions src/schema.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "ConfigFile",
"type": "object",
"required": [
"name",
"platforms"
],
"properties": {
"name": {
"type": "string"
},
"platforms": {
"type": "object",
"additionalProperties": {
"$ref": "#/definitions/ArtifactEntry"
}
}
},
"definitions": {
"ArtifactEntry": {
"type": "object",
"required": [
"digest",
"hash",
"path",
"providers",
"size"
],
"properties": {
"digest": {
"$ref": "#/definitions/Digest"
},
"format": {
"$ref": "#/definitions/ArtifactFormat"
},
"hash": {
"$ref": "#/definitions/HashAlgorithm"
},
"path": {
"$ref": "#/definitions/ArtifactPath"
},
"providers": {
"type": "array",
"items": true
},
"readonly": {
"type": "boolean"
},
"size": {
"type": "integer",
"format": "uint64",
"minimum": 0.0
}
}
},
"ArtifactFormat": {
"type": "string",
"enum": [
"gz",
"tar",
"tar.gz",
"tar.zst",
"tar.xz",
"xz",
"zst",
"zip"
]
},
"ArtifactPath": {
"description": "`ArtifactPath` is a newtype type for `String` rather than `PathBuf` because we want it to be unambiguously represented with forward slashes on all platforms.",
"type": "string"
},
"Digest": {
"type": "string"
},
"HashAlgorithm": {
"type": "string",
"enum": [
"blake3",
"sha256"
]
}
}
}

0 comments on commit d192ffe

Please sign in to comment.