diff --git a/Makefile b/Makefile index b2cf58591aa..92b565985d3 100644 --- a/Makefile +++ b/Makefile @@ -16,7 +16,7 @@ API_DEPS = .api.deps API_SHARED_INFO = etc/api/shared.yaml API_JSON_FILES = $(shell find etc -type f -name '*-api.json') MAKO_LIB_DIR = $(MAKO_SRC)/lib -MAKO_LIB_FILES = $(shell find $(MAKO_LIB_DIR) -type f -name '*.mako' -or -name '*.py') +MAKO_LIB_FILES = $(shell find $(MAKO_LIB_DIR) -type f -name '*.*') help: $(info using template engine: '$(TPL)') diff --git a/src/mako/lib.rs.mako b/src/mako/lib.rs.mako index 3f64c4c2019..5551aa4b8c7 100644 --- a/src/mako/lib.rs.mako +++ b/src/mako/lib.rs.mako @@ -19,6 +19,8 @@ extern crate "yup-oauth2" as oauth2; use std::collections::HashMap; +use cmn::{Resource, Part, ResponseResult, RequestResult, NestedType}; + // ############ // SCHEMAS ### // ########## diff --git a/src/mako/lib/schema.mako b/src/mako/lib/schema.mako index 4b9311da494..9c0ae36607b 100644 --- a/src/mako/lib/schema.mako +++ b/src/mako/lib/schema.mako @@ -2,7 +2,10 @@ ## Create new schema with everything. ## 's' contains the schema structure from json to build <%def name="new(s, c)">\ -<% assert s.type == "object" %>\ +<% + assert s.type == "object" + markers = util.schema_markers(s, c) +%>\ <%block filter="util.rust_doc_comment">\ ${doc(s, c)}\ @@ -18,6 +21,10 @@ pub struct ${s.id}\ % else: ; % endif + +% for marker_trait in markers: +impl ${marker_trait} for ${s.id} {} +% endfor <%def name="doc(s, c)">\ @@ -26,7 +33,11 @@ ${s.get('description', 'There is no detailed description.')} # Activities -${''.join("* %s\n" % a for a in c.sta_map[s.id].keys())} +This type is used in activities, which are methods you may call on this type or where this type is involved in. +The list links the activity name, along with information about where it is used (one of ${util.put_and(util.IO_TYPES)}. + +${''.join("* %s (%s)\n" % (util.activity_split(a)[1], iot and '|'.join(iot) or 'none') + for a, iot in c.sta_map[s.id].iteritems())} % else: This schema type is not used in any activity, and only used as *part* of another schema. diff --git a/src/mako/lib/util.py b/src/mako/lib/util.py index 74ca01cb36c..fd01bd0b4f3 100644 --- a/src/mako/lib/util.py +++ b/src/mako/lib/util.py @@ -14,9 +14,14 @@ 'string' : 'String', 'object' : 'HashMap'} TREF = '$ref' +IO_RESPONSE = 'response' +IO_REQUEST = 'request' +IO_TYPES = (IO_REQUEST, IO_RESPONSE) INS_METHOD = 'insert' DEL_METHOD = 'delete' +NESTED_TYPE_MARKER = 'is_nested' + # ============================================================================== ## @name Filters # ------------------------------------------------------------------------------ @@ -79,7 +84,7 @@ def nested_type(nt): elif nt.get('additionalProperties'): nt = nt.additionalProperties else: - assert(is_nested_type(nt)) + assert(is_nested_type_property(nt)) # It's a nested type - we take it literally like $ref, but generate a name for the type ourselves # This of course assumes return nested_type_name(sn, pn) @@ -112,8 +117,13 @@ def nested_type(nt): except AttributeError as err: raise AssertionError("%s: unknown dict layout: %s" % (str(err), t)) -def is_nested_type(t): - return 'type' in t and t.type == 'object' and 'additionalProperties' not in t +# return True if this property is actually a nested type +def is_nested_type_property(t): + return 'type' in t and t.type == 'object' and 'properties' in t + +# Return True if the schema is nested +def is_nested_type(s): + return NESTED_TYPE_MARKER in s # return an iterator yielding fake-schemas that identify a nested type def iter_nested_types(schemas): @@ -121,13 +131,38 @@ def iter_nested_types(schemas): if 'properties' not in s: continue for pn, p in s.properties.iteritems(): - if is_nested_type(p): + if is_nested_type_property(p): ns = p.copy() ns.id = nested_type_name(s.id, pn) + ns[NESTED_TYPE_MARKER] = True yield ns # end for ach property # end for aech schma +# Return sorted type names of all markers applicable to the given schema +def schema_markers(s, c): + res = set() + + activities = c.sta_map.get(s.id, dict()) + if len(activities) == 0: + res.add('Part') + else: + # it should have at least one activity that matches it's type to qualify for the Resource trait + for fqan, iot in activities.iteritems(): + if activity_name_to_type_name(activity_split(fqan)[0]) == s.id: + res.add('Resource') + if IO_RESPONSE in iot: + res.add('ResponseResult') + if IO_REQUEST in iot: + res.add('RequestResult') + # end for each activity + # end handle activites + + if is_nested_type(s): + res.add('NestedType') + + return sorted(res) + ## -- End Rust TypeSystem -- @} @@ -148,7 +183,7 @@ def build_activity_mappings(activities): for mn, m in a.methods.iteritems(): assert m.id not in fqan fqan[m.id] = m - for in_out_type_name in ('request', 'response'): + for in_out_type_name in IO_TYPES: t = m.get(in_out_type_name, None) if t is None: continue @@ -163,12 +198,10 @@ def build_activity_mappings(activities): # getrating: response is a 'SomethingResult', which is still related to activities name # the latter is used to deduce the resource name an, _ = activity_split(m.id) - # videos -> Video - an = an.capitalize()[:-1] - info = res.setdefault(an, dict()) + tn = activity_name_to_type_name(an) + info = res.setdefault(tn, dict()) if m.id not in info: - io_info = info.setdefault(m.id, []) - io_info.append([]) + info.setdefault(m.id, []) # end handle other cases # end for each method # end for each activity @@ -180,6 +213,10 @@ def activity_split(fqan): assert len(t) == 3 return t[1:] +# videos -> Video +def activity_name_to_type_name(an): + return an.capitalize()[:-1] + ## -- End Activity Utilities -- @} diff --git a/src/rust/lib.rs b/src/rust/lib.rs index f353eded45d..01f850fb6cf 100644 --- a/src/rust/lib.rs +++ b/src/rust/lib.rs @@ -3,6 +3,26 @@ extern crate hyper; extern crate "rustc-serialize" as rustc_serialize; extern crate "yup-oauth2" as oauth2; +use std::marker::MarkerTrait; + +/// Identifies types which can be inserted and deleted. +/// Types with this trait are most commonly used by clients of this API. +pub trait Resource: MarkerTrait {} + +/// Identifies types which are used in API responses. +pub trait ResponseResult: MarkerTrait {} + +/// Identifies types which are used in API requests. +pub trait RequestResult: MarkerTrait {} + +/// Identifies types which are only used as part of other types, which +/// usually are carrying the `Resource` trait. +pub trait Part: MarkerTrait {} + +/// Identifies types which are only used by other types internally. +/// They have no special meaning, this trait just marks them for completeness. +pub trait NestedType: MarkerTrait {} + /// This module is for testing only, its code is used in mako templates #[cfg(test)] mod dev; \ No newline at end of file