Merge branch 'common-cli-crate'

This commit is contained in:
Sebastian Thiel
2022-09-29 09:11:08 +08:00
12 changed files with 166 additions and 207 deletions

View File

@@ -1,35 +1,8 @@
# DO NOT PUBLISH
# This library is just to try out the code that should ultimately go into the code generator !
[package]
[workspace]
name = "client"
version = "0.0.1"
authors = ["Sebastian Thiel <byronimo@gmail.com>"]
description = "A library to facilitate interacting with your youtube account"
repository = "https://github.com/Byron/google-apis-rs"
license = "MIT/Apache-2.0"
keywords = ["youtube", "google", "protocol", "not-for-use"]
edition = "2018"
publish = false
[lib]
# The common client code, used by all generated implementations
name = "client"
path = "src/rust/lib.rs"
[dependencies]
google-apis-common = { version = "4.0", path = "google-apis-common" }
clap = "2"
http = "^0.2"
hyper = "0.14"
mime = "0.2"
rustc-serialize = "*"
yup-oauth2 = "^ 7.0"
serde = "1"
serde_json = "1"
serde_derive = "1"
strsim = "*"
tokio = "^ 1.0"
hyper-rustls = "^0.22"
itertools = "^ 0.10"
tower-service = "^0.3"
members = [
"google-apis-common",
"google-clis-common",
"src/rust/preproc"
]
exclude = ["gen"]

View File

@@ -10,6 +10,8 @@ license = "MIT"
keywords = ["google", "web", "api", "common"]
edition = "2021"
[lib]
doctest = false
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
@@ -26,4 +28,5 @@ http = "^0.2"
tokio = "^1.0"
tower-service = "^0.3.1"
[dev-dependencies]
serde = { version = "^ 1.0", features = ["derive"] }

View File

@@ -861,3 +861,71 @@ mod yup_oauth2_impl {
}
}
}
#[cfg(test)]
mod test_api {
use super::*;
use std::default::Default;
use std::str::FromStr;
use serde_json as json;
use serde::{Serialize, Deserialize};
#[test]
fn serde() {
#[derive(Default, Serialize, Deserialize)]
struct Foo {
opt: Option<String>,
req: u32,
opt_vec: Option<Vec<String>>,
vec: Vec<String>,
}
let f: Foo = Default::default();
json::to_string(&f).unwrap(); // should work
let j = "{\"opt\":null,\"req\":0,\"vec\":[]}";
let _f: Foo = json::from_str(j).unwrap();
// This fails, unless 'vec' is optional
// let j = "{\"opt\":null,\"req\":0}";
// let f: Foo = json::from_str(j).unwrap();
#[derive(Default, Serialize, Deserialize)]
struct Bar {
#[serde(rename = "snooSnoo")]
snoo_snoo: String,
}
json::to_string(&<Bar as Default>::default()).unwrap();
let j = "{\"snooSnoo\":\"foo\"}";
let b: Bar = json::from_str(&j).unwrap();
assert_eq!(b.snoo_snoo, "foo");
// We can't have unknown fields with structs.
// #[derive(Default, Serialize, Deserialize)]
// struct BarOpt {
// #[serde(rename="snooSnoo")]
// snoo_snoo: Option<String>
// }
// let j = "{\"snooSnoo\":\"foo\",\"foo\":\"bar\"}";
// let b: BarOpt = json::from_str(&j).unwrap();
}
#[test]
fn byte_range_from_str() {
assert_eq!(
<Chunk as FromStr>::from_str("2-42"),
Ok(Chunk { first: 2, last: 42 })
)
}
#[test]
fn dyn_delegate_is_send() {
fn with_send(_x: impl Send) {}
let mut dd = DefaultDelegate::default();
let dlg: &mut dyn Delegate = &mut dd;
with_send(dlg);
}
}

View File

@@ -0,0 +1,24 @@
# DO NOT PUBLISH
# This library is just to try out the code that should ultimately go into the code generator !
[package]
name = "google-clis-common"
version = "4.0.0"
authors = ["Sebastian Thiel <byronimo@gmail.com>"]
repository = "https://github.com/Byron/google-apis-rs"
homepage = "https://github.com/Byron/google-apis-rs/google-clis-common"
documentation = "https://docs.rs/google-clis-common"
description = "Shared functionality among the google-api CLI crates."
license = "MIT"
keywords = ["google", "web", "api", "cli", "common"]
edition = "2021"
[lib]
doctest = false
[dependencies]
mime = "0.2"
yup-oauth2 = "^ 7.0"
serde = "1"
serde_json = "1"
strsim = "*"
clap = "2"

View File

