mirror of
https://github.com/OMGeeky/google-apis-rs.git
synced 2026-01-11 05:51:49 +01:00
feat(pyratemp): successfully generating make deps
After minor modifications to pyratemp, it certainly does the job. What it **does NOT** do: * multiple outputs per template/command invocation * NICE embedding of code (like GSL can) It will do the job nonetheless, but mako might be worth a look
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -1,4 +1,5 @@
|
||||
target
|
||||
.api.deps
|
||||
Cargo.lock
|
||||
*.sublime-workspace
|
||||
*.xml
|
||||
|
||||
16
Makefile
16
Makefile
@@ -5,27 +5,29 @@ include Makefile.helpers
|
||||
PYTHON = python2.7
|
||||
TPL = etc/bin/pyratemp.py
|
||||
|
||||
API_DEPS_TPL = src/pyra/deps.pyra
|
||||
API_MAIN_TPL = src/pyra/main.pyra
|
||||
API_DEPS = .api.deps
|
||||
API_SHARED_INFO = ./etc/api/shared.yml
|
||||
API_SHARED_INFO = ./etc/api/shared.yaml
|
||||
API_JSON_FILES = $(shell find ./etc -type f -name '*-api.json')
|
||||
|
||||
help:
|
||||
$(info Programs)
|
||||
$(info ----> GSL: '$(GSL)')
|
||||
$(info ----> templat engine: '$(TPL)')
|
||||
$(info )
|
||||
$(info Targets)
|
||||
$(info help - print this help)
|
||||
$(info api-deps - generate a file to tell make what API file dependencies will be)
|
||||
$(info help-api - show all api targets to build individually)
|
||||
|
||||
json-to-xml: $(API_XML_FILES)
|
||||
$(API_DEPS): $(API_SHARED_INFO)
|
||||
$(TPL) -f $(API_SHARED_INFO) -d DEP_FILE=$@
|
||||
$(API_DEPS): $(API_SHARED_INFO) $(API_DEPS_TPL)
|
||||
$(TPL) -f $(API_SHARED_INFO) $(API_DEPS_TPL) > $@
|
||||
|
||||
api-deps: $(API_DEPS)
|
||||
|
||||
clean:
|
||||
include $(API_DEPS)
|
||||
|
||||
clean: clean-api
|
||||
-rm $(API_DEPS)
|
||||
-rm $(API_XML_FILES)
|
||||
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@ The license of everything not explicitly under a different license are licensed
|
||||
|
||||
What follows is a list of other material that is licensed differently.
|
||||
|
||||
* **./etc/bin/pyratemp.py** is licensed under MIT, as shown in [the header][pyratemp-header] of the file.
|
||||
* **./etc/bin/pyratemp.py** is licensed under MIT-like, as shown in [the header][pyratemp-header] of the file.
|
||||
* **./etc/api/\*\*/*.json** are licensed under a [MIT-like google license][google-lic].
|
||||
|
||||
|
||||
|
||||
20
etc/api/shared.yaml
Normal file
20
etc/api/shared.yaml
Normal file
@@ -0,0 +1,20 @@
|
||||
# Contains values shared among all API implementations
|
||||
directories:
|
||||
# directory under which all generated sources should reside
|
||||
output: ./generated
|
||||
# how to get from `output` back to common library
|
||||
common: ../
|
||||
# where are all the API meta files
|
||||
api_base: ./etc/api
|
||||
api:
|
||||
list:
|
||||
- name: youtube
|
||||
version: v3
|
||||
base_path: "etc/api"
|
||||
cargo:
|
||||
build_version: "0.0.1"
|
||||
authors:
|
||||
- Sebastian Thiel <byronimo@gmail>
|
||||
keywords: [google, protocol]
|
||||
# All APIs should live in the same repository
|
||||
repository_url: https://github.com/Byron/youtube-rs
|
||||
@@ -1,12 +0,0 @@
|
||||
# Contains values shared among all API implementations
|
||||
apis:
|
||||
base_path: "etc/api"
|
||||
- name: youtube
|
||||
version: v3
|
||||
cargo:
|
||||
build_version: "0.0.1"
|
||||
authors:
|
||||
- Sebastian Thiel <byronimo@gmail>
|
||||
keywords: [google, protocol]
|
||||
# All APIs should live in the same repository
|
||||
repository_url: https://github.com/Byron/youtube-rs
|
||||
@@ -1162,20 +1162,25 @@ class Renderer(object):
|
||||
output = []
|
||||
do_else = False # use else/elif-branch?
|
||||
|
||||
def to_str(v):
|
||||
if v is None:
|
||||
return unicode()
|
||||
return unicode(v)
|
||||
|
||||
if parsetree is None:
|
||||
return ""
|
||||
for elem in parsetree:
|
||||
if "str" == elem[0]:
|
||||
output.append(elem[1])
|
||||
elif "sub" == elem[0]:
|
||||
output.append(unicode(_eval(elem[1], data)))
|
||||
output.append(to_str(_eval(elem[1], data)))
|
||||
elif "esc" == elem[0]:
|
||||
obj = _eval(elem[2], data)
|
||||
#prevent double-escape
|
||||
if isinstance(obj, _dontescape) or isinstance(obj, TemplateBase):
|
||||
output.append(unicode(obj))
|
||||
output.append(to_str(obj))
|
||||
else:
|
||||
output.append(self.escapefunc(unicode(obj), elem[1]))
|
||||
output.append(self.escapefunc(to_str(obj), elem[1]))
|
||||
elif "for" == elem[0]:
|
||||
do_else = True
|
||||
(names, iterable) = elem[1:3]
|
||||
@@ -1279,6 +1284,201 @@ class Template(TemplateBase):
|
||||
#=========================================
|
||||
|
||||
|
||||
|
||||
class DictObject(object):
|
||||
|
||||
"""An object which wraps a dictionary to allow object.key access.
|
||||
If the source dictionary doesn't contain any sub-dictionaries, the input
|
||||
dict will be referenced. Otherwise it will be copied.
|
||||
|
||||
An attribute error is raised if a value is not accessible.
|
||||
|
||||
Please note that you cannot access dict keys which are not valid attribute names.
|
||||
"""
|
||||
|
||||
_default_dict = dict()
|
||||
_unpackable_types = (dict, tuple, list)
|
||||
|
||||
def __init__(self, indict=_default_dict):
|
||||
"""Initialize this instance from an input dictionary. If it contains other dictionaries, those will
|
||||
trigger their parent dictionaries to be copied, as they will be used as DictObject themselves and
|
||||
placed in the copy accordingly.
|
||||
NOTE: other DictObjects are used by reference. Generally, this type tries to perform the least
|
||||
amount of copying possible."""
|
||||
if indict is self._default_dict:
|
||||
return
|
||||
# end handle default instantiation, which makes us empty
|
||||
if isinstance(indict, DictObject):
|
||||
self.__dict__ = indict.__dict__
|
||||
return
|
||||
# END handle special case, be a reference
|
||||
dct = indict
|
||||
for key, val in dct.items():
|
||||
if isinstance(val, self._unpackable_types):
|
||||
dct = None
|
||||
break
|
||||
# END for each key-value pair
|
||||
|
||||
if dct is None:
|
||||
dct = dict(indict)
|
||||
|
||||
def unpack(val):
|
||||
"""unpack helper"""
|
||||
if isinstance(val, dict):
|
||||
val = DictObject(val)
|
||||
elif isinstance(val, (tuple, list)):
|
||||
val = type(val)(unpack(item) for item in val)
|
||||
return val
|
||||
# END unpack
|
||||
for key, val in dct.items():
|
||||
dct[key] = unpack(val)
|
||||
# END for each k,v pair
|
||||
# END handle recursive copy
|
||||
self.__dict__ = dct
|
||||
|
||||
def __str__(self):
|
||||
return str(self.__dict__)
|
||||
|
||||
def __repr__(self):
|
||||
return repr(self.__dict__)
|
||||
|
||||
def __getattr__(self, name):
|
||||
return object.__getattribute__(self, name)
|
||||
|
||||
def __getitem__(self, name):
|
||||
try:
|
||||
return getattr(self, name)
|
||||
except AttributeError:
|
||||
raise KeyError(name)
|
||||
# end convert exception
|
||||
|
||||
def __setitem__(self, name, value):
|
||||
setattr(self, name, value)
|
||||
|
||||
def __contains__(self, name):
|
||||
return name in self.__dict__
|
||||
|
||||
def __len__(self):
|
||||
return len(self.__dict__)
|
||||
|
||||
def __iter__(self):
|
||||
return iter(self.__dict__)
|
||||
|
||||
def __eq__(self, other):
|
||||
"""Compares a possibly expensive comparison"""
|
||||
if isinstance(other, DictObject):
|
||||
# EXPENSIVE !
|
||||
return self.to_dict() == other.to_dict()
|
||||
elif isinstance(other, dict):
|
||||
return self.to_dict() == other
|
||||
# end handle type of other
|
||||
return self is other
|
||||
|
||||
def update(self, other, **kwargs):
|
||||
"""Similar to dict.update"""
|
||||
items = other
|
||||
if hasattr(other, 'keys'):
|
||||
items = other.items()
|
||||
for item_list in (items, kwargs.items()):
|
||||
for k, v in item_list:
|
||||
setattr(self, k, v)
|
||||
# end for each item list
|
||||
|
||||
def to_dict(self, recursive=False):
|
||||
"""@return ourselves as normal dict
|
||||
@param recursive if True, a recursive copy will be returned if required."""
|
||||
if recursive:
|
||||
def obtain_needs_copy(value):
|
||||
"""figure out if a copy is required"""
|
||||
if isinstance(value, DictObject):
|
||||
return True
|
||||
if isinstance(value, (tuple, list, set)):
|
||||
for item in value:
|
||||
if obtain_needs_copy(item):
|
||||
return True
|
||||
# end check needs copy
|
||||
# end for each item in value
|
||||
# end if instance is iterable
|
||||
return False
|
||||
# end check needs copy
|
||||
|
||||
def unpack(val):
|
||||
"""unpack val recursively and copy it gently"""
|
||||
if isinstance(val, DictObject):
|
||||
val = val.to_dict(recursive)
|
||||
elif isinstance(val, (tuple, list, set)):
|
||||
val = type(val)(unpack(item) for item in val)
|
||||
# end handle type resolution
|
||||
return val
|
||||
# end unpack
|
||||
|
||||
needs_copy = False
|
||||
for value in self.__dict__.values():
|
||||
if obtain_needs_copy(value):
|
||||
needs_copy = True
|
||||
break
|
||||
# end check value
|
||||
# END for each value
|
||||
|
||||
if needs_copy:
|
||||
new_dict = dict()
|
||||
for key, val in self.__dict__.items():
|
||||
new_dict[key] = unpack(val)
|
||||
# END for each key, value pair
|
||||
return new_dict
|
||||
# else:
|
||||
# just fall through and return ourselves as dictionary
|
||||
|
||||
# END handle recursion
|
||||
return self.__dict__
|
||||
|
||||
def copy(self):
|
||||
"""@return a (deep) copy of self"""
|
||||
return type(self)(self.to_dict())
|
||||
|
||||
def clone(self):
|
||||
"""@return a deep copy of this dict. This onyl means that the key-sets are independent. However, the
|
||||
values are still shared, which matters in case of lists for instance"""
|
||||
return type(self)(deepcopy(self.to_dict(recursive=True)))
|
||||
|
||||
def inversed_dict(self):
|
||||
"""@return new dictionary which uses this dicts keys as values, and values as keys
|
||||
@note duplicate values will result in just a single key, effectively drupping items.
|
||||
Use this only if you have unique key-value pairs"""
|
||||
return dict(list(zip(list(self.__dict__.values()), list(self.__dict__.keys()))))
|
||||
|
||||
def get(self, name, default=None):
|
||||
"""as dict.get"""
|
||||
return self.__dict__.get(name, default)
|
||||
|
||||
def keys(self):
|
||||
"""as dict.keys"""
|
||||
return list(self.__dict__.keys())
|
||||
|
||||
def values(self):
|
||||
"""as dict.values"""
|
||||
return list(self.__dict__.values())
|
||||
|
||||
def items(self):
|
||||
"""as dict.items"""
|
||||
return list(self.__dict__.items())
|
||||
|
||||
def iteritems(self):
|
||||
"""as dict.iteritems"""
|
||||
return iter(self.__dict__.items())
|
||||
|
||||
def pop(self, key, default=re):
|
||||
"""as dict.pop"""
|
||||
if default is re:
|
||||
return self.__dict__.pop(key)
|
||||
else:
|
||||
return self.__dict__.pop(key, default)
|
||||
# end assure semantics are kept
|
||||
|
||||
|
||||
# end class DictObject
|
||||
|
||||
|
||||
__version__ = "0.3.2"
|
||||
__author__ = "Roland Koebler <rk at simple-is-better dot org>"
|
||||
__license__ = """Copyright (c) 2007-2013 by Roland Koebler
|
||||
@@ -1344,6 +1544,7 @@ def load_data(datafiles):
|
||||
mydata = {}
|
||||
|
||||
for filename, n, namespace in datafiles:
|
||||
data = None
|
||||
if filename[-5:].lower() == ".json":
|
||||
if not imported_json:
|
||||
try:
|
||||
@@ -1352,14 +1553,9 @@ def load_data(datafiles):
|
||||
import json
|
||||
imported_json = True
|
||||
try:
|
||||
myjson = json.load(open(filename, 'r'))
|
||||
data = json.load(open(filename, 'r'))
|
||||
if n != -1:
|
||||
myjson = myjson[n]
|
||||
|
||||
if namespace is None:
|
||||
mydata.update(myjson)
|
||||
else:
|
||||
mydata.update({namespace: myjson})
|
||||
data = data[n]
|
||||
except ValueError as err:
|
||||
raise ValueError("Invalid JSON in file '%s'. (%s)" % (filename, str(err)))
|
||||
elif filename[-5:].lower() == ".yaml":
|
||||
@@ -1368,13 +1564,16 @@ def load_data(datafiles):
|
||||
imported_yaml = True
|
||||
if n == -1:
|
||||
n = 0
|
||||
myyaml = yaml.load_all(open(filename, 'r'))
|
||||
if namespace is not None:
|
||||
mydata.update({namespace: list(myyaml)[n]})
|
||||
else:
|
||||
mydata.update(list(myyaml)[n])
|
||||
data = yaml.load_all(open(filename, 'r'))
|
||||
data = list(data)[n]
|
||||
else:
|
||||
raise ValueError("Invalid data-file '%s', must be .json or .yaml" % filename)
|
||||
assert data is not None
|
||||
data = DictObject(data)
|
||||
if namespace is None:
|
||||
mydata.update(data)
|
||||
else:
|
||||
mydata.update({namespace: data})
|
||||
return mydata
|
||||
|
||||
#-----------------------------------------
|
||||
@@ -1466,4 +1665,3 @@ if __name__ == "__main__":
|
||||
sys.exit(30)
|
||||
|
||||
#-----------------------------------------
|
||||
|
||||
|
||||
24
src/pyra/deps.pyra
Normal file
24
src/pyra/deps.pyra
Normal file
@@ -0,0 +1,24 @@
|
||||
$!setvar("api_info", "[]")!$#!
|
||||
|
||||
<!--(for a in api.list)-->
|
||||
$!setvar("gen_root", "directories.output + '/' + a.name + '_' + a.version")!$#!
|
||||
$!setvar("api_name", "a.name+a.version")!$#!
|
||||
$!setvar("api_clean", "api_name+'-clean'")!$#!
|
||||
$!gen_root!$: $!directories.api_base!$/$!a.name!$/$!a.version!$/$!a.name!$-api.json
|
||||
$!api_name!$: $!gen_root!$
|
||||
$!api_clean!$:
|
||||
rm -Rf $!gen_root!$
|
||||
$!api_info.append((api_name, api_clean, gen_root))!$#!
|
||||
|
||||
<!--(end)-->
|
||||
|
||||
.PHONY += $(.PHONY) $!' '.join(a[0] for a in api_info)!$ $!' '.join(a[1] for a in api_info)!$
|
||||
|
||||
help-api:
|
||||
<!--(for a in api_info)-->
|
||||
$(info $!a[0]!$ - build the $!a[0]!$ api)
|
||||
$(info $!a[1]!$ - clean all generated files of the $!a[0]!$ api)
|
||||
<!--(end)-->
|
||||
|
||||
|
||||
clean-api: $!' '.join(a[1] for a in api_info)!$
|
||||
Reference in New Issue
Block a user