add an optional builder pattern as well as extension traits for tags when using the builder interface (#86)
This commit is contained in:
parent
9e84bde032
commit
9b28ac87c6
|
@ -14,10 +14,26 @@ jobs:
|
|||
runs-on: ubuntu-18.04
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Install nightly
|
||||
uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
toolchain: nightly
|
||||
components: rustfmt
|
||||
default: false
|
||||
- name: Install stable
|
||||
uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
toolchain: stable
|
||||
components: rustfmt
|
||||
default: true
|
||||
- name: Report cargo version
|
||||
run: cargo --version
|
||||
- name: Report rustfmt version
|
||||
run: cargo fmt -- --version
|
||||
- name: Report nightly cargo version
|
||||
run: cargo +nightly --version
|
||||
- name: Report nightly rustfmt version
|
||||
run: cargo +nightly fmt -- --version
|
||||
- name: Check style
|
||||
run: cargo fmt -- --check
|
||||
|
||||
|
@ -28,6 +44,18 @@ jobs:
|
|||
os: [ ubuntu-18.04, windows-2019, macos-10.15 ]
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Install nightly
|
||||
uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
toolchain: nightly
|
||||
components: rustfmt
|
||||
default: false
|
||||
- name: Install stable
|
||||
uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
toolchain: stable
|
||||
components: rustfmt
|
||||
default: true
|
||||
- name: Build
|
||||
run: cargo build --tests --verbose
|
||||
- name: Run tests
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
:icons: font
|
||||
:toclevels: 1
|
||||
|
||||
= Typify Changelog
|
||||
= Progenitor Changelog
|
||||
|
||||
// WARNING: This file is modified programmatically by `cargo release` as
|
||||
// configured in release.toml. DO NOT change the format of the headers or the
|
||||
|
@ -15,6 +15,8 @@
|
|||
|
||||
https://github.com/oxidecomputer/progenitor/compare/v0.1.1\...HEAD[Full list of commits]
|
||||
|
||||
* Add support for a builder-style generation in addition to the positional style (#86)
|
||||
|
||||
== 0.1.1 (released 2022-05-13)
|
||||
|
||||
First published version
|
||||
|
|
|
@ -116,6 +116,45 @@ dependencies = [
|
|||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap"
|
||||
version = "3.2.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "190814073e85d238f31ff738fcb0bf6910cedeb73376c87cd69291028966fd83"
|
||||
dependencies = [
|
||||
"atty",
|
||||
"bitflags",
|
||||
"clap_derive",
|
||||
"clap_lex",
|
||||
"indexmap",
|
||||
"once_cell",
|
||||
"strsim",
|
||||
"termcolor",
|
||||
"textwrap",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap_derive"
|
||||
version = "3.2.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "759bf187376e1afa7b85b959e6a664a3e7a95203415dba952ad19139e798f902"
|
||||
dependencies = [
|
||||
"heck",
|
||||
"proc-macro-error",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap_lex"
|
||||
version = "0.2.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2850f2f5a82cbf437dd5af4d49848fbdfc27c157c3d010345776f952765261c5"
|
||||
dependencies = [
|
||||
"os_str_bytes",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "console"
|
||||
version = "0.15.0"
|
||||
|
@ -776,9 +815,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "once_cell"
|
||||
version = "1.9.0"
|
||||
version = "1.12.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "da32515d9f6e6e489d7bc9d84c71b060db7247dc035bbe44eac88cf87486d8d5"
|
||||
checksum = "7709cef83f0c1f58f666e746a08b21e0085f7440fa6a29cc194d68aac97a4225"
|
||||
|
||||
[[package]]
|
||||
name = "openapiv3"
|
||||
|
@ -824,6 +863,12 @@ dependencies = [
|
|||
"vcpkg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "os_str_bytes"
|
||||
version = "6.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "21326818e99cfe6ce1e524c2a805c189a99b5ae555a35d19f9a284b427d86afa"
|
||||
|
||||
[[package]]
|
||||
name = "parking_lot"
|
||||
version = "0.12.0"
|
||||
|
@ -886,6 +931,30 @@ version = "0.3.24"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "58893f751c9b0412871a09abd62ecd2a00298c6c83befa223ef98c52aef40cbe"
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro-error"
|
||||
version = "1.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c"
|
||||
dependencies = [
|
||||
"proc-macro-error-attr",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"version_check",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro-error-attr"
|
||||
version = "1.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"version_check",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.40"
|
||||
|
@ -901,8 +970,8 @@ version = "0.1.2-dev"
|
|||
dependencies = [
|
||||
"anyhow",
|
||||
"chrono",
|
||||
"clap",
|
||||
"futures",
|
||||
"getopts",
|
||||
"openapiv3",
|
||||
"percent-encoding",
|
||||
"progenitor-client",
|
||||
|
@ -1394,6 +1463,12 @@ version = "0.5.2"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d"
|
||||
|
||||
[[package]]
|
||||
name = "strsim"
|
||||
version = "0.10.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "1.0.98"
|
||||
|
@ -1436,6 +1511,15 @@ dependencies = [
|
|||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "termcolor"
|
||||
version = "1.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bab24d30b911b2376f3a13cc2cd443142f0c81dda04c118693e35b3835757755"
|
||||
dependencies = [
|
||||
"winapi-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "terminal_size"
|
||||
version = "0.1.17"
|
||||
|
@ -1446,6 +1530,12 @@ dependencies = [
|
|||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "textwrap"
|
||||
version = "0.15.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b1141d4d61095b28419e22cb0bbf02755f5e54e0526f97f1e3d1d160e60885fb"
|
||||
|
||||
[[package]]
|
||||
name = "thiserror"
|
||||
version = "1.0.31"
|
||||
|
@ -1640,9 +1730,9 @@ checksum = "59547bce71d9c38b83d9c0e92b6066c4253371f15005def0c30d9657f50c7642"
|
|||
|
||||
[[package]]
|
||||
name = "typify"
|
||||
version = "0.0.8"
|
||||
version = "0.0.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d94783d3e464d8b2b8f78e826521e9f11c7df83523dafd544c5e642bf31df5a4"
|
||||
checksum = "505f18fc847efc93b45a763f36f8099d3415dbfc6c0d6c3857a3012e20db92c7"
|
||||
dependencies = [
|
||||
"typify-impl",
|
||||
"typify-macro",
|
||||
|
@ -1650,9 +1740,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "typify-impl"
|
||||
version = "0.0.8"
|
||||
version = "0.0.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b27f7e4f8a3b375daabcd3721bc067920a59ea9a33c1f01b9b2b98d17c3b5497"
|
||||
checksum = "b572369a55be8402a5a7e24c721e8d895dbd58bf3d9dccb4b3619fcb926e7bde"
|
||||
dependencies = [
|
||||
"heck",
|
||||
"log",
|
||||
|
@ -1663,14 +1753,14 @@ dependencies = [
|
|||
"serde_json",
|
||||
"syn",
|
||||
"thiserror",
|
||||
"unicode-xid",
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "typify-macro"
|
||||
version = "0.0.8"
|
||||
version = "0.0.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e4211d794d8e4e6fed99bdcd263529ee05af52d9794004cc235123216f1fef42"
|
||||
checksum = "a615bfbbcf929b1733898d2afe00c83dbf8756f8028aa42c156c3c2713b0f03b"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
|
@ -1696,9 +1786,9 @@ checksum = "1a01404663e3db436ed2746d9fefef640d868edae3cceb81c3b8d5732fda678f"
|
|||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
version = "1.0.0"
|
||||
version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d22af068fba1eb5edcb4aea19d382b2a3deb4c8f9d475c589b6ada9e0fd493ee"
|
||||
checksum = "5bd2fe26506023ed7b5e1e315add59d6f584c621d037f9368fea9cfb988f368c"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-normalization"
|
||||
|
@ -1715,12 +1805,6 @@ version = "0.1.9"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3ed742d4ea2bd1176e236172c8429aaf54486e7ac098db29ffe6529e0ce50973"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-xid"
|
||||
version = "0.2.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "957e51f3646910546462e67d5f7599b9e4fb8acdd304b087a6494730f9eebf04"
|
||||
|
||||
[[package]]
|
||||
name = "untrusted"
|
||||
version = "0.7.1"
|
||||
|
|
|
@ -8,7 +8,9 @@ members = [
|
|||
"progenitor-macro",
|
||||
]
|
||||
|
||||
#[patch."https://github.com/oxidecomputer/typify"]
|
||||
#typify = { path = "../typify/typify" }
|
||||
#[patch."https://github.com/oxidecomputer/dropshot"]
|
||||
#dropshot = { path = "../dropshot/dropshot" }
|
||||
|
||||
#[patch.crates-io]
|
||||
#typify = { path = "../typify/typify" }
|
||||
#rustfmt-wrapper = { path = "../rustfmt-wrapper" }
|
||||
|
|
14
README.md
14
README.md
|
@ -51,11 +51,13 @@ The macro has some additional fancy options to control the generated code:
|
|||
|
||||
```rust
|
||||
generate_api!(
|
||||
spec = "path/to/openapi_document.json", // The OpenAPI document
|
||||
inner_type = my_client::InnerType, // Client inner type available to pre and post hooks
|
||||
pre_hook = closure::or::path::to::function, // Hook invoked before issuing the HTTP request
|
||||
post_hook = closure::or::path::to::function, // Hook invoked prior to receiving the HTTP response
|
||||
derives = [ schemars::JsonSchema ], // Additional derive macros applied to generated types
|
||||
spec = "path/to/openapi_document.json", // The OpenAPI document
|
||||
interface = Builder, // Choose positional (default) or builder style
|
||||
tags = Separate, // Tags may be Merged or Separate (default)
|
||||
inner_type = my_client::InnerType, // Client inner type available to pre and post hooks
|
||||
pre_hook = closure::or::path::to::function, // Hook invoked before issuing the HTTP request
|
||||
post_hook = closure::or::path::to::function, // Hook invoked prior to receiving the HTTP response
|
||||
derives = [ schemars::JsonSchema ], // Additional derive macros applied to generated types
|
||||
);
|
||||
```
|
||||
|
||||
|
@ -76,7 +78,7 @@ fn main() {
|
|||
println!("cargo:rerun-if-changed={}", src);
|
||||
let file = File::open(src).unwrap();
|
||||
let spec = serde_json::from_reader(file).unwrap();
|
||||
let mut generator = progenitor::Generator::new();
|
||||
let mut generator = progenitor::Generator::default();
|
||||
|
||||
let content = generator.generate_text(&spec).unwrap();
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
name = "example-build"
|
||||
version = "0.0.1"
|
||||
authors = ["Adam H. Leventhal <ahl@oxidecomputer.com>"]
|
||||
edition = "2018"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
chrono = { version = "0.4", features = ["serde"] }
|
||||
|
|
|
@ -11,7 +11,7 @@ fn main() {
|
|||
println!("cargo:rerun-if-changed={}", src);
|
||||
let file = File::open(src).unwrap();
|
||||
let spec = serde_json::from_reader(file).unwrap();
|
||||
let mut generator = progenitor::Generator::new();
|
||||
let mut generator = progenitor::Generator::default();
|
||||
|
||||
let content = generator.generate_text(&spec).unwrap();
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
name = "example-macro"
|
||||
version = "0.0.1"
|
||||
authors = ["Adam H. Leventhal <ahl@oxidecomputer.com>"]
|
||||
edition = "2018"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
chrono = { version = "0.4", features = ["serde"] }
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
[package]
|
||||
name = "progenitor-client"
|
||||
version = "0.1.2-dev"
|
||||
edition = "2018"
|
||||
edition = "2021"
|
||||
license = "MPL-2.0"
|
||||
repository = "https://github.com/oxidecomputer/progenitor.git"
|
||||
description = "An OpenAPI client generator - client support"
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
// Copyright 2022 Oxide Computer Company
|
||||
|
||||
#![allow(dead_code)]
|
||||
|
||||
//! Support code for generated clients.
|
||||
|
||||
use std::{
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
[package]
|
||||
name = "progenitor-impl"
|
||||
version = "0.1.2-dev"
|
||||
edition = "2018"
|
||||
edition = "2021"
|
||||
license = "MPL-2.0"
|
||||
repository = "https://github.com/oxidecomputer/progenitor.git"
|
||||
description = "An OpenAPI client generator - core implementation"
|
||||
|
@ -14,13 +14,13 @@ openapiv3 = "1.0.0"
|
|||
proc-macro2 = "1.0"
|
||||
quote = "1.0"
|
||||
regex = "1.5"
|
||||
rustfmt-wrapper = "0.2"
|
||||
rustfmt-wrapper = "0.2.0"
|
||||
schemars = { version = "0.8.10", features = ["chrono", "uuid1"] }
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
serde_json = "1.0"
|
||||
syn = { version = "1.0", features = ["parsing"] }
|
||||
thiserror = "1.0"
|
||||
typify = "0.0.8"
|
||||
typify = "0.0.9"
|
||||
unicode-ident = "1.0.0"
|
||||
|
||||
[dev-dependencies]
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
use openapiv3::OpenAPI;
|
||||
use proc_macro2::TokenStream;
|
||||
use quote::quote;
|
||||
use serde::Deserialize;
|
||||
use thiserror::Error;
|
||||
use typify::TypeSpace;
|
||||
|
||||
|
@ -32,17 +33,59 @@ pub type Result<T> = std::result::Result<T, Error>;
|
|||
#[derive(Default)]
|
||||
pub struct Generator {
|
||||
type_space: TypeSpace,
|
||||
inner_type: Option<TokenStream>,
|
||||
pre_hook: Option<TokenStream>,
|
||||
post_hook: Option<TokenStream>,
|
||||
settings: GenerationSettings,
|
||||
uses_futures: bool,
|
||||
}
|
||||
|
||||
impl Generator {
|
||||
#[derive(Default, Clone)]
|
||||
pub struct GenerationSettings {
|
||||
interface: InterfaceStyle,
|
||||
tag: TagStyle,
|
||||
inner_type: Option<TokenStream>,
|
||||
pre_hook: Option<TokenStream>,
|
||||
post_hook: Option<TokenStream>,
|
||||
extra_derives: Vec<TokenStream>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Deserialize)]
|
||||
pub enum InterfaceStyle {
|
||||
Positional,
|
||||
Builder,
|
||||
}
|
||||
|
||||
impl Default for InterfaceStyle {
|
||||
fn default() -> Self {
|
||||
Self::Positional
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Deserialize)]
|
||||
pub enum TagStyle {
|
||||
Merged,
|
||||
Separate,
|
||||
}
|
||||
|
||||
impl Default for TagStyle {
|
||||
fn default() -> Self {
|
||||
Self::Merged
|
||||
}
|
||||
}
|
||||
|
||||
impl GenerationSettings {
|
||||
pub fn new() -> Self {
|
||||
Self::default()
|
||||
}
|
||||
|
||||
pub fn with_interface(&mut self, interface: InterfaceStyle) -> &mut Self {
|
||||
self.interface = interface;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn with_tag(&mut self, tag: TagStyle) -> &mut Self {
|
||||
self.tag = tag;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn with_inner_type(&mut self, inner_type: TokenStream) -> &mut Self {
|
||||
self.inner_type = Some(inner_type);
|
||||
self
|
||||
|
@ -58,10 +101,21 @@ impl Generator {
|
|||
self
|
||||
}
|
||||
|
||||
// TODO maybe change to a typify::Settings or something
|
||||
pub fn with_derive(&mut self, derive: TokenStream) -> &mut Self {
|
||||
self.type_space.add_derive(derive);
|
||||
self.extra_derives.push(derive);
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl Generator {
|
||||
pub fn new(settings: &GenerationSettings) -> Self {
|
||||
Self {
|
||||
type_space: TypeSpace::default(),
|
||||
settings: settings.clone(),
|
||||
uses_futures: false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn generate_tokens(&mut self, spec: &OpenAPI) -> Result<TokenStream> {
|
||||
// Convert our components dictionary to schemars
|
||||
|
@ -100,10 +154,23 @@ impl Generator {
|
|||
})
|
||||
.collect::<Result<Vec<_>>>()?;
|
||||
|
||||
let methods = raw_methods
|
||||
.iter()
|
||||
.map(|method| self.positional_method(method))
|
||||
.collect::<Result<Vec<_>>>()?;
|
||||
let operation_code = match (
|
||||
&self.settings.interface,
|
||||
&self.settings.tag,
|
||||
) {
|
||||
(InterfaceStyle::Positional, TagStyle::Merged) => {
|
||||
self.generate_tokens_positional_merged(&raw_methods)
|
||||
}
|
||||
(InterfaceStyle::Positional, TagStyle::Separate) => {
|
||||
unimplemented!("positional arguments with separate tags are currently unsupported")
|
||||
}
|
||||
(InterfaceStyle::Builder, TagStyle::Merged) => {
|
||||
self.generate_tokens_builder_merged(&raw_methods)
|
||||
}
|
||||
(InterfaceStyle::Builder, TagStyle::Separate) => {
|
||||
self.generate_tokens_builder_separate(&raw_methods)
|
||||
}
|
||||
}?;
|
||||
|
||||
let mut types = self
|
||||
.type_space
|
||||
|
@ -114,12 +181,17 @@ impl Generator {
|
|||
let types = types.into_iter().map(|(_, def)| def);
|
||||
let shared = self.type_space.common_code();
|
||||
|
||||
let inner_property = self.inner_type.as_ref().map(|inner| {
|
||||
let inner_property = self.settings.inner_type.as_ref().map(|inner| {
|
||||
quote! {
|
||||
pub (crate) inner: #inner,
|
||||
}
|
||||
});
|
||||
let inner_parameter = self.settings.inner_type.as_ref().map(|inner| {
|
||||
quote! {
|
||||
inner: #inner,
|
||||
}
|
||||
});
|
||||
let inner_value = self.inner_type.as_ref().map(|_| {
|
||||
let inner_value = self.settings.inner_type.as_ref().map(|_| {
|
||||
quote! {
|
||||
inner
|
||||
}
|
||||
|
@ -129,6 +201,8 @@ impl Generator {
|
|||
// Re-export ResponseValue and Error since those are used by the
|
||||
// public interface of Client.
|
||||
pub use progenitor_client::{ByteStream, Error, ResponseValue};
|
||||
#[allow(unused_imports)]
|
||||
use progenitor_client::encode_path;
|
||||
|
||||
pub mod types {
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
@ -138,15 +212,15 @@ impl Generator {
|
|||
|
||||
#[derive(Clone)]
|
||||
pub struct Client {
|
||||
baseurl: String,
|
||||
client: reqwest::Client,
|
||||
pub(crate) baseurl: String,
|
||||
pub(crate) client: reqwest::Client,
|
||||
#inner_property
|
||||
}
|
||||
|
||||
impl Client {
|
||||
pub fn new(
|
||||
baseurl: &str,
|
||||
#inner_property
|
||||
#inner_parameter
|
||||
) -> Self {
|
||||
let dur = std::time::Duration::from_secs(15);
|
||||
let client = reqwest::ClientBuilder::new()
|
||||
|
@ -160,7 +234,7 @@ impl Generator {
|
|||
pub fn new_with_client(
|
||||
baseurl: &str,
|
||||
client: reqwest::Client,
|
||||
#inner_property
|
||||
#inner_parameter
|
||||
) -> Self {
|
||||
Self {
|
||||
baseurl: baseurl.to_string(),
|
||||
|
@ -177,18 +251,126 @@ impl Generator {
|
|||
&self.client
|
||||
}
|
||||
|
||||
#(#methods)*
|
||||
}
|
||||
|
||||
#operation_code
|
||||
};
|
||||
|
||||
Ok(file)
|
||||
}
|
||||
|
||||
fn generate_tokens_positional_merged(
|
||||
&mut self,
|
||||
input_methods: &[method::OperationMethod],
|
||||
) -> Result<TokenStream> {
|
||||
let methods = input_methods
|
||||
.iter()
|
||||
.map(|method| self.positional_method(method))
|
||||
.collect::<Result<Vec<_>>>()?;
|
||||
let out = quote! {
|
||||
impl Client {
|
||||
#(#methods)*
|
||||
}
|
||||
};
|
||||
Ok(out)
|
||||
}
|
||||
|
||||
fn generate_tokens_builder_merged(
|
||||
&mut self,
|
||||
input_methods: &[method::OperationMethod],
|
||||
) -> Result<TokenStream> {
|
||||
let builder_struct = input_methods
|
||||
.iter()
|
||||
.map(|method| self.builder_struct(method, TagStyle::Merged))
|
||||
.collect::<Result<Vec<_>>>()?;
|
||||
|
||||
let builder_methods = input_methods
|
||||
.iter()
|
||||
.map(|method| self.builder_impl(method))
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let out = quote! {
|
||||
impl Client {
|
||||
#(#builder_methods)*
|
||||
}
|
||||
|
||||
pub mod builder {
|
||||
use super::types;
|
||||
#[allow(unused_imports)]
|
||||
use super::{ByteStream, Error, ResponseValue};
|
||||
#[allow(unused_imports)]
|
||||
use super::encode_path;
|
||||
|
||||
#(#builder_struct)*
|
||||
}
|
||||
};
|
||||
|
||||
Ok(out)
|
||||
}
|
||||
|
||||
fn generate_tokens_builder_separate(
|
||||
&mut self,
|
||||
input_methods: &[method::OperationMethod],
|
||||
) -> Result<TokenStream> {
|
||||
let builder_struct = input_methods
|
||||
.iter()
|
||||
.map(|method| self.builder_struct(method, TagStyle::Separate))
|
||||
.collect::<Result<Vec<_>>>()?;
|
||||
|
||||
let traits_and_impls = self.builder_tags(input_methods);
|
||||
|
||||
let out = quote! {
|
||||
#traits_and_impls
|
||||
|
||||
pub mod builder {
|
||||
use super::types;
|
||||
#[allow(unused_imports)]
|
||||
use super::{ByteStream, Error, ResponseValue};
|
||||
#[allow(unused_imports)]
|
||||
use super::encode_path;
|
||||
|
||||
#(#builder_struct)*
|
||||
}
|
||||
};
|
||||
|
||||
Ok(out)
|
||||
}
|
||||
|
||||
/// Render text output.
|
||||
pub fn generate_text(&mut self, spec: &OpenAPI) -> Result<String> {
|
||||
self.generate_text_impl(
|
||||
spec,
|
||||
rustfmt_wrapper::config::Config::default(),
|
||||
)
|
||||
}
|
||||
|
||||
/// Render text output and normalize doc comments
|
||||
///
|
||||
/// Requires a nightly install of `rustfmt` (even if the target project is
|
||||
/// not using nightly).
|
||||
pub fn generate_text_normalize_comments(
|
||||
&mut self,
|
||||
spec: &OpenAPI,
|
||||
) -> Result<String> {
|
||||
self.generate_text_impl(
|
||||
spec,
|
||||
rustfmt_wrapper::config::Config {
|
||||
normalize_doc_attributes: Some(true),
|
||||
wrap_comments: Some(true),
|
||||
..Default::default()
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
fn generate_text_impl(
|
||||
&mut self,
|
||||
spec: &OpenAPI,
|
||||
config: rustfmt_wrapper::config::Config,
|
||||
) -> Result<String> {
|
||||
let output = self.generate_tokens(spec)?;
|
||||
|
||||
// Format the file with rustfmt.
|
||||
let content = rustfmt_wrapper::rustfmt(output).unwrap();
|
||||
let content = rustfmt_wrapper::rustfmt_config(config, output).unwrap();
|
||||
|
||||
// Add newlines after end-braces at <= two levels of indentation.
|
||||
Ok(if cfg!(not(windows)) {
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -19,7 +19,11 @@ pub struct PathTemplate {
|
|||
}
|
||||
|
||||
impl PathTemplate {
|
||||
pub fn compile(&self, rename: HashMap<&String, &String>) -> TokenStream {
|
||||
pub fn compile(
|
||||
&self,
|
||||
rename: HashMap<&String, &String>,
|
||||
client: TokenStream,
|
||||
) -> TokenStream {
|
||||
let mut fmt = String::new();
|
||||
fmt.push_str("{}");
|
||||
for c in self.components.iter() {
|
||||
|
@ -39,7 +43,7 @@ impl PathTemplate {
|
|||
.expect(&format!("missing path name mapping {}", n)),
|
||||
);
|
||||
Some(quote! {
|
||||
progenitor_client::encode_path(&#param.to_string())
|
||||
encode_path(&#param.to_string())
|
||||
})
|
||||
} else {
|
||||
None
|
||||
|
@ -47,7 +51,7 @@ impl PathTemplate {
|
|||
});
|
||||
|
||||
quote! {
|
||||
let url = format!(#fmt, self.baseurl, #(#components,)*);
|
||||
let url = format!(#fmt, #client.baseurl, #(#components,)*);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -233,11 +237,11 @@ mod test {
|
|||
let number = "number".to_string();
|
||||
rename.insert(&number, &number);
|
||||
let t = parse("/measure/{number}").unwrap();
|
||||
let out = t.compile(rename);
|
||||
let out = t.compile(rename, quote::quote! { self });
|
||||
let want = quote::quote! {
|
||||
let url = format!("{}/measure/{}",
|
||||
self.baseurl,
|
||||
progenitor_client::encode_path(&number.to_string()),
|
||||
encode_path(&number.to_string()),
|
||||
);
|
||||
};
|
||||
assert_eq!(want.to_string(), out.to_string());
|
||||
|
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -1,3 +1,5 @@
|
|||
#[allow(unused_imports)]
|
||||
use progenitor_client::encode_path;
|
||||
pub use progenitor_client::{ByteStream, Error, ResponseValue};
|
||||
pub mod types {
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
@ -132,8 +134,8 @@ pub mod types {
|
|||
|
||||
#[derive(Clone)]
|
||||
pub struct Client {
|
||||
baseurl: String,
|
||||
client: reqwest::Client,
|
||||
pub(crate) baseurl: String,
|
||||
pub(crate) client: reqwest::Client,
|
||||
}
|
||||
|
||||
impl Client {
|
||||
|
@ -161,8 +163,10 @@ impl Client {
|
|||
pub fn client(&self) -> &reqwest::Client {
|
||||
&self.client
|
||||
}
|
||||
}
|
||||
|
||||
#[doc = "Sends a `POST` request to `/v1/control/hold`"]
|
||||
impl Client {
|
||||
///Sends a `POST` request to `/v1/control/hold`
|
||||
pub async fn control_hold<'a>(&'a self) -> Result<ResponseValue<()>, Error<()>> {
|
||||
let url = format!("{}/v1/control/hold", self.baseurl,);
|
||||
let request = self.client.post(url).build()?;
|
||||
|
@ -174,7 +178,7 @@ impl Client {
|
|||
}
|
||||
}
|
||||
|
||||
#[doc = "Sends a `POST` request to `/v1/control/resume`"]
|
||||
///Sends a `POST` request to `/v1/control/resume`
|
||||
pub async fn control_resume<'a>(&'a self) -> Result<ResponseValue<()>, Error<()>> {
|
||||
let url = format!("{}/v1/control/resume", self.baseurl,);
|
||||
let request = self.client.post(url).build()?;
|
||||
|
@ -186,7 +190,7 @@ impl Client {
|
|||
}
|
||||
}
|
||||
|
||||
#[doc = "Sends a `GET` request to `/v1/task/{task}`"]
|
||||
///Sends a `GET` request to `/v1/task/{task}`
|
||||
pub async fn task_get<'a>(
|
||||
&'a self,
|
||||
task: &'a str,
|
||||
|
@ -194,7 +198,7 @@ impl Client {
|
|||
let url = format!(
|
||||
"{}/v1/task/{}",
|
||||
self.baseurl,
|
||||
progenitor_client::encode_path(&task.to_string()),
|
||||
encode_path(&task.to_string()),
|
||||
);
|
||||
let request = self.client.get(url).build()?;
|
||||
let result = self.client.execute(request).await;
|
||||
|
@ -205,7 +209,7 @@ impl Client {
|
|||
}
|
||||
}
|
||||
|
||||
#[doc = "Sends a `GET` request to `/v1/tasks`"]
|
||||
///Sends a `GET` request to `/v1/tasks`
|
||||
pub async fn tasks_get<'a>(&'a self) -> Result<ResponseValue<Vec<types::Task>>, Error<()>> {
|
||||
let url = format!("{}/v1/tasks", self.baseurl,);
|
||||
let request = self.client.get(url).build()?;
|
||||
|
@ -217,13 +221,13 @@ impl Client {
|
|||
}
|
||||
}
|
||||
|
||||
#[doc = "Sends a `POST` request to `/v1/tasks`"]
|
||||
///Sends a `POST` request to `/v1/tasks`
|
||||
pub async fn task_submit<'a>(
|
||||
&'a self,
|
||||
body: &'a types::TaskSubmit,
|
||||
) -> Result<ResponseValue<types::TaskSubmitResult>, Error<()>> {
|
||||
let url = format!("{}/v1/tasks", self.baseurl,);
|
||||
let request = self.client.post(url).json(body).build()?;
|
||||
let request = self.client.post(url).json(&body).build()?;
|
||||
let result = self.client.execute(request).await;
|
||||
let response = result?;
|
||||
match response.status().as_u16() {
|
||||
|
@ -232,7 +236,7 @@ impl Client {
|
|||
}
|
||||
}
|
||||
|
||||
#[doc = "Sends a `GET` request to `/v1/tasks/{task}/events`"]
|
||||
///Sends a `GET` request to `/v1/tasks/{task}/events`
|
||||
pub async fn task_events_get<'a>(
|
||||
&'a self,
|
||||
task: &'a str,
|
||||
|
@ -241,7 +245,7 @@ impl Client {
|
|||
let url = format!(
|
||||
"{}/v1/tasks/{}/events",
|
||||
self.baseurl,
|
||||
progenitor_client::encode_path(&task.to_string()),
|
||||
encode_path(&task.to_string()),
|
||||
);
|
||||
let mut query = Vec::new();
|
||||
if let Some(v) = &minseq {
|
||||
|
@ -257,7 +261,7 @@ impl Client {
|
|||
}
|
||||
}
|
||||
|
||||
#[doc = "Sends a `GET` request to `/v1/tasks/{task}/outputs`"]
|
||||
///Sends a `GET` request to `/v1/tasks/{task}/outputs`
|
||||
pub async fn task_outputs_get<'a>(
|
||||
&'a self,
|
||||
task: &'a str,
|
||||
|
@ -265,7 +269,7 @@ impl Client {
|
|||
let url = format!(
|
||||
"{}/v1/tasks/{}/outputs",
|
||||
self.baseurl,
|
||||
progenitor_client::encode_path(&task.to_string()),
|
||||
encode_path(&task.to_string()),
|
||||
);
|
||||
let request = self.client.get(url).build()?;
|
||||
let result = self.client.execute(request).await;
|
||||
|
@ -276,7 +280,7 @@ impl Client {
|
|||
}
|
||||
}
|
||||
|
||||
#[doc = "Sends a `GET` request to `/v1/tasks/{task}/outputs/{output}`"]
|
||||
///Sends a `GET` request to `/v1/tasks/{task}/outputs/{output}`
|
||||
pub async fn task_output_download<'a>(
|
||||
&'a self,
|
||||
task: &'a str,
|
||||
|
@ -285,8 +289,8 @@ impl Client {
|
|||
let url = format!(
|
||||
"{}/v1/tasks/{}/outputs/{}",
|
||||
self.baseurl,
|
||||
progenitor_client::encode_path(&task.to_string()),
|
||||
progenitor_client::encode_path(&output.to_string()),
|
||||
encode_path(&task.to_string()),
|
||||
encode_path(&output.to_string()),
|
||||
);
|
||||
let request = self.client.get(url).build()?;
|
||||
let result = self.client.execute(request).await;
|
||||
|
@ -297,13 +301,13 @@ impl Client {
|
|||
}
|
||||
}
|
||||
|
||||
#[doc = "Sends a `POST` request to `/v1/users`"]
|
||||
///Sends a `POST` request to `/v1/users`
|
||||
pub async fn user_create<'a>(
|
||||
&'a self,
|
||||
body: &'a types::UserCreate,
|
||||
) -> Result<ResponseValue<types::UserCreateResult>, Error<()>> {
|
||||
let url = format!("{}/v1/users", self.baseurl,);
|
||||
let request = self.client.post(url).json(body).build()?;
|
||||
let request = self.client.post(url).json(&body).build()?;
|
||||
let result = self.client.execute(request).await;
|
||||
let response = result?;
|
||||
match response.status().as_u16() {
|
||||
|
@ -312,7 +316,7 @@ impl Client {
|
|||
}
|
||||
}
|
||||
|
||||
#[doc = "Sends a `GET` request to `/v1/whoami`"]
|
||||
///Sends a `GET` request to `/v1/whoami`
|
||||
pub async fn whoami<'a>(&'a self) -> Result<ResponseValue<types::WhoamiResult>, Error<()>> {
|
||||
let url = format!("{}/v1/whoami", self.baseurl,);
|
||||
let request = self.client.get(url).build()?;
|
||||
|
@ -324,13 +328,13 @@ impl Client {
|
|||
}
|
||||
}
|
||||
|
||||
#[doc = "Sends a `POST` request to `/v1/worker/bootstrap`"]
|
||||
///Sends a `POST` request to `/v1/worker/bootstrap`
|
||||
pub async fn worker_bootstrap<'a>(
|
||||
&'a self,
|
||||
body: &'a types::WorkerBootstrap,
|
||||
) -> Result<ResponseValue<types::WorkerBootstrapResult>, Error<()>> {
|
||||
let url = format!("{}/v1/worker/bootstrap", self.baseurl,);
|
||||
let request = self.client.post(url).json(body).build()?;
|
||||
let request = self.client.post(url).json(&body).build()?;
|
||||
let result = self.client.execute(request).await;
|
||||
let response = result?;
|
||||
match response.status().as_u16() {
|
||||
|
@ -339,7 +343,7 @@ impl Client {
|
|||
}
|
||||
}
|
||||
|
||||
#[doc = "Sends a `GET` request to `/v1/worker/ping`"]
|
||||
///Sends a `GET` request to `/v1/worker/ping`
|
||||
pub async fn worker_ping<'a>(
|
||||
&'a self,
|
||||
) -> Result<ResponseValue<types::WorkerPingResult>, Error<()>> {
|
||||
|
@ -353,7 +357,7 @@ impl Client {
|
|||
}
|
||||
}
|
||||
|
||||
#[doc = "Sends a `POST` request to `/v1/worker/task/{task}/append`"]
|
||||
///Sends a `POST` request to `/v1/worker/task/{task}/append`
|
||||
pub async fn worker_task_append<'a>(
|
||||
&'a self,
|
||||
task: &'a str,
|
||||
|
@ -362,9 +366,9 @@ impl Client {
|
|||
let url = format!(
|
||||
"{}/v1/worker/task/{}/append",
|
||||
self.baseurl,
|
||||
progenitor_client::encode_path(&task.to_string()),
|
||||
encode_path(&task.to_string()),
|
||||
);
|
||||
let request = self.client.post(url).json(body).build()?;
|
||||
let request = self.client.post(url).json(&body).build()?;
|
||||
let result = self.client.execute(request).await;
|
||||
let response = result?;
|
||||
match response.status().as_u16() {
|
||||
|
@ -373,7 +377,7 @@ impl Client {
|
|||
}
|
||||
}
|
||||
|
||||
#[doc = "Sends a `POST` request to `/v1/worker/task/{task}/chunk`"]
|
||||
///Sends a `POST` request to `/v1/worker/task/{task}/chunk`
|
||||
pub async fn worker_task_upload_chunk<'a, B: Into<reqwest::Body>>(
|
||||
&'a self,
|
||||
task: &'a str,
|
||||
|
@ -382,7 +386,7 @@ impl Client {
|
|||
let url = format!(
|
||||
"{}/v1/worker/task/{}/chunk",
|
||||
self.baseurl,
|
||||
progenitor_client::encode_path(&task.to_string()),
|
||||
encode_path(&task.to_string()),
|
||||
);
|
||||
let request = self.client.post(url).body(body).build()?;
|
||||
let result = self.client.execute(request).await;
|
||||
|
@ -393,7 +397,7 @@ impl Client {
|
|||
}
|
||||
}
|
||||
|
||||
#[doc = "Sends a `POST` request to `/v1/worker/task/{task}/complete`"]
|
||||
///Sends a `POST` request to `/v1/worker/task/{task}/complete`
|
||||
pub async fn worker_task_complete<'a>(
|
||||
&'a self,
|
||||
task: &'a str,
|
||||
|
@ -402,9 +406,9 @@ impl Client {
|
|||
let url = format!(
|
||||
"{}/v1/worker/task/{}/complete",
|
||||
self.baseurl,
|
||||
progenitor_client::encode_path(&task.to_string()),
|
||||
encode_path(&task.to_string()),
|
||||
);
|
||||
let request = self.client.post(url).json(body).build()?;
|
||||
let request = self.client.post(url).json(&body).build()?;
|
||||
let result = self.client.execute(request).await;
|
||||
let response = result?;
|
||||
match response.status().as_u16() {
|
||||
|
@ -413,7 +417,7 @@ impl Client {
|
|||
}
|
||||
}
|
||||
|
||||
#[doc = "Sends a `POST` request to `/v1/worker/task/{task}/output`"]
|
||||
///Sends a `POST` request to `/v1/worker/task/{task}/output`
|
||||
pub async fn worker_task_add_output<'a>(
|
||||
&'a self,
|
||||
task: &'a str,
|
||||
|
@ -422,9 +426,9 @@ impl Client {
|
|||
let url = format!(
|
||||
"{}/v1/worker/task/{}/output",
|
||||
self.baseurl,
|
||||
progenitor_client::encode_path(&task.to_string()),
|
||||
encode_path(&task.to_string()),
|
||||
);
|
||||
let request = self.client.post(url).json(body).build()?;
|
||||
let request = self.client.post(url).json(&body).build()?;
|
||||
let result = self.client.execute(request).await;
|
||||
let response = result?;
|
||||
match response.status().as_u16() {
|
||||
|
@ -433,7 +437,7 @@ impl Client {
|
|||
}
|
||||
}
|
||||
|
||||
#[doc = "Sends a `GET` request to `/v1/workers`"]
|
||||
///Sends a `GET` request to `/v1/workers`
|
||||
pub async fn workers_list<'a>(
|
||||
&'a self,
|
||||
) -> Result<ResponseValue<types::WorkersResult>, Error<()>> {
|
||||
|
@ -447,7 +451,7 @@ impl Client {
|
|||
}
|
||||
}
|
||||
|
||||
#[doc = "Sends a `POST` request to `/v1/workers/recycle`"]
|
||||
///Sends a `POST` request to `/v1/workers/recycle`
|
||||
pub async fn workers_recycle<'a>(&'a self) -> Result<ResponseValue<()>, Error<()>> {
|
||||
let url = format!("{}/v1/workers/recycle", self.baseurl,);
|
||||
let request = self.client.post(url).build()?;
|
|
@ -0,0 +1,418 @@
|
|||
#[allow(unused_imports)]
|
||||
use progenitor_client::encode_path;
|
||||
pub use progenitor_client::{ByteStream, Error, ResponseValue};
|
||||
pub mod types {
|
||||
use serde::{Deserialize, Serialize};
|
||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||
pub struct EnrolBody {
|
||||
pub host: String,
|
||||
pub key: String,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||
pub struct GlobalJobsResult {
|
||||
pub summary: Vec<ReportSummary>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||
pub struct OutputRecord {
|
||||
pub msg: String,
|
||||
pub stream: String,
|
||||
pub time: chrono::DateTime<chrono::offset::Utc>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||
pub struct PingResult {
|
||||
pub host: String,
|
||||
pub ok: bool,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||
pub struct ReportFinishBody {
|
||||
pub duration_millis: i32,
|
||||
pub end_time: chrono::DateTime<chrono::offset::Utc>,
|
||||
pub exit_status: i32,
|
||||
pub id: ReportId,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||
pub struct ReportId {
|
||||
pub host: String,
|
||||
pub job: String,
|
||||
pub pid: u64,
|
||||
pub time: chrono::DateTime<chrono::offset::Utc>,
|
||||
pub uuid: String,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||
pub struct ReportOutputBody {
|
||||
pub id: ReportId,
|
||||
pub record: OutputRecord,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||
pub struct ReportResult {
|
||||
pub existed_already: bool,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||
pub struct ReportStartBody {
|
||||
pub id: ReportId,
|
||||
pub script: String,
|
||||
pub start_time: chrono::DateTime<chrono::offset::Utc>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||
pub struct ReportSummary {
|
||||
pub age_seconds: i32,
|
||||
pub duration_seconds: i32,
|
||||
pub host: String,
|
||||
pub job: String,
|
||||
pub status: i32,
|
||||
pub when: chrono::DateTime<chrono::offset::Utc>,
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Client {
|
||||
pub(crate) baseurl: String,
|
||||
pub(crate) client: reqwest::Client,
|
||||
}
|
||||
|
||||
impl Client {
|
||||
pub fn new(baseurl: &str) -> Self {
|
||||
let dur = std::time::Duration::from_secs(15);
|
||||
let client = reqwest::ClientBuilder::new()
|
||||
.connect_timeout(dur)
|
||||
.timeout(dur)
|
||||
.build()
|
||||
.unwrap();
|
||||
Self::new_with_client(baseurl, client)
|
||||
}
|
||||
|
||||
pub fn new_with_client(baseurl: &str, client: reqwest::Client) -> Self {
|
||||
Self {
|
||||
baseurl: baseurl.to_string(),
|
||||
client,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn baseurl(&self) -> &String {
|
||||
&self.baseurl
|
||||
}
|
||||
|
||||
pub fn client(&self) -> &reqwest::Client {
|
||||
&self.client
|
||||
}
|
||||
}
|
||||
|
||||
impl Client {
|
||||
///Sends a `POST` request to `/enrol`
|
||||
///```ignore
|
||||
/// let response = client.enrol()
|
||||
/// .body(body)
|
||||
/// .send()
|
||||
/// .await;
|
||||
/// ```
|
||||
pub fn enrol(&self) -> builder::Enrol {
|
||||
builder::Enrol::new(self)
|
||||
}
|
||||
|
||||
///Sends a `GET` request to `/global/jobs`
|
||||
///```ignore
|
||||
/// let response = client.global_jobs()
|
||||
/// .send()
|
||||
/// .await;
|
||||
/// ```
|
||||
pub fn global_jobs(&self) -> builder::GlobalJobs {
|
||||
builder::GlobalJobs::new(self)
|
||||
}
|
||||
|
||||
///Sends a `GET` request to `/ping`
|
||||
///```ignore
|
||||
/// let response = client.ping()
|
||||
/// .send()
|
||||
/// .await;
|
||||
/// ```
|
||||
pub fn ping(&self) -> builder::Ping {
|
||||
builder::Ping::new(self)
|
||||
}
|
||||
|
||||
///Sends a `POST` request to `/report/finish`
|
||||
///```ignore
|
||||
/// let response = client.report_finish()
|
||||
/// .body(body)
|
||||
/// .send()
|
||||
/// .await;
|
||||
/// ```
|
||||
pub fn report_finish(&self) -> builder::ReportFinish {
|
||||
builder::ReportFinish::new(self)
|
||||
}
|
||||
|
||||
///Sends a `POST` request to `/report/output`
|
||||
///```ignore
|
||||
/// let response = client.report_output()
|
||||
/// .body(body)
|
||||
/// .send()
|
||||
/// .await;
|
||||
/// ```
|
||||
pub fn report_output(&self) -> builder::ReportOutput {
|
||||
builder::ReportOutput::new(self)
|
||||
}
|
||||
|
||||
///Sends a `POST` request to `/report/start`
|
||||
///```ignore
|
||||
/// let response = client.report_start()
|
||||
/// .body(body)
|
||||
/// .send()
|
||||
/// .await;
|
||||
/// ```
|
||||
pub fn report_start(&self) -> builder::ReportStart {
|
||||
builder::ReportStart::new(self)
|
||||
}
|
||||
}
|
||||
|
||||
pub mod builder {
|
||||
#[allow(unused_imports)]
|
||||
use super::encode_path;
|
||||
use super::types;
|
||||
#[allow(unused_imports)]
|
||||
use super::{ByteStream, Error, ResponseValue};
|
||||
///Builder for [`Client::enrol`]
|
||||
///
|
||||
///[`Client::enrol`]: super::Client::enrol
|
||||
#[derive(Clone)]
|
||||
pub struct Enrol<'a> {
|
||||
client: &'a super::Client,
|
||||
body: Option<types::EnrolBody>,
|
||||
}
|
||||
|
||||
impl<'a> Enrol<'a> {
|
||||
pub fn new(client: &'a super::Client) -> Self {
|
||||
Self { client, body: None }
|
||||
}
|
||||
|
||||
pub fn body(mut self, value: types::EnrolBody) -> Self {
|
||||
self.body = Some(value);
|
||||
self
|
||||
}
|
||||
|
||||
///Sends a `POST` request to `/enrol`
|
||||
pub async fn send(self) -> Result<ResponseValue<()>, Error<()>> {
|
||||
let Self { client, body } = self;
|
||||
let (body,) = match (body,) {
|
||||
(Some(body),) => (body,),
|
||||
(body,) => {
|
||||
let mut missing = Vec::new();
|
||||
if body.is_none() {
|
||||
missing.push(stringify!(body));
|
||||
}
|
||||
return Err(super::Error::InvalidRequest(format!(
|
||||
"the following parameters are required: {}",
|
||||
missing.join(", "),
|
||||
)));
|
||||
}
|
||||
};
|
||||
let url = format!("{}/enrol", client.baseurl,);
|
||||
let request = client.client.post(url).json(&body).build()?;
|
||||
let result = client.client.execute(request).await;
|
||||
let response = result?;
|
||||
match response.status().as_u16() {
|
||||
201u16 => Ok(ResponseValue::empty(response)),
|
||||
_ => Err(Error::UnexpectedResponse(response)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
///Builder for [`Client::global_jobs`]
|
||||
///
|
||||
///[`Client::global_jobs`]: super::Client::global_jobs
|
||||
#[derive(Clone)]
|
||||
pub struct GlobalJobs<'a> {
|
||||
client: &'a super::Client,
|
||||
}
|
||||
|
||||
impl<'a> GlobalJobs<'a> {
|
||||
pub fn new(client: &'a super::Client) -> Self {
|
||||
Self { client }
|
||||
}
|
||||
|
||||
///Sends a `GET` request to `/global/jobs`
|
||||
pub async fn send(self) -> Result<ResponseValue<types::GlobalJobsResult>, Error<()>> {
|
||||
let Self { client } = self;
|
||||
let url = format!("{}/global/jobs", client.baseurl,);
|
||||
let request = client.client.get(url).build()?;
|
||||
let result = client.client.execute(request).await;
|
||||
let response = result?;
|
||||
match response.status().as_u16() {
|
||||
201u16 => ResponseValue::from_response(response).await,
|
||||
_ => Err(Error::UnexpectedResponse(response)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
///Builder for [`Client::ping`]
|
||||
///
|
||||
///[`Client::ping`]: super::Client::ping
|
||||
#[derive(Clone)]
|
||||
pub struct Ping<'a> {
|
||||
client: &'a super::Client,
|
||||
}
|
||||
|
||||
impl<'a> Ping<'a> {
|
||||
pub fn new(client: &'a super::Client) -> Self {
|
||||
Self { client }
|
||||
}
|
||||
|
||||
///Sends a `GET` request to `/ping`
|
||||
pub async fn send(self) -> Result<ResponseValue<types::PingResult>, Error<()>> {
|
||||
let Self { client } = self;
|
||||
let url = format!("{}/ping", client.baseurl,);
|
||||
let request = client.client.get(url).build()?;
|
||||
let result = client.client.execute(request).await;
|
||||
let response = result?;
|
||||
match response.status().as_u16() {
|
||||
201u16 => ResponseValue::from_response(response).await,
|
||||
_ => Err(Error::UnexpectedResponse(response)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
///Builder for [`Client::report_finish`]
|
||||
///
|
||||
///[`Client::report_finish`]: super::Client::report_finish
|
||||
#[derive(Clone)]
|
||||
pub struct ReportFinish<'a> {
|
||||
client: &'a super::Client,
|
||||
body: Option<types::ReportFinishBody>,
|
||||
}
|
||||
|
||||
impl<'a> ReportFinish<'a> {
|
||||
pub fn new(client: &'a super::Client) -> Self {
|
||||
Self { client, body: None }
|
||||
}
|
||||
|
||||
pub fn body(mut self, value: types::ReportFinishBody) -> Self {
|
||||
self.body = Some(value);
|
||||
self
|
||||
}
|
||||
|
||||
///Sends a `POST` request to `/report/finish`
|
||||
pub async fn send(self) -> Result<ResponseValue<types::ReportResult>, Error<()>> {
|
||||
let Self { client, body } = self;
|
||||
let (body,) = match (body,) {
|
||||
(Some(body),) => (body,),
|
||||
(body,) => {
|
||||
let mut missing = Vec::new();
|
||||
if body.is_none() {
|
||||
missing.push(stringify!(body));
|
||||
}
|
||||
return Err(super::Error::InvalidRequest(format!(
|
||||
"the following parameters are required: {}",
|
||||
missing.join(", "),
|
||||
)));
|
||||
}
|
||||
};
|
||||
let url = format!("{}/report/finish", client.baseurl,);
|
||||
let request = client.client.post(url).json(&body).build()?;
|
||||
let result = client.client.execute(request).await;
|
||||
let response = result?;
|
||||
match response.status().as_u16() {
|
||||
201u16 => ResponseValue::from_response(response).await,
|
||||
_ => Err(Error::UnexpectedResponse(response)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
///Builder for [`Client::report_output`]
|
||||
///
|
||||
///[`Client::report_output`]: super::Client::report_output
|
||||
#[derive(Clone)]
|
||||
pub struct ReportOutput<'a> {
|
||||
client: &'a super::Client,
|
||||
body: Option<types::ReportOutputBody>,
|
||||
}
|
||||
|
||||
impl<'a> ReportOutput<'a> {
|
||||
pub fn new(client: &'a super::Client) -> Self {
|
||||
Self { client, body: None }
|
||||
}
|
||||
|
||||
pub fn body(mut self, value: types::ReportOutputBody) -> Self {
|
||||
self.body = Some(value);
|
||||
self
|
||||
}
|
||||
|
||||
///Sends a `POST` request to `/report/output`
|
||||
pub async fn send(self) -> Result<ResponseValue<types::ReportResult>, Error<()>> {
|
||||
let Self { client, body } = self;
|
||||
let (body,) = match (body,) {
|
||||
(Some(body),) => (body,),
|
||||
(body,) => {
|
||||
let mut missing = Vec::new();
|
||||
if body.is_none() {
|
||||
missing.push(stringify!(body));
|
||||
}
|
||||
return Err(super::Error::InvalidRequest(format!(
|
||||
"the following parameters are required: {}",
|
||||
missing.join(", "),
|
||||
)));
|
||||
}
|
||||
};
|
||||
let url = format!("{}/report/output", client.baseurl,);
|
||||
let request = client.client.post(url).json(&body).build()?;
|
||||
let result = client.client.execute(request).await;
|
||||
let response = result?;
|
||||
match response.status().as_u16() {
|
||||
201u16 => ResponseValue::from_response(response).await,
|
||||
_ => Err(Error::UnexpectedResponse(response)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
///Builder for [`Client::report_start`]
|
||||
///
|
||||
///[`Client::report_start`]: super::Client::report_start
|
||||
#[derive(Clone)]
|
||||
pub struct ReportStart<'a> {
|
||||
client: &'a super::Client,
|
||||
body: Option<types::ReportStartBody>,
|
||||
}
|
||||
|
||||
impl<'a> ReportStart<'a> {
|
||||
pub fn new(client: &'a super::Client) -> Self {
|
||||
Self { client, body: None }
|
||||
}
|
||||
|
||||
pub fn body(mut self, value: types::ReportStartBody) -> Self {
|
||||
self.body = Some(value);
|
||||
self
|
||||
}
|
||||
|
||||
///Sends a `POST` request to `/report/start`
|
||||
pub async fn send(self) -> Result<ResponseValue<types::ReportResult>, Error<()>> {
|
||||
let Self { client, body } = self;
|
||||
let (body,) = match (body,) {
|
||||
(Some(body),) => (body,),
|
||||
(body,) => {
|
||||
let mut missing = Vec::new();
|
||||
if body.is_none() {
|
||||
missing.push(stringify!(body));
|
||||
}
|
||||
return Err(super::Error::InvalidRequest(format!(
|
||||
"the following parameters are required: {}",
|
||||
missing.join(", "),
|
||||
)));
|
||||
}
|
||||
};
|
||||
let url = format!("{}/report/start", client.baseurl,);
|
||||
let request = client.client.post(url).json(&body).build()?;
|
||||
let result = client.client.execute(request).await;
|
||||
let response = result?;
|
||||
match response.status().as_u16() {
|
||||
201u16 => ResponseValue::from_response(response).await,
|
||||
_ => Err(Error::UnexpectedResponse(response)),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,418 @@
|
|||
#[allow(unused_imports)]
|
||||
use progenitor_client::encode_path;
|
||||
pub use progenitor_client::{ByteStream, Error, ResponseValue};
|
||||
pub mod types {
|
||||
use serde::{Deserialize, Serialize};
|
||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||
pub struct EnrolBody {
|
||||
pub host: String,
|
||||
pub key: String,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||
pub struct GlobalJobsResult {
|
||||
pub summary: Vec<ReportSummary>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||
pub struct OutputRecord {
|
||||
pub msg: String,
|
||||
pub stream: String,
|
||||
pub time: chrono::DateTime<chrono::offset::Utc>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||
pub struct PingResult {
|
||||
pub host: String,
|
||||
pub ok: bool,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||
pub struct ReportFinishBody {
|
||||
pub duration_millis: i32,
|
||||
pub end_time: chrono::DateTime<chrono::offset::Utc>,
|
||||
pub exit_status: i32,
|
||||
pub id: ReportId,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||
pub struct ReportId {
|
||||
pub host: String,
|
||||
pub job: String,
|
||||
pub pid: u64,
|
||||
pub time: chrono::DateTime<chrono::offset::Utc>,
|
||||
pub uuid: String,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||
pub struct ReportOutputBody {
|
||||
pub id: ReportId,
|
||||
pub record: OutputRecord,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||
pub struct ReportResult {
|
||||
pub existed_already: bool,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||
pub struct ReportStartBody {
|
||||
pub id: ReportId,
|
||||
pub script: String,
|
||||
pub start_time: chrono::DateTime<chrono::offset::Utc>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||
pub struct ReportSummary {
|
||||
pub age_seconds: i32,
|
||||
pub duration_seconds: i32,
|
||||
pub host: String,
|
||||
pub job: String,
|
||||
pub status: i32,
|
||||
pub when: chrono::DateTime<chrono::offset::Utc>,
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Client {
|
||||
pub(crate) baseurl: String,
|
||||
pub(crate) client: reqwest::Client,
|
||||
}
|
||||
|
||||
impl Client {
|
||||
pub fn new(baseurl: &str) -> Self {
|
||||
let dur = std::time::Duration::from_secs(15);
|
||||
let client = reqwest::ClientBuilder::new()
|
||||
.connect_timeout(dur)
|
||||
.timeout(dur)
|
||||
.build()
|
||||
.unwrap();
|
||||
Self::new_with_client(baseurl, client)
|
||||
}
|
||||
|
||||
pub fn new_with_client(baseurl: &str, client: reqwest::Client) -> Self {
|
||||
Self {
|
||||
baseurl: baseurl.to_string(),
|
||||
client,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn baseurl(&self) -> &String {
|
||||
&self.baseurl
|
||||
}
|
||||
|
||||
pub fn client(&self) -> &reqwest::Client {
|
||||
&self.client
|
||||
}
|
||||
}
|
||||
|
||||
impl Client {
|
||||
///Sends a `POST` request to `/enrol`
|
||||
///```ignore
|
||||
/// let response = client.enrol()
|
||||
/// .body(body)
|
||||
/// .send()
|
||||
/// .await;
|
||||
/// ```
|
||||
pub fn enrol(&self) -> builder::Enrol {
|
||||
builder::Enrol::new(self)
|
||||
}
|
||||
|
||||
///Sends a `GET` request to `/global/jobs`
|
||||
///```ignore
|
||||
/// let response = client.global_jobs()
|
||||
/// .send()
|
||||
/// .await;
|
||||
/// ```
|
||||
pub fn global_jobs(&self) -> builder::GlobalJobs {
|
||||
builder::GlobalJobs::new(self)
|
||||
}
|
||||
|
||||
///Sends a `GET` request to `/ping`
|
||||
///```ignore
|
||||
/// let response = client.ping()
|
||||
/// .send()
|
||||
/// .await;
|
||||
/// ```
|
||||
pub fn ping(&self) -> builder::Ping {
|
||||
builder::Ping::new(self)
|
||||
}
|
||||
|
||||
///Sends a `POST` request to `/report/finish`
|
||||
///```ignore
|
||||
/// let response = client.report_finish()
|
||||
/// .body(body)
|
||||
/// .send()
|
||||
/// .await;
|
||||
/// ```
|
||||
pub fn report_finish(&self) -> builder::ReportFinish {
|
||||
builder::ReportFinish::new(self)
|
||||
}
|
||||
|
||||
///Sends a `POST` request to `/report/output`
|
||||
///```ignore
|
||||
/// let response = client.report_output()
|
||||
/// .body(body)
|
||||
/// .send()
|
||||
/// .await;
|
||||
/// ```
|
||||
pub fn report_output(&self) -> builder::ReportOutput {
|
||||
builder::ReportOutput::new(self)
|
||||
}
|
||||
|
||||
///Sends a `POST` request to `/report/start`
|
||||
///```ignore
|
||||
/// let response = client.report_start()
|
||||
/// .body(body)
|
||||
/// .send()
|
||||
/// .await;
|
||||
/// ```
|
||||
pub fn report_start(&self) -> builder::ReportStart {
|
||||
builder::ReportStart::new(self)
|
||||
}
|
||||
}
|
||||
|
||||
pub mod builder {
|
||||
#[allow(unused_imports)]
|
||||
use super::encode_path;
|
||||
use super::types;
|
||||
#[allow(unused_imports)]
|
||||
use super::{ByteStream, Error, ResponseValue};
|
||||
///Builder for [`Client::enrol`]
|
||||
///
|
||||
///[`Client::enrol`]: super::Client::enrol
|
||||
#[derive(Clone)]
|
||||
pub struct Enrol<'a> {
|
||||
client: &'a super::Client,
|
||||
body: Option<types::EnrolBody>,
|
||||
}
|
||||
|
||||
impl<'a> Enrol<'a> {
|
||||
pub fn new(client: &'a super::Client) -> Self {
|
||||
Self { client, body: None }
|
||||
}
|
||||
|
||||
pub fn body(mut self, value: types::EnrolBody) -> Self {
|
||||
self.body = Some(value);
|
||||
self
|
||||
}
|
||||
|
||||
///Sends a `POST` request to `/enrol`
|
||||
pub async fn send(self) -> Result<ResponseValue<()>, Error<()>> {
|
||||
let Self { client, body } = self;
|
||||
let (body,) = match (body,) {
|
||||
(Some(body),) => (body,),
|
||||
(body,) => {
|
||||
let mut missing = Vec::new();
|
||||
if body.is_none() {
|
||||
missing.push(stringify!(body));
|
||||
}
|
||||
return Err(super::Error::InvalidRequest(format!(
|
||||
"the following parameters are required: {}",
|
||||
missing.join(", "),
|
||||
)));
|
||||
}
|
||||
};
|
||||
let url = format!("{}/enrol", client.baseurl,);
|
||||
let request = client.client.post(url).json(&body).build()?;
|
||||
let result = client.client.execute(request).await;
|
||||
let response = result?;
|
||||
match response.status().as_u16() {
|
||||
201u16 => Ok(ResponseValue::empty(response)),
|
||||
_ => Err(Error::UnexpectedResponse(response)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
///Builder for [`Client::global_jobs`]
|
||||
///
|
||||
///[`Client::global_jobs`]: super::Client::global_jobs
|
||||
#[derive(Clone)]
|
||||
pub struct GlobalJobs<'a> {
|
||||
client: &'a super::Client,
|
||||
}
|
||||
|
||||
impl<'a> GlobalJobs<'a> {
|
||||
pub fn new(client: &'a super::Client) -> Self {
|
||||
Self { client }
|
||||
}
|
||||
|
||||
///Sends a `GET` request to `/global/jobs`
|
||||
pub async fn send(self) -> Result<ResponseValue<types::GlobalJobsResult>, Error<()>> {
|
||||
let Self { client } = self;
|
||||
let url = format!("{}/global/jobs", client.baseurl,);
|
||||
let request = client.client.get(url).build()?;
|
||||
let result = client.client.execute(request).await;
|
||||
let response = result?;
|
||||
match response.status().as_u16() {
|
||||
201u16 => ResponseValue::from_response(response).await,
|
||||
_ => Err(Error::UnexpectedResponse(response)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
///Builder for [`Client::ping`]
|
||||
///
|
||||
///[`Client::ping`]: super::Client::ping
|
||||
#[derive(Clone)]
|
||||
pub struct Ping<'a> {
|
||||
client: &'a super::Client,
|
||||
}
|
||||
|
||||
impl<'a> Ping<'a> {
|
||||
pub fn new(client: &'a super::Client) -> Self {
|
||||
Self { client }
|
||||
}
|
||||
|
||||
///Sends a `GET` request to `/ping`
|
||||
pub async fn send(self) -> Result<ResponseValue<types::PingResult>, Error<()>> {
|
||||
let Self { client } = self;
|
||||
let url = format!("{}/ping", client.baseurl,);
|
||||
let request = client.client.get(url).build()?;
|
||||
let result = client.client.execute(request).await;
|
||||
let response = result?;
|
||||
match response.status().as_u16() {
|
||||
201u16 => ResponseValue::from_response(response).await,
|
||||
_ => Err(Error::UnexpectedResponse(response)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
///Builder for [`Client::report_finish`]
|
||||
///
|
||||
///[`Client::report_finish`]: super::Client::report_finish
|
||||
#[derive(Clone)]
|
||||
pub struct ReportFinish<'a> {
|
||||
client: &'a super::Client,
|
||||
body: Option<types::ReportFinishBody>,
|
||||
}
|
||||
|
||||
impl<'a> ReportFinish<'a> {
|
||||
pub fn new(client: &'a super::Client) -> Self {
|
||||
Self { client, body: None }
|
||||
}
|
||||
|
||||
pub fn body(mut self, value: types::ReportFinishBody) -> Self {
|
||||
self.body = Some(value);
|
||||
self
|
||||
}
|
||||
|
||||
///Sends a `POST` request to `/report/finish`
|
||||
pub async fn send(self) -> Result<ResponseValue<types::ReportResult>, Error<()>> {
|
||||
let Self { client, body } = self;
|
||||
let (body,) = match (body,) {
|
||||
(Some(body),) => (body,),
|
||||
(body,) => {
|
||||
let mut missing = Vec::new();
|
||||
if body.is_none() {
|
||||
missing.push(stringify!(body));
|
||||
}
|
||||
return Err(super::Error::InvalidRequest(format!(
|
||||
"the following parameters are required: {}",
|
||||
missing.join(", "),
|
||||
)));
|
||||
}
|
||||
};
|
||||
let url = format!("{}/report/finish", client.baseurl,);
|
||||
let request = client.client.post(url).json(&body).build()?;
|
||||
let result = client.client.execute(request).await;
|
||||
let response = result?;
|
||||
match response.status().as_u16() {
|
||||
201u16 => ResponseValue::from_response(response).await,
|
||||
_ => Err(Error::UnexpectedResponse(response)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
///Builder for [`Client::report_output`]
|
||||
///
|
||||
///[`Client::report_output`]: super::Client::report_output
|
||||
#[derive(Clone)]
|
||||
pub struct ReportOutput<'a> {
|
||||
client: &'a super::Client,
|
||||
body: Option<types::ReportOutputBody>,
|
||||
}
|
||||
|
||||
impl<'a> ReportOutput<'a> {
|
||||
pub fn new(client: &'a super::Client) -> Self {
|
||||
Self { client, body: None }
|
||||
}
|
||||
|
||||
pub fn body(mut self, value: types::ReportOutputBody) -> Self {
|
||||
self.body = Some(value);
|
||||
self
|
||||
}
|
||||
|
||||
///Sends a `POST` request to `/report/output`
|
||||
pub async fn send(self) -> Result<ResponseValue<types::ReportResult>, Error<()>> {
|
||||
let Self { client, body } = self;
|
||||
let (body,) = match (body,) {
|
||||
(Some(body),) => (body,),
|
||||
(body,) => {
|
||||
let mut missing = Vec::new();
|
||||
if body.is_none() {
|
||||
missing.push(stringify!(body));
|
||||
}
|
||||
return Err(super::Error::InvalidRequest(format!(
|
||||
"the following parameters are required: {}",
|
||||
missing.join(", "),
|
||||
)));
|
||||
}
|
||||
};
|
||||
let url = format!("{}/report/output", client.baseurl,);
|
||||
let request = client.client.post(url).json(&body).build()?;
|
||||
let result = client.client.execute(request).await;
|
||||
let response = result?;
|
||||
match response.status().as_u16() {
|
||||
201u16 => ResponseValue::from_response(response).await,
|
||||
_ => Err(Error::UnexpectedResponse(response)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
///Builder for [`Client::report_start`]
|
||||
///
|
||||
///[`Client::report_start`]: super::Client::report_start
|
||||
#[derive(Clone)]
|
||||
pub struct ReportStart<'a> {
|
||||
client: &'a super::Client,
|
||||
body: Option<types::ReportStartBody>,
|
||||
}
|
||||
|
||||
impl<'a> ReportStart<'a> {
|
||||
pub fn new(client: &'a super::Client) -> Self {
|
||||
Self { client, body: None }
|
||||
}
|
||||
|
||||
pub fn body(mut self, value: types::ReportStartBody) -> Self {
|
||||
self.body = Some(value);
|
||||
self
|
||||
}
|
||||
|
||||
///Sends a `POST` request to `/report/start`
|
||||
pub async fn send(self) -> Result<ResponseValue<types::ReportResult>, Error<()>> {
|
||||
let Self { client, body } = self;
|
||||
let (body,) = match (body,) {
|
||||
(Some(body),) => (body,),
|
||||
(body,) => {
|
||||
let mut missing = Vec::new();
|
||||
if body.is_none() {
|
||||
missing.push(stringify!(body));
|
||||
}
|
||||
return Err(super::Error::InvalidRequest(format!(
|
||||
"the following parameters are required: {}",
|
||||
missing.join(", "),
|
||||
)));
|
||||
}
|
||||
};
|
||||
let url = format!("{}/report/start", client.baseurl,);
|
||||
let request = client.client.post(url).json(&body).build()?;
|
||||
let result = client.client.execute(request).await;
|
||||
let response = result?;
|
||||
match response.status().as_u16() {
|
||||
201u16 => ResponseValue::from_response(response).await,
|
||||
_ => Err(Error::UnexpectedResponse(response)),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,3 +1,5 @@
|
|||
#[allow(unused_imports)]
|
||||
use progenitor_client::encode_path;
|
||||
pub use progenitor_client::{ByteStream, Error, ResponseValue};
|
||||
pub mod types {
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
@ -73,8 +75,8 @@ pub mod types {
|
|||
|
||||
#[derive(Clone)]
|
||||
pub struct Client {
|
||||
baseurl: String,
|
||||
client: reqwest::Client,
|
||||
pub(crate) baseurl: String,
|
||||
pub(crate) client: reqwest::Client,
|
||||
}
|
||||
|
||||
impl Client {
|
||||
|
@ -102,14 +104,16 @@ impl Client {
|
|||
pub fn client(&self) -> &reqwest::Client {
|
||||
&self.client
|
||||
}
|
||||
}
|
||||
|
||||
#[doc = "Sends a `POST` request to `/enrol`"]
|
||||
impl Client {
|
||||
///Sends a `POST` request to `/enrol`
|
||||
pub async fn enrol<'a>(
|
||||
&'a self,
|
||||
body: &'a types::EnrolBody,
|
||||
) -> Result<ResponseValue<()>, Error<()>> {
|
||||
let url = format!("{}/enrol", self.baseurl,);
|
||||
let request = self.client.post(url).json(body).build()?;
|
||||
let request = self.client.post(url).json(&body).build()?;
|
||||
let result = self.client.execute(request).await;
|
||||
let response = result?;
|
||||
match response.status().as_u16() {
|
||||
|
@ -118,7 +122,7 @@ impl Client {
|
|||
}
|
||||
}
|
||||
|
||||
#[doc = "Sends a `GET` request to `/global/jobs`"]
|
||||
///Sends a `GET` request to `/global/jobs`
|
||||
pub async fn global_jobs<'a>(
|
||||
&'a self,
|
||||
) -> Result<ResponseValue<types::GlobalJobsResult>, Error<()>> {
|
||||
|
@ -132,7 +136,7 @@ impl Client {
|
|||
}
|
||||
}
|
||||
|
||||
#[doc = "Sends a `GET` request to `/ping`"]
|
||||
///Sends a `GET` request to `/ping`
|
||||
pub async fn ping<'a>(&'a self) -> Result<ResponseValue<types::PingResult>, Error<()>> {
|
||||
let url = format!("{}/ping", self.baseurl,);
|
||||
let request = self.client.get(url).build()?;
|
||||
|
@ -144,13 +148,13 @@ impl Client {
|
|||
}
|
||||
}
|
||||
|
||||
#[doc = "Sends a `POST` request to `/report/finish`"]
|
||||
///Sends a `POST` request to `/report/finish`
|
||||
pub async fn report_finish<'a>(
|
||||
&'a self,
|
||||
body: &'a types::ReportFinishBody,
|
||||
) -> Result<ResponseValue<types::ReportResult>, Error<()>> {
|
||||
let url = format!("{}/report/finish", self.baseurl,);
|
||||
let request = self.client.post(url).json(body).build()?;
|
||||
let request = self.client.post(url).json(&body).build()?;
|
||||
let result = self.client.execute(request).await;
|
||||
let response = result?;
|
||||
match response.status().as_u16() {
|
||||
|
@ -159,13 +163,13 @@ impl Client {
|
|||
}
|
||||
}
|
||||
|
||||
#[doc = "Sends a `POST` request to `/report/output`"]
|
||||
///Sends a `POST` request to `/report/output`
|
||||
pub async fn report_output<'a>(
|
||||
&'a self,
|
||||
body: &'a types::ReportOutputBody,
|
||||
) -> Result<ResponseValue<types::ReportResult>, Error<()>> {
|
||||
let url = format!("{}/report/output", self.baseurl,);
|
||||
let request = self.client.post(url).json(body).build()?;
|
||||
let request = self.client.post(url).json(&body).build()?;
|
||||
let result = self.client.execute(request).await;
|
||||
let response = result?;
|
||||
match response.status().as_u16() {
|
||||
|
@ -174,13 +178,13 @@ impl Client {
|
|||
}
|
||||
}
|
||||
|
||||
#[doc = "Sends a `POST` request to `/report/start`"]
|
||||
///Sends a `POST` request to `/report/start`
|
||||
pub async fn report_start<'a>(
|
||||
&'a self,
|
||||
body: &'a types::ReportStartBody,
|
||||
) -> Result<ResponseValue<types::ReportResult>, Error<()>> {
|
||||
let url = format!("{}/report/start", self.baseurl,);
|
||||
let request = self.client.post(url).json(body).build()?;
|
||||
let request = self.client.post(url).json(&body).build()?;
|
||||
let result = self.client.execute(request).await;
|
||||
let response = result?;
|
||||
match response.status().as_u16() {
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -1,3 +1,5 @@
|
|||
#[allow(unused_imports)]
|
||||
use progenitor_client::encode_path;
|
||||
pub use progenitor_client::{ByteStream, Error, ResponseValue};
|
||||
pub mod types {
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
@ -20,7 +22,7 @@ pub mod types {
|
|||
pub yes: bool,
|
||||
}
|
||||
|
||||
#[doc = "Error information from a response."]
|
||||
///Error information from a response.
|
||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||
pub struct Error {
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
|
@ -32,8 +34,8 @@ pub mod types {
|
|||
|
||||
#[derive(Clone)]
|
||||
pub struct Client {
|
||||
baseurl: String,
|
||||
client: reqwest::Client,
|
||||
pub(crate) baseurl: String,
|
||||
pub(crate) client: reqwest::Client,
|
||||
}
|
||||
|
||||
impl Client {
|
||||
|
@ -61,14 +63,16 @@ impl Client {
|
|||
pub fn client(&self) -> &reqwest::Client {
|
||||
&self.client
|
||||
}
|
||||
}
|
||||
|
||||
#[doc = "Sends a `POST` request to ``"]
|
||||
impl Client {
|
||||
///Sends a `POST` request to ``
|
||||
pub async fn default_params<'a>(
|
||||
&'a self,
|
||||
body: &'a types::BodyWithDefaults,
|
||||
) -> Result<ResponseValue<ByteStream>, Error<ByteStream>> {
|
||||
let url = format!("{}", self.baseurl,);
|
||||
let request = self.client.post(url).json(body).build()?;
|
||||
let request = self.client.post(url).json(&body).build()?;
|
||||
let result = self.client.execute(request).await;
|
||||
let response = result?;
|
||||
match response.status().as_u16() {
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
#[allow(unused_imports)]
|
||||
use progenitor_client::encode_path;
|
||||
pub use progenitor_client::{ByteStream, Error, ResponseValue};
|
||||
pub mod types {
|
||||
use serde::{Deserialize, Serialize};
|
||||
#[doc = "Error information from a response."]
|
||||
///Error information from a response.
|
||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||
pub struct Error {
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
|
@ -13,8 +15,8 @@ pub mod types {
|
|||
|
||||
#[derive(Clone)]
|
||||
pub struct Client {
|
||||
baseurl: String,
|
||||
client: reqwest::Client,
|
||||
pub(crate) baseurl: String,
|
||||
pub(crate) client: reqwest::Client,
|
||||
}
|
||||
|
||||
impl Client {
|
||||
|
@ -42,8 +44,10 @@ impl Client {
|
|||
pub fn client(&self) -> &reqwest::Client {
|
||||
&self.client
|
||||
}
|
||||
}
|
||||
|
||||
#[doc = "Sends a `GET` request to ``"]
|
||||
impl Client {
|
||||
///Sends a `GET` request to ``
|
||||
pub async fn freeform_response<'a>(
|
||||
&'a self,
|
||||
) -> Result<ResponseValue<ByteStream>, Error<ByteStream>> {
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
#[allow(unused_imports)]
|
||||
use progenitor_client::encode_path;
|
||||
pub use progenitor_client::{ByteStream, Error, ResponseValue};
|
||||
pub mod types {
|
||||
use serde::{Deserialize, Serialize};
|
||||
#[doc = "Error information from a response."]
|
||||
///Error information from a response.
|
||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||
pub struct Error {
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
|
@ -13,8 +15,8 @@ pub mod types {
|
|||
|
||||
#[derive(Clone)]
|
||||
pub struct Client {
|
||||
baseurl: String,
|
||||
client: reqwest::Client,
|
||||
pub(crate) baseurl: String,
|
||||
pub(crate) client: reqwest::Client,
|
||||
}
|
||||
|
||||
impl Client {
|
||||
|
@ -42,8 +44,10 @@ impl Client {
|
|||
pub fn client(&self) -> &reqwest::Client {
|
||||
&self.client
|
||||
}
|
||||
}
|
||||
|
||||
#[doc = "Sends a `GET` request to `/{ref}/{type}/{trait}`"]
|
||||
impl Client {
|
||||
///Sends a `GET` request to `/{ref}/{type}/{trait}`
|
||||
pub async fn renamed_parameters<'a>(
|
||||
&'a self,
|
||||
ref_: &'a str,
|
||||
|
@ -56,9 +60,9 @@ impl Client {
|
|||
let url = format!(
|
||||
"{}/{}/{}/{}",
|
||||
self.baseurl,
|
||||
progenitor_client::encode_path(&ref_.to_string()),
|
||||
progenitor_client::encode_path(&type_.to_string()),
|
||||
progenitor_client::encode_path(&trait_.to_string()),
|
||||
encode_path(&ref_.to_string()),
|
||||
encode_path(&type_.to_string()),
|
||||
encode_path(&trait_.to_string()),
|
||||
);
|
||||
let mut query = Vec::new();
|
||||
query.push(("if", if_.to_string()));
|
||||
|
|
|
@ -2,36 +2,61 @@
|
|||
|
||||
use std::{fs::File, path::PathBuf};
|
||||
|
||||
use progenitor_impl::Generator;
|
||||
use progenitor_impl::{
|
||||
GenerationSettings, Generator, InterfaceStyle, TagStyle,
|
||||
};
|
||||
|
||||
#[track_caller]
|
||||
fn verify_file(openapi_file: &str) {
|
||||
fn verify_apis(openapi_file: &str) {
|
||||
let mut in_path = PathBuf::from("../sample_openapi");
|
||||
in_path.push(format!("{}.json", openapi_file));
|
||||
|
||||
let file = File::open(in_path).unwrap();
|
||||
let spec = serde_json::from_reader(file).unwrap();
|
||||
let mut generator = Generator::new();
|
||||
let output = generator.generate_text(&spec).unwrap();
|
||||
|
||||
let mut generator = Generator::default();
|
||||
let output = generator.generate_text_normalize_comments(&spec).unwrap();
|
||||
expectorate::assert_contents(
|
||||
format!("tests/output/{}.out", openapi_file),
|
||||
format!("tests/output/{}-positional.out", openapi_file),
|
||||
&output,
|
||||
)
|
||||
);
|
||||
|
||||
let mut generator = Generator::new(
|
||||
GenerationSettings::default()
|
||||
.with_interface(InterfaceStyle::Builder)
|
||||
.with_tag(TagStyle::Merged),
|
||||
);
|
||||
let output = generator.generate_text_normalize_comments(&spec).unwrap();
|
||||
expectorate::assert_contents(
|
||||
format!("tests/output/{}-builder.out", openapi_file),
|
||||
&output,
|
||||
);
|
||||
|
||||
let mut generator = Generator::new(
|
||||
GenerationSettings::default()
|
||||
.with_interface(InterfaceStyle::Builder)
|
||||
.with_tag(TagStyle::Separate),
|
||||
);
|
||||
let output = generator.generate_text_normalize_comments(&spec).unwrap();
|
||||
expectorate::assert_contents(
|
||||
format!("tests/output/{}-builder-tagged.out", openapi_file),
|
||||
&output,
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_keeper() {
|
||||
verify_file("keeper");
|
||||
verify_apis("keeper");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_buildomat() {
|
||||
verify_file("buildomat");
|
||||
verify_apis("buildomat");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_nexus() {
|
||||
verify_file("nexus");
|
||||
verify_apis("nexus");
|
||||
}
|
||||
|
||||
// TODO this file is full of inconsistencies and incorrectly specified types.
|
||||
|
@ -40,5 +65,5 @@ fn test_nexus() {
|
|||
#[ignore]
|
||||
#[test]
|
||||
fn test_github() {
|
||||
verify_file("api.github.com");
|
||||
verify_apis("api.github.com");
|
||||
}
|
||||
|
|
|
@ -64,8 +64,8 @@ fn test_renamed_parameters() {
|
|||
|
||||
let spec = serde_json::from_str::<OpenAPI>(out).unwrap();
|
||||
|
||||
let mut generator = Generator::new();
|
||||
let output = generator.generate_text(&spec).unwrap();
|
||||
let mut generator = Generator::default();
|
||||
let output = generator.generate_text_normalize_comments(&spec).unwrap();
|
||||
expectorate::assert_contents(
|
||||
format!("tests/output/{}.out", "test_renamed_parameters"),
|
||||
&output,
|
||||
|
@ -97,8 +97,8 @@ fn test_freeform_response() {
|
|||
let out = from_utf8(&out).unwrap();
|
||||
let spec = serde_json::from_str::<OpenAPI>(out).unwrap();
|
||||
|
||||
let mut generator = Generator::new();
|
||||
let output = generator.generate_text(&spec).unwrap();
|
||||
let mut generator = Generator::default();
|
||||
let output = generator.generate_text_normalize_comments(&spec).unwrap();
|
||||
expectorate::assert_contents(
|
||||
format!("tests/output/{}.out", "test_freeform_response"),
|
||||
&output,
|
||||
|
@ -145,8 +145,8 @@ fn test_default_params() {
|
|||
let out = from_utf8(&out).unwrap();
|
||||
let spec = serde_json::from_str::<OpenAPI>(out).unwrap();
|
||||
|
||||
let mut generator = Generator::new();
|
||||
let output = generator.generate_text(&spec).unwrap();
|
||||
let mut generator = Generator::default();
|
||||
let output = generator.generate_text_normalize_comments(&spec).unwrap();
|
||||
expectorate::assert_contents(
|
||||
format!("tests/output/{}.out", "test_default_params"),
|
||||
&output,
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
[package]
|
||||
name = "progenitor-macro"
|
||||
version = "0.1.2-dev"
|
||||
edition = "2018"
|
||||
edition = "2021"
|
||||
license = "MPL-2.0"
|
||||
repository = "https://github.com/oxidecomputer/progenitor.git"
|
||||
description = "An OpenAPI client generator - macros"
|
||||
|
|
|
@ -4,7 +4,9 @@ use std::path::Path;
|
|||
|
||||
use openapiv3::OpenAPI;
|
||||
use proc_macro::TokenStream;
|
||||
use progenitor_impl::Generator;
|
||||
use progenitor_impl::{
|
||||
GenerationSettings, Generator, InterfaceStyle, TagStyle,
|
||||
};
|
||||
use quote::{quote, ToTokens};
|
||||
use serde::Deserialize;
|
||||
use serde_tokenstream::ParseWrapper;
|
||||
|
@ -22,7 +24,8 @@ use syn::LitStr;
|
|||
/// ```ignore
|
||||
/// generate_api!(
|
||||
/// spec = "path/to/spec.json",
|
||||
/// [ inner_type = path::to:Type, ]
|
||||
/// [ interface = ( Positional | Builder ), ]
|
||||
/// [ tags = ( Merged | Separate ), ]
|
||||
/// [ pre_hook = closure::or::path::to::function, ]
|
||||
/// [ post_hook = closure::or::path::to::function, ]
|
||||
/// [ derives = [ path::to::DeriveMacro ], ]
|
||||
|
@ -32,6 +35,14 @@ use syn::LitStr;
|
|||
/// The `spec` key is required; it is the OpenAPI document from which the
|
||||
/// client is derived.
|
||||
///
|
||||
/// The optional `interface` lets you specify either a `Positional` argument or
|
||||
/// `Builder` argument style; `Positional` is the default.
|
||||
///
|
||||
/// The optional `tags` may be `Merged` in which case all operations are
|
||||
/// methods on the `Client` struct or `Separate` in which case each tag is
|
||||
/// represented by an "extension trait" that `Client` implements. The default
|
||||
/// is `Merged`.
|
||||
///
|
||||
/// The optional `inner_type` is for ancillary data, stored with the generated
|
||||
/// client that can be usd by the pre and post hooks.
|
||||
///
|
||||
|
@ -58,8 +69,12 @@ pub fn generate_api(item: TokenStream) -> TokenStream {
|
|||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
struct Settings {
|
||||
struct MacroSettings {
|
||||
spec: ParseWrapper<LitStr>,
|
||||
#[serde(default)]
|
||||
interface: InterfaceStyle,
|
||||
#[serde(default)]
|
||||
tags: TagStyle,
|
||||
inner_type: Option<ParseWrapper<syn::Type>>,
|
||||
pre_hook: Option<ParseWrapper<ClosureOrPath>>,
|
||||
post_hook: Option<ParseWrapper<ClosureOrPath>>,
|
||||
|
@ -67,6 +82,18 @@ struct Settings {
|
|||
derives: Vec<ParseWrapper<syn::Path>>,
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
enum GenerationStyle {
|
||||
Positional,
|
||||
Builder,
|
||||
}
|
||||
|
||||
impl Default for GenerationStyle {
|
||||
fn default() -> Self {
|
||||
Self::Positional
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct ClosureOrPath(proc_macro2::TokenStream);
|
||||
|
||||
|
@ -90,25 +117,35 @@ impl syn::parse::Parse for ClosureOrPath {
|
|||
}
|
||||
|
||||
fn do_generate_api(item: TokenStream) -> Result<TokenStream, syn::Error> {
|
||||
let (spec, inner_type, pre_hook, post_hook, derives) =
|
||||
if let Ok(spec) = syn::parse::<LitStr>(item.clone()) {
|
||||
(spec, None, None, None, Vec::new())
|
||||
} else {
|
||||
let Settings {
|
||||
spec,
|
||||
inner_type,
|
||||
pre_hook,
|
||||
post_hook,
|
||||
derives,
|
||||
} = serde_tokenstream::from_tokenstream(&item.into())?;
|
||||
(
|
||||
spec.into_inner(),
|
||||
inner_type.map(|x| x.into_inner()),
|
||||
pre_hook.map(|x| x.into_inner()),
|
||||
post_hook.map(|x| x.into_inner()),
|
||||
derives.into_iter().map(ParseWrapper::into_inner).collect(),
|
||||
)
|
||||
};
|
||||
let (spec, settings) = if let Ok(spec) = syn::parse::<LitStr>(item.clone())
|
||||
{
|
||||
(spec, GenerationSettings::default())
|
||||
} else {
|
||||
let MacroSettings {
|
||||
spec,
|
||||
interface,
|
||||
tags,
|
||||
inner_type,
|
||||
pre_hook,
|
||||
post_hook,
|
||||
derives,
|
||||
} = serde_tokenstream::from_tokenstream(&item.into())?;
|
||||
let mut settings = GenerationSettings::default();
|
||||
settings.with_interface(interface);
|
||||
settings.with_tag(tags);
|
||||
inner_type.map(|inner_type| {
|
||||
settings.with_inner_type(inner_type.to_token_stream())
|
||||
});
|
||||
pre_hook
|
||||
.map(|pre_hook| settings.with_pre_hook(pre_hook.into_inner().0));
|
||||
post_hook
|
||||
.map(|post_hook| settings.with_post_hook(post_hook.into_inner().0));
|
||||
|
||||
derives.into_iter().for_each(|derive| {
|
||||
settings.with_derive(derive.to_token_stream());
|
||||
});
|
||||
(spec.into_inner(), settings)
|
||||
};
|
||||
|
||||
let dir = std::env::var("CARGO_MANIFEST_DIR").map_or_else(
|
||||
|_| std::env::current_dir().unwrap(),
|
||||
|
@ -122,31 +159,22 @@ fn do_generate_api(item: TokenStream) -> Result<TokenStream, syn::Error> {
|
|||
serde_json::from_reader(std::fs::File::open(&path).map_err(|e| {
|
||||
syn::Error::new(
|
||||
spec.span(),
|
||||
format!("couldn't read file {}: {}", path_str, e.to_string()),
|
||||
format!("couldn't read file {}: {}", path_str, e),
|
||||
)
|
||||
})?)
|
||||
.map_err(|e| {
|
||||
syn::Error::new(
|
||||
spec.span(),
|
||||
format!("failed to parse {}: {}", path_str, e.to_string()),
|
||||
format!("failed to parse {}: {}", path_str, e),
|
||||
)
|
||||
})?;
|
||||
|
||||
let mut builder = Generator::new();
|
||||
inner_type.map(|inner_type| {
|
||||
builder.with_inner_type(inner_type.to_token_stream())
|
||||
});
|
||||
pre_hook.map(|pre_hook| builder.with_pre_hook(pre_hook.0));
|
||||
post_hook.map(|post_hook| builder.with_post_hook(post_hook.0));
|
||||
|
||||
derives.into_iter().for_each(|derive| {
|
||||
builder.with_derive(derive.to_token_stream());
|
||||
});
|
||||
let mut builder = Generator::new(&settings);
|
||||
|
||||
let code = builder.generate_tokens(&oapi).map_err(|e| {
|
||||
syn::Error::new(
|
||||
spec.span(),
|
||||
format!("generation error for {}: {}", spec.value(), e.to_string()),
|
||||
format!("generation error for {}: {}", spec.value(), e),
|
||||
)
|
||||
})?;
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
[package]
|
||||
name = "progenitor"
|
||||
version = "0.1.2-dev"
|
||||
edition = "2018"
|
||||
edition = "2021"
|
||||
license = "MPL-2.0"
|
||||
repository = "https://github.com/oxidecomputer/progenitor.git"
|
||||
description = "An OpenAPI client generator"
|
||||
|
@ -11,10 +11,10 @@ progenitor-client = { version = "0.1.2-dev", path = "../progenitor-client" }
|
|||
progenitor-impl = { version = "0.1.2-dev", path = "../progenitor-impl" }
|
||||
progenitor-macro = { version = "0.1.2-dev", path = "../progenitor-macro" }
|
||||
anyhow = "1.0"
|
||||
getopts = "0.2"
|
||||
openapiv3 = "1.0.0"
|
||||
serde = { version = "1.0", features = [ "derive" ] }
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
serde_json = "1.0"
|
||||
clap = { version = "3.2.8", features = ["derive"] }
|
||||
|
||||
[dev-dependencies]
|
||||
chrono = { version = "0.4", features = ["serde"] }
|
||||
|
|
|
@ -12,5 +12,8 @@
|
|||
|
||||
pub use progenitor_client;
|
||||
pub use progenitor_impl::Error;
|
||||
pub use progenitor_impl::GenerationSettings;
|
||||
pub use progenitor_impl::Generator;
|
||||
pub use progenitor_impl::InterfaceStyle;
|
||||
pub use progenitor_impl::TagStyle;
|
||||
pub use progenitor_macro::generate_api;
|
||||
|
|
|
@ -8,10 +8,64 @@ use std::{
|
|||
};
|
||||
|
||||
use anyhow::{bail, Result};
|
||||
use clap::{Parser, ValueEnum};
|
||||
use openapiv3::OpenAPI;
|
||||
use progenitor::Generator;
|
||||
use progenitor::{GenerationSettings, Generator, InterfaceStyle, TagStyle};
|
||||
use serde::Deserialize;
|
||||
|
||||
#[derive(Parser)]
|
||||
struct Args {
|
||||
/// OpenAPI definition document (JSON)
|
||||
#[clap(short = 'i', long)]
|
||||
input: String,
|
||||
/// Output directory for Rust crate
|
||||
#[clap(short = 'o', long)]
|
||||
output: String,
|
||||
/// Target Rust crate name
|
||||
#[clap(short = 'n', long)]
|
||||
name: String,
|
||||
/// Target Rust crate version
|
||||
#[clap(short = 'v', long)]
|
||||
version: String,
|
||||
|
||||
/// SDK interface style
|
||||
#[clap(value_enum, long, default_value_t = InterfaceArg::Positional)]
|
||||
interface: InterfaceArg,
|
||||
/// SDK tag style
|
||||
#[clap(value_enum, long, default_value_t = TagArg::Merged)]
|
||||
tags: TagArg,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, ValueEnum)]
|
||||
enum InterfaceArg {
|
||||
Positional,
|
||||
Builder,
|
||||
}
|
||||
|
||||
impl From<InterfaceArg> for InterfaceStyle {
|
||||
fn from(arg: InterfaceArg) -> Self {
|
||||
match arg {
|
||||
InterfaceArg::Positional => InterfaceStyle::Positional,
|
||||
InterfaceArg::Builder => InterfaceStyle::Builder,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, ValueEnum)]
|
||||
enum TagArg {
|
||||
Merged,
|
||||
Separate,
|
||||
}
|
||||
|
||||
impl From<TagArg> for TagStyle {
|
||||
fn from(arg: TagArg) -> Self {
|
||||
match arg {
|
||||
TagArg::Merged => TagStyle::Merged,
|
||||
TagArg::Separate => TagStyle::Separate,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn save<P>(p: P, data: &str) -> Result<()>
|
||||
where
|
||||
P: AsRef<Path>,
|
||||
|
@ -28,30 +82,15 @@ where
|
|||
}
|
||||
|
||||
fn main() -> Result<()> {
|
||||
let mut opts = getopts::Options::new();
|
||||
opts.parsing_style(getopts::ParsingStyle::StopAtFirstFree);
|
||||
opts.reqopt("i", "", "OpenAPI definition document (JSON)", "INPUT");
|
||||
opts.reqopt("o", "", "Generated Rust crate directory", "OUTPUT");
|
||||
opts.reqopt("n", "", "Target Rust crate name", "CRATE");
|
||||
opts.reqopt("v", "", "Target Rust crate version", "VERSION");
|
||||
let args = Args::parse();
|
||||
let api = load_api(&args.input)?;
|
||||
|
||||
let args = match opts.parse(std::env::args().skip(1)) {
|
||||
Ok(args) => {
|
||||
if !args.free.is_empty() {
|
||||
eprintln!("{}", opts.usage("progenitor"));
|
||||
bail!("unexpected positional arguments");
|
||||
}
|
||||
args
|
||||
}
|
||||
Err(e) => {
|
||||
eprintln!("{}", opts.usage("progenitor"));
|
||||
bail!(e);
|
||||
}
|
||||
};
|
||||
|
||||
let api = load_api(&args.opt_str("i").unwrap())?;
|
||||
|
||||
let mut builder = Generator::new();
|
||||
//let mut builder = Generator::default();
|
||||
let mut builder = Generator::new(
|
||||
GenerationSettings::default()
|
||||
.with_interface(args.interface.into())
|
||||
.with_tag(args.tags.into()),
|
||||
);
|
||||
|
||||
match builder.generate_text(&api) {
|
||||
Ok(api_code) => {
|
||||
|
@ -67,13 +106,13 @@ fn main() -> Result<()> {
|
|||
println!("-----------------------------------------------------");
|
||||
println!();
|
||||
|
||||
let name = args.opt_str("n").unwrap();
|
||||
let version = args.opt_str("v").unwrap();
|
||||
let name = &args.name;
|
||||
let version = &args.version;
|
||||
|
||||
/*
|
||||
* Create the top-level crate directory:
|
||||
*/
|
||||
let root = PathBuf::from(args.opt_str("o").unwrap());
|
||||
let root = PathBuf::from(&args.output);
|
||||
std::fs::create_dir_all(&root)?;
|
||||
|
||||
/*
|
||||
|
|
|
@ -1,3 +1,41 @@
|
|||
// Copyright 2021 Oxide Computer Company
|
||||
// Copyright 2022 Oxide Computer Company
|
||||
|
||||
progenitor::generate_api!("../sample_openapi/buildomat.json");
|
||||
mod positional {
|
||||
progenitor::generate_api!("../sample_openapi/buildomat.json");
|
||||
|
||||
fn _ignore() {
|
||||
let _ = Client::new("").worker_task_upload_chunk("task", vec![0]);
|
||||
}
|
||||
}
|
||||
|
||||
mod builder_untagged {
|
||||
progenitor::generate_api!(
|
||||
spec = "../sample_openapi/buildomat.json",
|
||||
interface = Builder,
|
||||
tags = Merged,
|
||||
);
|
||||
|
||||
fn _ignore() {
|
||||
let _ = Client::new("")
|
||||
.worker_task_upload_chunk()
|
||||
.task("task")
|
||||
.body(vec![0])
|
||||
.send();
|
||||
}
|
||||
}
|
||||
|
||||
mod builder_tagged {
|
||||
progenitor::generate_api!(
|
||||
spec = "../sample_openapi/buildomat.json",
|
||||
interface = Builder,
|
||||
tags = Separate,
|
||||
);
|
||||
|
||||
fn _ignore() {
|
||||
let _ = Client::new("")
|
||||
.worker_task_upload_chunk()
|
||||
.task("task")
|
||||
.body(vec![0])
|
||||
.send();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,3 +1,48 @@
|
|||
// Copyright 2021 Oxide Computer Company
|
||||
// Copyright 2022 Oxide Computer Company
|
||||
|
||||
progenitor::generate_api!("../sample_openapi/keeper.json");
|
||||
mod positional {
|
||||
progenitor::generate_api!("../sample_openapi/keeper.json");
|
||||
|
||||
fn _ignore() {
|
||||
let _ = Client::new("").enrol(&types::EnrolBody {
|
||||
host: "".to_string(),
|
||||
key: "".to_string(),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
mod builder_untagged {
|
||||
progenitor::generate_api!(
|
||||
spec = "../sample_openapi/keeper.json",
|
||||
interface = Builder,
|
||||
tags = Merged,
|
||||
);
|
||||
|
||||
fn _ignore() {
|
||||
let _ = Client::new("")
|
||||
.enrol()
|
||||
.body(types::EnrolBody {
|
||||
host: "".to_string(),
|
||||
key: "".to_string(),
|
||||
})
|
||||
.send();
|
||||
}
|
||||
}
|
||||
|
||||
mod builder_tagged {
|
||||
progenitor::generate_api!(
|
||||
spec = "../sample_openapi/keeper.json",
|
||||
interface = Builder,
|
||||
tags = Separate,
|
||||
);
|
||||
|
||||
fn _ignore() {
|
||||
let _ = Client::new("")
|
||||
.enrol()
|
||||
.body(types::EnrolBody {
|
||||
host: "".to_string(),
|
||||
key: "".to_string(),
|
||||
})
|
||||
.send();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,23 +1,74 @@
|
|||
// Copyright 2021 Oxide Computer Company
|
||||
|
||||
progenitor::generate_api!("../sample_openapi/nexus.json");
|
||||
mod positional {
|
||||
use futures::StreamExt;
|
||||
|
||||
pub async fn iteration_example() {
|
||||
let client = Client::new("xxx");
|
||||
mod nexus_client {
|
||||
progenitor::generate_api!("../sample_openapi/nexus.json");
|
||||
}
|
||||
|
||||
let bod = types::LoginParams {
|
||||
username: "ahl".to_string(),
|
||||
};
|
||||
use nexus_client::{types, Client};
|
||||
|
||||
let mut stream = client.spoof_login(&bod).await.unwrap();
|
||||
|
||||
loop {
|
||||
use futures::TryStreamExt;
|
||||
|
||||
match stream.try_next().await {
|
||||
Ok(Some(bytes)) => println!("bytes: {:?}", bytes),
|
||||
Ok(None) => break,
|
||||
Err(e) => panic!("{}", e),
|
||||
}
|
||||
fn _ignore() {
|
||||
let _ = async {
|
||||
let client = Client::new("");
|
||||
let org = types::Name("org".to_string());
|
||||
let project = types::Name("project".to_string());
|
||||
let instance = types::Name("instance".to_string());
|
||||
let stream = client.instance_disks_get_stream(
|
||||
&org, &project, &instance, None, None,
|
||||
);
|
||||
let _ = stream.collect::<Vec<_>>();
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
mod builder_untagged {
|
||||
use futures::StreamExt;
|
||||
|
||||
mod nexus_client {
|
||||
progenitor::generate_api!(
|
||||
spec = "../sample_openapi/nexus.json",
|
||||
interface = Builder,
|
||||
tags = Merged,
|
||||
);
|
||||
}
|
||||
|
||||
use nexus_client::{types, Client};
|
||||
|
||||
pub fn _ignore() {
|
||||
let client = Client::new("");
|
||||
let stream = client
|
||||
.instance_disks_get()
|
||||
.organization_name(types::Name("org".to_string()))
|
||||
.project_name(types::Name("project".to_string()))
|
||||
.instance_name(types::Name("instance".to_string()))
|
||||
.stream();
|
||||
let _ = stream.collect::<Vec<_>>();
|
||||
}
|
||||
}
|
||||
|
||||
mod builder_tagged {
|
||||
use futures::StreamExt;
|
||||
|
||||
mod nexus_client {
|
||||
progenitor::generate_api!(
|
||||
spec = "../sample_openapi/nexus.json",
|
||||
interface = Builder,
|
||||
tags = Separate,
|
||||
);
|
||||
}
|
||||
|
||||
use nexus_client::{types, Client, ClientInstancesExt};
|
||||
|
||||
fn _ignore() {
|
||||
let client = Client::new("");
|
||||
let stream = client
|
||||
.instance_disks_get()
|
||||
.organization_name(types::Name("org".to_string()))
|
||||
.project_name(types::Name("project".to_string()))
|
||||
.instance_name(types::Name("instance".to_string()))
|
||||
.stream();
|
||||
let _ = stream.collect::<Vec<_>>();
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue