changeset 15:88754a78780e

Correctly treat subresources
author Lewin Bormann <lbo@spheniscida.de>
date Sat, 17 Oct 2020 18:16:55 +0200
parents ca993cdce94d
children 3243f92caec1
files generate/generate.py manual_demo/src/main.rs
diffstat 2 files changed, 61 insertions(+), 31 deletions(-) [+]
line wrap: on
line diff
--- a/generate/generate.py	Sat Oct 17 17:45:11 2020 +0200
+++ b/generate/generate.py	Sat Oct 17 18:16:55 2020 +0200
@@ -22,12 +22,14 @@
 
 
 def capitalize_first(name):
+    if len(name) == 0:
+        return name
     return name[0].upper() + name[1:]
 
 
 def snake_case(name):
     def r(c):
-        if c.islower():
+        if not c.isupper():
             return c
         return '_' + c.lower()
 
@@ -144,16 +146,18 @@
     raise Exception('unknown scalar type:', jsont)
 
 
-def generate_parameter_types(resources):
+def generate_parameter_types(resources, super_name=''):
     """Generate parameter structs from the resources list.
 
     Returns a list of source code strings.
     """
-    structs = []
+    frags = []
+    print('processing:', resources.keys())
     for resourcename, resource in resources.items():
-        for methodname, method in resource['methods'].items():
-            print("processed:", resourcename, methodname)
-            struct = {'name': capitalize_first(resourcename) + capitalize_first(methodname) + 'Params', 'fields': []}
+        for methodname, method in resource.get('methods', {}).items():
+            param_type_name = capitalize_first(super_name)+capitalize_first(resourcename) + capitalize_first(methodname) + 'Params'
+            print("processed:", resourcename, methodname, param_type_name)
+            struct = {'name': param_type_name, 'fields': []}
             # Build struct dict for rendering.
             if 'parameters' in method:
                 for paramname, param in method['parameters'].items():
@@ -167,8 +171,11 @@
                         'attr':
                         '#[serde(rename = "{}")]'.format(paramname),
                     })
-            structs.append(struct)
-    return [chevron.render(ResourceStructTmpl, s) for s in structs]
+            frags.append(chevron.render(ResourceStructTmpl, struct))
+        # Generate parameter types for subresources.
+        frags.extend(
+                generate_parameter_types(resource.get('resources', {}), super_name=resourcename))
+    return frags
 
 
 def resolve_parameters(string, paramsname='params', suffix=''):