@@ -1,16 +1,15 @@
use clap::{App, SubCommand};
use mime::Mime;
use crate::oauth2::{ApplicationSecret, ConsoleApplicationSecret};
use yup_oauth2::{ApplicationSecret, ConsoleApplicationSecret};
use serde_json as json;
use serde_json::value::Value;
use clap::arg_enum;
use std::env;
use std::error::Error as StdError;
use std::fmt;
use std::fs;
use std::io;
use std::io::{stdout, Read, Write};
use std::path::{Path, PathBuf};
use std::io::{stdout, Write};
use std::path::Path;
use std::str::FromStr;
use std::string::ToString;
@@ -230,7 +229,7 @@ impl FieldCursor {
}
};
for (cid, c) in value.chars().enumerate() {
for c in value.chars() {
if c == FIELD_SEP {
if last_c != FIELD_SEP {
push_field(&mut output, &mut field);
@@ -370,7 +369,7 @@ pub fn calltype_from_str(
) -> CallType {
CallType::Upload(match UploadProtocol::from_str(name) {
Ok(up) => up,
Err(msg) => {
Err(_msg) => {
err.issues.push(CLIError::InvalidUploadProtocol(
name.to_string(),
valid_protocols,
@@ -744,3 +743,48 @@ pub fn application_secret_from_directory(
}
unreachable!();
}
#[cfg(test)]
mod test_cli {
use super::*;
use std::default::Default;
#[test]
fn cursor() {
let mut c: FieldCursor = Default::default();
assert_eq!(c.to_string(), "");
assert_eq!(c.num_fields(), 0);
assert!(c.set("").is_err());
assert!(c.set(".").is_ok());
assert!(c.set("..").is_err());
assert_eq!(c.num_fields(), 0);
assert!(c.set("foo").is_ok());
assert_eq!(c.to_string(), "foo");
assert_eq!(c.num_fields(), 1);
assert!(c.set("..").is_ok());
assert_eq!(c.num_fields(), 0);
assert_eq!(c.to_string(), "");
assert!(c.set("foo.").is_err());
assert!(c.set("foo.bar").is_ok());
assert_eq!(c.num_fields(), 2);
assert_eq!(c.to_string(), "foo.bar");
assert!(c.set("sub.level").is_ok());
assert_eq!(c.num_fields(), 4);
assert_eq!(c.to_string(), "foo.bar.sub.level");
assert!(c.set("...other").is_ok());
assert_eq!(c.to_string(), "foo.bar.other");
assert_eq!(c.num_fields(), 3);
assert!(c.set(".one.two.three...beer").is_ok());
assert_eq!(c.num_fields(), 2);
assert_eq!(c.to_string(), "one.beer");
assert!(c.set("one.two.three...").is_ok());
assert_eq!(c.num_fields(), 3);
assert_eq!(c.to_string(), "one.beer.one");
}
}

View File

@@ -34,7 +34,9 @@ mime = "^ 0.2.0"
serde = { version = "^ 1.0", features = ["derive"] }
serde_json = "^ 1.0"
itertools = "^ 0.10"
% if 'is_executable' not in cargo:
% if cargo.get('is_executable', False):
google-clis-common = { path = "../../google-clis-common", version = "4.0" }
% else:
google-apis-common = { path = "../../google-apis-common", version = "4.0" }
% endif
% for dep in cargo.get('dependencies', list()):

View File

@@ -14,8 +14,6 @@
</%block>
#![allow(unused_variables, unused_imports, dead_code, unused_mut)]
extern crate tokio;
#[macro_use]
extern crate clap;
@@ -25,7 +23,7 @@ use clap::{App, SubCommand, Arg};
use ${to_extern_crate_name(library_to_crate_name(library_name(name, version), make.depends_on_suffix))}::{api, Error, oauth2};
mod client;
use google_clis_common as client;
${engine.new(c)}\

View File

@@ -105,12 +105,9 @@
print('Could not open JSON file at {}'.format(api_json))
print(e)
%>\
${api_common}: $(RUST_SRC)/${make.id}/client.rs $(lastword $(MAKEFILE_LIST)) ${gen_root_stamp}
@ echo "// COPY OF '$<'" > $@
@ echo "// DO NOT EDIT" >> $@
@cat $< >> $@
${api_common}: ${gen_root_stamp}
${gen_root_stamp}: $(MAKO_RENDER) ${' '.join(i[0] for i in sds)} ${api_json_inputs} $(MAKO_STANDARD_DEPENDENCIES) ${depends_on_target}
${gen_root_stamp}: $(MAKO_RENDER) ${' '.join(i[0] for i in sds)} ${api_json_inputs} $(MAKO_STANDARD_DEPENDENCIES)
@echo Generating ${api_target}
$(MAKO) -io ${' '.join("%s=%s" % (s, d) for s, d in sds)} ${post_processor_arg} --data-files ${api_json_inputs}
@touch $@

View File

@@ -1,2 +0,0 @@
//! This file serves on purpose and is an artifact of the buildsystem.
//! Its content can now be found in the `google-apis-common` crate.

View File

@@ -1 +0,0 @@
pub mod client;

View File

@@ -1,153 +0,0 @@
#![allow(
dead_code,
deprecated,
unused_features,
unused_variables,
unused_imports
)]
#[macro_use]
extern crate clap;
#[macro_use]
extern crate hyper;
extern crate mime;
extern crate rustc_serialize;
extern crate serde;
extern crate serde_json;
extern crate yup_oauth2 as oauth2;
#[macro_use]
extern crate serde_derive;
extern crate strsim;
// just pull it in the check if it compiles
mod cli;
use google_apis_common as api;
/// This module is for testing only, its code is used in mako templates
#[cfg(test)]
mod test_api {
use super::api::*;
use hyper;
use std::default::Default;
use std::io::Read;
use std::str::FromStr;
use serde_json as json;
const EXPECTED: &'static str = "\r\n--MDuXWGyeE33QFXGchb2VFWc4Z7945d\r\n\
Content-Length: 50\r\n\
Content-Type: application/json\r\n\
\r\n\
foo\r\n\
--MDuXWGyeE33QFXGchb2VFWc4Z7945d\r\n\
Content-Length: 25\r\n\
Content-Type: application/plain\r\n\
\r\n\
bar\r\n\
--MDuXWGyeE33QFXGchb2VFWc4Z7945d--";
const EXPECTED_LEN: usize = 223;
#[test]
fn serde() {
#[derive(Default, Serialize, Deserialize)]
struct Foo {
opt: Option<String>,
req: u32,
opt_vec: Option<Vec<String>>,
vec: Vec<String>,
}
let f: Foo = Default::default();
json::to_string(&f).unwrap(); // should work
let j = "{\"opt\":null,\"req\":0,\"vec\":[]}";
let f: Foo = json::from_str(j).unwrap();
// This fails, unless 'vec' is optional
// let j = "{\"opt\":null,\"req\":0}";
// let f: Foo = json::from_str(j).unwrap();
#[derive(Default, Serialize, Deserialize)]
struct Bar {
#[serde(rename = "snooSnoo")]
snoo_snoo: String,
}
json::to_string(&<Bar as Default>::default()).unwrap();
let j = "{\"snooSnoo\":\"foo\"}";
let b: Bar = json::from_str(&j).unwrap();
assert_eq!(b.snoo_snoo, "foo");
// We can't have unknown fields with structs.
// #[derive(Default, Serialize, Deserialize)]
// struct BarOpt {
// #[serde(rename="snooSnoo")]
// snoo_snoo: Option<String>
// }
// let j = "{\"snooSnoo\":\"foo\",\"foo\":\"bar\"}";
// let b: BarOpt = json::from_str(&j).unwrap();
}
#[test]
fn byte_range_from_str() {
assert_eq!(
<Chunk as FromStr>::from_str("2-42"),
Ok(Chunk { first: 2, last: 42 })
)
}
#[test]
fn dyn_delegate_is_send() {
fn with_send(x: impl Send) {}
let mut dd = DefaultDelegate::default();
let dlg: &mut dyn Delegate = &mut dd;
with_send(dlg);
}
}
#[cfg(test)]
mod test_cli {
use super::cli::client::*;
use std::default::Default;
#[test]
fn cursor() {
let mut c: FieldCursor = Default::default();
assert_eq!(c.to_string(), "");
assert_eq!(c.num_fields(), 0);
assert!(c.set("").is_err());
assert!(c.set(".").is_ok());
assert!(c.set("..").is_err());
assert_eq!(c.num_fields(), 0);
assert!(c.set("foo").is_ok());
assert_eq!(c.to_string(), "foo");
assert_eq!(c.num_fields(), 1);
assert!(c.set("..").is_ok());
assert_eq!(c.num_fields(), 0);
assert_eq!(c.to_string(), "");
assert!(c.set("foo.").is_err());
assert!(c.set("foo.bar").is_ok());
assert_eq!(c.num_fields(), 2);
assert_eq!(c.to_string(), "foo.bar");
assert!(c.set("sub.level").is_ok());
assert_eq!(c.num_fields(), 4);
assert_eq!(c.to_string(), "foo.bar.sub.level");
assert!(c.set("...other").is_ok());
assert_eq!(c.to_string(), "foo.bar.other");
assert_eq!(c.num_fields(), 3);
assert!(c.set(".one.two.three...beer").is_ok());
assert_eq!(c.num_fields(), 2);
assert_eq!(c.to_string(), "one.beer");
assert!(c.set("one.two.three...").is_ok());
assert_eq!(c.num_fields(), 3);
assert_eq!(c.to_string(), "one.beer.one");
}
}

View File

@@ -5,6 +5,12 @@ authors = ["Sebastian Thiel <sthiel@thoughtworks.com>"]
edition = "2018"
publish = false
[[bin]]
name = "preproc"
path = "src/main.rs"
doctest = false
test = false
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]