Skip to content

Commit 10e32d7

Browse files
authored
added aws-guided codegen model (#240)
1 parent ad52d0e commit 10e32d7

35 files changed

+1353
-101
lines changed

.pylintrc

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ disable=
1212
bad-continuation, # clashes with black
1313
too-few-public-methods, # triggers when inheriting
1414
ungrouped-imports, # clashes with isort
15-
1615
[BASIC]
1716

1817
good-names=e,ex,f,fp,i,j,k,n,_

.travis.yml

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ jobs:
3030
before_install: skip
3131
install: skip
3232
script: mvn verify
33-
- stage: integ
33+
- stage: "integ default"
3434
language: python
3535
python: "3.6"
3636
install:
@@ -40,6 +40,19 @@ jobs:
4040
- DIR=$(mktemp -d)
4141
- cd "$DIR"
4242
- ls -la
43-
- printf "AWS::Foo::Bar\n\n" | cfn init -vv
43+
- printf "AWS::Foo::Bar\n\n1" | cfn init -vv
44+
- mvn verify
45+
- ls -la
46+
- stage: "integ guided"
47+
language: python
48+
python: "3.6"
49+
install:
50+
- mvn install
51+
- pip install .
52+
script:
53+
- DIR=$(mktemp -d)
54+
- cd "$DIR"
55+
- ls -la
56+
- printf "AWS::Foo::Bar\n\n2" | cfn init -vv
4457
- mvn verify
4558
- ls -la

python/rpdk/java/codegen.py

Lines changed: 156 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
# pylint doesn't recognize abstract methods
33
import logging
44
import shutil
5+
from collections import namedtuple
56

67
from rpdk.core.data_loaders import resource_stream
78
from rpdk.core.exceptions import InternalError, SysExitRecommendedError
@@ -10,12 +11,30 @@
1011
from rpdk.core.plugin_base import LanguagePlugin
1112

1213
from .resolver import translate_type
13-
from .utils import safe_reserved, validate_namespace
14+
from .utils import safe_reserved, validate_codegen_model, validate_namespace
1415

1516
LOG = logging.getLogger(__name__)
1617

1718
OPERATIONS = ("Create", "Read", "Update", "Delete", "List")
1819
EXECUTABLE = "cfn"
20+
AWSCODEGEN = namedtuple("AWSCODEGEN", "default guided default_code guided_code")
21+
CODEGEN = AWSCODEGEN("default", "guided_aws", "1", "2")
22+
23+
24+
def logdebug(func: object):
25+
def wrapper(*args, **kwargs):
26+
log_msg = func.__name__ if not func.__doc__ else func.__doc__
27+
entry_message = "{} started".format(log_msg)
28+
LOG.debug(entry_message)
29+
if "entity" in kwargs:
30+
writing_message = "Writing {}".format(kwargs["entity"])
31+
LOG.debug(writing_message)
32+
result = func(*args, **kwargs)
33+
exit_message = "{} complete".format(log_msg)
34+
LOG.debug(exit_message)
35+
return result
36+
37+
return wrapper
1938

2039

2140
class JavaArchiveNotFoundError(SysExitRecommendedError):
@@ -33,6 +52,7 @@ def __init__(self):
3352
self.env = self._setup_jinja_env(
3453
trim_blocks=True, lstrip_blocks=True, keep_trailing_newline=True
3554
)
55+
self.codegen_template_path = None
3656
self.env.filters["translate_type"] = translate_type
3757
self.env.filters["safe_reserved"] = safe_reserved
3858
self.namespace = None
@@ -66,19 +86,61 @@ def _prompt_for_namespace(self, project):
6686
project.settings["namespace"] = self.namespace
6787
self.package_name = ".".join(self.namespace)
6888

69-
def init(self, project):
70-
LOG.debug("Init started")
89+
@staticmethod
90+
def _prompt_for_codegen_model(project):
91+
prompt = "Choose codegen model - 1 (default) or 2 (guided-aws): "
7192

72-
self._prompt_for_namespace(project)
93+
codegen_model = input_with_validation(
94+
prompt, validate_codegen_model(CODEGEN.default_code)
95+
)
7396

74-
self._init_settings(project)
97+
project.settings["codegen_template_path"] = CODEGEN.default
7598

76-
# .gitignore
77-
path = project.root / ".gitignore"
78-
LOG.debug("Writing .gitignore: %s", path)
79-
contents = resource_stream(__name__, "data/java.gitignore").read()
99+
if codegen_model == CODEGEN.guided_code:
100+
project.settings["codegen_template_path"] = CODEGEN.guided
101+
102+
def _get_template(self, project, stage, name):
103+
return self.env.get_template(
104+
stage + "/" + project.settings["codegen_template_path"] + "/" + name
105+
)
106+
107+
@staticmethod
108+
def _is_aws_guided(project: object) -> bool:
109+
return project.settings["codegen_template_path"] == CODEGEN.guided
110+
111+
@logdebug
112+
def _writing_component(
113+
self, project: object, src: str, entity: str, **kwargs # noqa: C816
114+
) -> None:
115+
"""Writing module"""
116+
117+
stub_entity: str = kwargs.get("stub_entity")
118+
operation: str = kwargs.get("operation")
119+
pojo_name: str = kwargs.get("pojo_name")
120+
call_graph: str = kwargs.get("call_graph")
121+
122+
if not stub_entity:
123+
stub_entity = entity
124+
125+
template = self._get_template(project, "init", stub_entity)
126+
path = src / entity
127+
contents = template.render(
128+
package_name=self.package_name,
129+
operation=operation,
130+
pojo_name=pojo_name,
131+
call_graph=call_graph,
132+
)
80133
project.safewrite(path, contents)
81134

135+
@logdebug
136+
def init(self, project):
137+
"""Init"""
138+
self._prompt_for_namespace(project)
139+
140+
self._prompt_for_codegen_model(project)
141+
142+
self._init_settings(project)
143+
82144
# maven folder structure
83145
src = (project.root / "src" / "main" / "java").joinpath(*self.namespace)
84146
LOG.debug("Making source folder structure: %s", src)
@@ -87,9 +149,26 @@ def init(self, project):
87149
LOG.debug("Making test folder structure: %s", tst)
88150
tst.mkdir(parents=True, exist_ok=True)
89151

152+
# initialize shared files
153+
self.init_shared(project, src, tst)
154+
155+
# write specialized generated files
156+
if self._is_aws_guided(project):
157+
self.init_guided_aws(project, src, tst)
158+
159+
@logdebug
160+
def init_shared(self, project, src, tst):
161+
"""Writing project configuration"""
162+
# .gitignore
163+
path = project.root / ".gitignore"
164+
LOG.debug("Writing .gitignore: %s", path)
165+
contents = resource_stream(__name__, "data/java.gitignore").read()
166+
project.safewrite(path, contents)
167+
168+
# pom.xml
90169
path = project.root / "pom.xml"
91170
LOG.debug("Writing Maven POM: %s", path)
92-
template = self.env.get_template("pom.xml")
171+
template = self.env.get_template("init/shared/pom.xml")
93172
artifact_id = "{}-handler".format(project.hypenated_name)
94173
contents = template.render(
95174
group_id=self.package_name,
@@ -100,17 +179,35 @@ def init(self, project):
100179
)
101180
project.safewrite(path, contents)
102181

182+
# lombok.config
103183
path = project.root / "lombok.config"
104184
LOG.debug("Writing Lombok Config: %s", path)
105-
template = self.env.get_template("lombok.config")
185+
template = self.env.get_template("init/shared/lombok.config")
106186
contents = template.render()
107187
project.safewrite(path, contents)
108188

189+
LOG.debug("Writing callback context")
190+
template = self.env.get_template("init/shared/CallbackContext.java")
191+
path = src / "CallbackContext.java"
192+
contents = template.render(package_name=self.package_name)
193+
project.safewrite(path, contents)
194+
195+
path = src / "Configuration.java"
196+
LOG.debug("Writing configuration: %s", path)
197+
template = self.env.get_template("init/shared/StubConfiguration.java")
198+
contents = template.render(
199+
package_name=self.package_name,
200+
schema_file_name=project.schema_filename,
201+
pojo_name="ResourceModel",
202+
)
203+
project.safewrite(path, contents)
204+
109205
# CloudFormation/SAM template for handler lambda
110206
path = project.root / "template.yml"
111207
LOG.debug("Writing SAM template: %s", path)
112-
template = self.env.get_template("template.yml")
113-
208+
template = self.env.get_template(
209+
"template.yml"
210+
) # this template is in the CLI itself
114211
handler_params = {
115212
"Handler": project.entrypoint,
116213
"Runtime": project.runtime,
@@ -128,69 +225,59 @@ def init(self, project):
128225
)
129226
project.safewrite(path, contents)
130227

131-
LOG.debug("Writing handlers and tests")
132-
self.init_handlers(project, src, tst)
133-
134-
LOG.debug("Writing callback context")
135-
template = self.env.get_template("CallbackContext.java")
136-
path = src / "CallbackContext.java"
137-
contents = template.render(package_name=self.package_name)
138-
project.safewrite(path, contents)
139-
140-
path = src / "Configuration.java"
141-
LOG.debug("Writing configuration: %s", path)
142-
template = self.env.get_template("StubConfiguration.java")
143-
contents = template.render(
144-
package_name=self.package_name,
145-
schema_file_name=project.schema_filename,
146-
pojo_name="ResourceModel",
147-
)
148-
project.safewrite(path, contents)
149-
150-
# generated docs
228+
# generate docs
151229
path = project.root / "README.md"
152230
LOG.debug("Writing README: %s", path)
153-
template = self.env.get_template("README.md")
231+
template = self.env.get_template("init/shared/README.md")
154232
contents = template.render(
155233
type_name=project.type_name,
156234
schema_path=project.schema_path,
157235
executable=EXECUTABLE,
158236
)
159237
project.safewrite(path, contents)
160238

161-
LOG.debug("Init complete")
239+
self.init_handlers(project, src, tst)
240+
241+
@logdebug
242+
def init_guided_aws(self, project, src, tst):
243+
"""Writing supporting modules"""
244+
self._writing_component(project, src, entity="Translator.java")
245+
self._writing_component(project, src, entity="ClientBuilder.java")
246+
self._writing_component(project, src, entity="BaseHandlerStd.java")
247+
self._writing_component(project, tst, entity="AbstractTestBase.java")
162248

249+
@logdebug
163250
def init_handlers(self, project, src, tst):
164-
LOG.debug("Writing stub handlers")
251+
"""Writing stub handlers and tests"""
252+
pojo_name = "ResourceModel"
165253
for operation in OPERATIONS:
166-
if operation == "List":
167-
template = self.env.get_template("StubListHandler.java")
168-
else:
169-
template = self.env.get_template("StubHandler.java")
170-
path = src / "{}Handler.java".format(operation)
171-
LOG.debug("%s handler: %s", operation, path)
172-
contents = template.render(
173-
package_name=self.package_name,
174-
operation=operation,
175-
pojo_name="ResourceModel",
176-
)
177-
project.safewrite(path, contents)
254+
entity = "{}Handler.java".format(operation)
255+
entity_test = "{}HandlerTest.java".format(operation)
178256

179-
LOG.debug("Writing stub tests")
180-
for operation in OPERATIONS:
181-
if operation == "List":
182-
template = self.env.get_template("StubListHandlerTest.java")
183-
else:
184-
template = self.env.get_template("StubHandlerTest.java")
257+
stub_entity = "Stub{}Handler.java".format(
258+
operation if operation == "List" or self._is_aws_guided(project) else ""
259+
)
260+
stub_entity_test = "Stub{}HandlerTest.java".format(
261+
operation if operation == "List" else ""
262+
)
185263

186-
path = tst / "{}HandlerTest.java".format(operation)
187-
LOG.debug("%s handler: %s", operation, path)
188-
contents = template.render(
189-
package_name=self.package_name,
264+
self._writing_component(
265+
project,
266+
src,
267+
entity=entity,
268+
stub_entity=stub_entity,
190269
operation=operation,
191-
pojo_name="ResourceModel",
270+
pojo_name=pojo_name,
271+
call_graph=project.type_name.replace("::", "-"),
272+
)
273+
self._writing_component(
274+
project,
275+
tst,
276+
entity=entity_test,
277+
stub_entity=stub_entity_test,
278+
operation=operation,
279+
pojo_name=pojo_name,
192280
)
193-
project.safewrite(path, contents)
194281

195282
def _init_settings(self, project):
196283
project.runtime = self.RUNTIME
@@ -205,8 +292,9 @@ def _get_generated_root(project):
205292
def _get_generated_tests_root(project):
206293
return project.root / "target" / "generated-test-sources" / "rpdk"
207294

295+
@logdebug
208296
def generate(self, project):
209-
LOG.debug("Generate started")
297+
"""Generate"""
210298

211299
self._namespace_from_project(project)
212300

@@ -230,7 +318,7 @@ def generate(self, project):
230318
# write generated handler integration with LambdaWrapper
231319
path = src / "HandlerWrapper.java"
232320
LOG.debug("Writing handler wrapper: %s", path)
233-
template = self.env.get_template("HandlerWrapper.java")
321+
template = self.env.get_template("generate/HandlerWrapper.java")
234322
contents = template.render(
235323
package_name=self.package_name,
236324
operations=project.schema.get("handlers", {}).keys(),
@@ -240,7 +328,7 @@ def generate(self, project):
240328

241329
path = src / "BaseConfiguration.java"
242330
LOG.debug("Writing base configuration: %s", path)
243-
template = self.env.get_template("BaseConfiguration.java")
331+
template = self.env.get_template("generate/BaseConfiguration.java")
244332
contents = template.render(
245333
package_name=self.package_name,
246334
schema_file_name=project.schema_filename,
@@ -250,7 +338,7 @@ def generate(self, project):
250338

251339
path = src / "BaseHandler.java"
252340
LOG.debug("Writing base handler: %s", path)
253-
template = self.env.get_template("BaseHandler.java")
341+
template = self.env.get_template("generate/BaseHandler.java")
254342
contents = template.render(
255343
package_name=self.package_name,
256344
operations=OPERATIONS,
@@ -263,8 +351,8 @@ def generate(self, project):
263351

264352
LOG.debug("Writing %d POJOs", len(models))
265353

266-
base_template = self.env.get_template("ResourceModel.java")
267-
pojo_template = self.env.get_template("POJO.java")
354+
base_template = self.env.get_template("generate/ResourceModel.java")
355+
pojo_template = self.env.get_template("generate/POJO.java")
268356

269357
for model_name, properties in models.items():
270358
path = src / "{}.java".format(model_name)
@@ -289,8 +377,6 @@ def generate(self, project):
289377
)
290378
project.overwrite(path, contents)
291379

292-
LOG.debug("Generate complete")
293-
294380
@staticmethod
295381
def _find_jar(project):
296382
jar_glob = list(
@@ -313,8 +399,9 @@ def _find_jar(project):
313399

314400
return jar_glob[0]
315401

402+
@logdebug
316403
def package(self, project, zip_file):
317-
LOG.info("Packaging Java project")
404+
"""Packaging Java project"""
318405

319406
def write_with_relative_path(path):
320407
relative = path.relative_to(project.root)

0 commit comments

Comments
 (0)