@@ -188,13 +195,15 @@
     Returns a rendered string with source code.
     """
     service = capitalize_first(resource)
-
-    parts = []
-
     method_fragments = []
+    subresource_fragments = []
 
     # Generate individual methods.
-    for methodname, method in methods['methods'].items():
+    for subresname, subresource in methods.get('resources', {}).items():
+        #subresource_fragments.extend(generate_parameter_types({service+capitalize_first(subresname): subresource}))
+        subresource_fragments.append(generate_service(service+capitalize_first(subresname), subresource, discdoc))
+
+    for methodname, method in methods.get('methods', {}).items():
         params_name = service + capitalize_first(methodname) + 'Params'
         parameters = {p: snake_case(p) for p, pp in method.get('parameters', {}).items() if 'required' not in pp}
         required_parameters = {p: snake_case(p) for p, pp in method.get('parameters', {}).items() if 'required' in pp}
@@ -210,7 +219,7 @@
 
         formatted_path, required_params = resolve_parameters(method['path'])
         data_normal = {
-            'name': methodname,
+            'name': snake_case(methodname),
             'param_type': params_name,
             'in_type': in_type,
             'out_type': out_type,
@@ -253,7 +262,7 @@
         'methods': [{
             'text': t
         } for t in method_fragments]
-    })
+    }) + '\n'.join(subresource_fragments)
 
 
 def generate_structs(discdoc):
@@ -278,6 +287,8 @@
             for field in s['fields']:
                 if field.get('comment', None):
                     field['comment'] = field['comment'].replace('\n', ' ')
+            if not s['name']:
+                print('WARN', s)
             f.write(chevron.render(ResourceStructTmpl, s))
         for pt in parameter_types:
             f.write(pt)
--- a/manual_demo/src/main.rs	Sat Oct 17 17:45:11 2020 +0200
+++ b/manual_demo/src/main.rs	Sat Oct 17 18:16:55 2020 +0200
@@ -1,14 +1,15 @@
 // A manual client for a Google API (e.g. Drive), to test what makes sense and what doesn't.
 
 mod drive_v3_types;
+mod storage_v1_types;
 
 use drive_v3_types as drive;
 
-use yup_oauth2::InstalledFlowAuthenticator;
-use std::string::String;
+use std::fs;
+use std::path::Path;
 use std::str::FromStr;
-use std::path::Path;
-use std::fs;
+use std::string::String;
+use yup_oauth2::InstalledFlowAuthenticator;
 
 use hyper::Uri;
 use hyper_rustls::HttpsConnector;
@@ -25,19 +26,26 @@
 
 struct FilesService {
     client: TlsClient,
-    authenticator: Authenticator
+    authenticator: Authenticator,
 }
 
 impl FilesService {
-    fn create(&mut self, parameters: drive::FilesCreateParams, file: drive::File, data: &hyper::body::Bytes) -> hyper::Result<drive::File> {
-
+    fn create(
+        &mut self,
+        parameters: drive::FilesCreateParams,
+        file: drive::File,
+        data: &hyper::body::Bytes,
+    ) -> hyper::Result<drive::File> {
         unimplemented!()
     }
 }
 
 async fn upload_file(cl: &mut TlsClient, auth: &mut Authenticator, f: &Path) {
     let posturl = "https://www.googleapis.com/upload/drive/v3/files?uploadType=media";
-    let tok = auth.token(&["https://www.googleapis.com/auth/drive.file"]).await.unwrap();
+    let tok = auth
+        .token(&["https://www.googleapis.com/auth/drive.file"])
+        .await
+        .unwrap();
     let authtok = format!("&oauth_token={}&fields=*", tok.as_str());
 
     let file = fs::OpenOptions::new().read(true).open(f).unwrap();
@@ -45,8 +53,10 @@
 
     let bytes = hyper::body::Bytes::from(fs::read(&f).unwrap());
     let body = hyper::Body::from(bytes);
-    let req = hyper::Request::post(posturl.to_string()+&authtok).header("Content-Length", format!("{}", len))
-        .body(body).unwrap();
+    let req = hyper::Request::post(posturl.to_string() + &authtok)
+        .header("Content-Length", format!("{}", len))
+        .body(body)
+        .unwrap();
     let resp = cl.request(req).await.unwrap();
 
     let body = resp.into_body();
@@ -86,10 +96,16 @@
 async fn get_about(cl: &mut TlsClient, auth: &mut Authenticator) {
     let baseurl = "https://www.googleapis.com/drive/v3/";
     let path = "about";
-    let tok = auth.token(&["https://www.googleapis.com/auth/drive.file"]).await.unwrap();
+    let tok = auth
+        .token(&["https://www.googleapis.com/auth/drive.file"])
+        .await
+        .unwrap();
     let authtok = format!("?oauth_token={}&fields=*", tok.as_str());
 
-    let resp = cl.get(Uri::from_str(&(String::from(baseurl)+path+&authtok)).unwrap()).await.unwrap();
+    let resp = cl
+        .get(Uri::from_str(&(String::from(baseurl) + path + &authtok)).unwrap())
+        .await
+        .unwrap();
     let body = resp.into_body();
     let body = hyper::body::to_bytes(body).await.unwrap();
     let dec = String::from_utf8(body.to_vec()).unwrap();
@@ -103,11 +119,14 @@
         .await
         .expect("client secret couldn't be read.");
 
-    let mut auth = InstalledFlowAuthenticator::builder(sec, yup_oauth2::InstalledFlowReturnMethod::HTTPRedirect)
-        .persist_tokens_to_disk("tokencache.json")
-        .build()
-        .await
-        .expect("installed flow authenticator!");
+    let mut auth = InstalledFlowAuthenticator::builder(
+        sec,
+        yup_oauth2::InstalledFlowReturnMethod::HTTPRedirect,
+    )
+    .persist_tokens_to_disk("tokencache.json")
+    .build()
+    .await
+    .expect("installed flow authenticator!");
 
     let scopes = &["https://www.googleapis.com/auth/drive.file"];