snowflake-cli-labs 3.0.0rc0__py3-none-any.whl → 3.0.0rc2__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- snowflake/cli/__about__.py +1 -1
- snowflake/cli/_app/cli_app.py +10 -1
- snowflake/cli/_app/snow_connector.py +91 -37
- snowflake/cli/_app/telemetry.py +8 -4
- snowflake/cli/_app/version_check.py +74 -0
- snowflake/cli/_plugins/connection/commands.py +3 -2
- snowflake/cli/_plugins/git/commands.py +55 -14
- snowflake/cli/_plugins/git/manager.py +14 -6
- snowflake/cli/_plugins/nativeapp/codegen/compiler.py +18 -2
- snowflake/cli/_plugins/nativeapp/codegen/setup/native_app_setup_processor.py +123 -42
- snowflake/cli/_plugins/nativeapp/codegen/setup/setup_driver.py.source +5 -2
- snowflake/cli/_plugins/nativeapp/codegen/snowpark/python_processor.py +6 -11
- snowflake/cli/_plugins/nativeapp/codegen/templates/templates_processor.py +111 -0
- snowflake/cli/_plugins/nativeapp/exceptions.py +3 -3
- snowflake/cli/_plugins/nativeapp/manager.py +74 -144
- snowflake/cli/_plugins/nativeapp/project_model.py +2 -9
- snowflake/cli/_plugins/nativeapp/run_processor.py +56 -260
- snowflake/cli/_plugins/nativeapp/same_account_install_method.py +74 -0
- snowflake/cli/_plugins/nativeapp/teardown_processor.py +17 -246
- snowflake/cli/_plugins/nativeapp/v2_conversions/v2_to_v1_decorator.py +91 -17
- snowflake/cli/_plugins/snowpark/commands.py +5 -65
- snowflake/cli/_plugins/snowpark/common.py +17 -1
- snowflake/cli/_plugins/snowpark/models.py +2 -1
- snowflake/cli/_plugins/snowpark/package/anaconda_packages.py +1 -35
- snowflake/cli/_plugins/sql/commands.py +1 -2
- snowflake/cli/_plugins/stage/commands.py +2 -2
- snowflake/cli/_plugins/stage/manager.py +46 -15
- snowflake/cli/_plugins/streamlit/commands.py +4 -63
- snowflake/cli/_plugins/streamlit/manager.py +13 -0
- snowflake/cli/_plugins/workspace/action_context.py +7 -0
- snowflake/cli/_plugins/workspace/commands.py +145 -32
- snowflake/cli/_plugins/workspace/manager.py +21 -4
- snowflake/cli/api/cli_global_context.py +136 -313
- snowflake/cli/api/commands/decorators.py +1 -1
- snowflake/cli/api/commands/flags.py +106 -102
- snowflake/cli/api/commands/snow_typer.py +15 -6
- snowflake/cli/api/config.py +18 -5
- snowflake/cli/api/connections.py +214 -0
- snowflake/cli/api/console/abc.py +4 -2
- snowflake/cli/api/constants.py +11 -0
- snowflake/cli/api/entities/application_entity.py +687 -2
- snowflake/cli/api/entities/application_package_entity.py +407 -9
- snowflake/cli/api/entities/common.py +7 -2
- snowflake/cli/api/entities/utils.py +80 -20
- snowflake/cli/api/exceptions.py +12 -2
- snowflake/cli/api/feature_flags.py +0 -2
- snowflake/cli/api/identifiers.py +3 -0
- snowflake/cli/api/project/definition.py +35 -1
- snowflake/cli/api/project/definition_conversion.py +352 -0
- snowflake/cli/api/project/schemas/entities/application_package_entity_model.py +17 -0
- snowflake/cli/api/project/schemas/entities/common.py +0 -12
- snowflake/cli/api/project/schemas/identifier_model.py +2 -2
- snowflake/cli/api/project/schemas/project_definition.py +102 -43
- snowflake/cli/api/rendering/jinja.py +2 -16
- snowflake/cli/api/rendering/project_definition_templates.py +5 -1
- snowflake/cli/api/rendering/sql_templates.py +14 -4
- snowflake/cli/api/secure_path.py +13 -18
- snowflake/cli/api/secure_utils.py +90 -1
- snowflake/cli/api/sql_execution.py +13 -0
- snowflake/cli/api/utils/definition_rendering.py +7 -7
- {snowflake_cli_labs-3.0.0rc0.dist-info → snowflake_cli_labs-3.0.0rc2.dist-info}/METADATA +9 -9
- {snowflake_cli_labs-3.0.0rc0.dist-info → snowflake_cli_labs-3.0.0rc2.dist-info}/RECORD +65 -61
- snowflake/cli/api/commands/typer_pre_execute.py +0 -26
- {snowflake_cli_labs-3.0.0rc0.dist-info → snowflake_cli_labs-3.0.0rc2.dist-info}/WHEEL +0 -0
- {snowflake_cli_labs-3.0.0rc0.dist-info → snowflake_cli_labs-3.0.0rc2.dist-info}/entry_points.txt +0 -0
- {snowflake_cli_labs-3.0.0rc0.dist-info → snowflake_cli_labs-3.0.0rc2.dist-info}/licenses/LICENSE +0 -0
|
@@ -15,12 +15,18 @@
|
|
|
15
15
|
from __future__ import annotations
|
|
16
16
|
|
|
17
17
|
import json
|
|
18
|
+
import logging
|
|
18
19
|
import os.path
|
|
19
20
|
from pathlib import Path
|
|
20
21
|
from typing import List, Optional
|
|
21
22
|
|
|
23
|
+
import yaml
|
|
22
24
|
from click import ClickException
|
|
23
|
-
from snowflake.cli._plugins.nativeapp.artifacts import
|
|
25
|
+
from snowflake.cli._plugins.nativeapp.artifacts import (
|
|
26
|
+
BundleMap,
|
|
27
|
+
find_manifest_file,
|
|
28
|
+
find_setup_script_file,
|
|
29
|
+
)
|
|
24
30
|
from snowflake.cli._plugins.nativeapp.codegen.artifact_processor import (
|
|
25
31
|
ArtifactProcessor,
|
|
26
32
|
is_python_file_artifact,
|
|
@@ -40,6 +46,32 @@ from snowflake.cli.api.project.schemas.native_app.path_mapping import (
|
|
|
40
46
|
DEFAULT_TIMEOUT = 30
|
|
41
47
|
DRIVER_PATH = Path(__file__).parent / "setup_driver.py.source"
|
|
42
48
|
|
|
49
|
+
log = logging.getLogger(__name__)
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def safe_set(d: dict, *keys: str, **kwargs) -> None:
|
|
53
|
+
"""
|
|
54
|
+
Sets a value in a nested dictionary structure, creating intermediate dictionaries as needed.
|
|
55
|
+
Sample usage:
|
|
56
|
+
|
|
57
|
+
d = {}
|
|
58
|
+
safe_set(d, "a", "b", "c", value=42)
|
|
59
|
+
|
|
60
|
+
d is now:
|
|
61
|
+
{
|
|
62
|
+
"a": {
|
|
63
|
+
"b": {
|
|
64
|
+
"c": 42
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
"""
|
|
69
|
+
curr = d
|
|
70
|
+
for k in keys[:-1]:
|
|
71
|
+
curr = curr.setdefault(k, {})
|
|
72
|
+
|
|
73
|
+
curr[keys[-1]] = kwargs.get("value")
|
|
74
|
+
|
|
43
75
|
|
|
44
76
|
class NativeAppSetupProcessor(ArtifactProcessor):
|
|
45
77
|
def __init__(self, *args, **kwargs):
|
|
@@ -62,7 +94,7 @@ class NativeAppSetupProcessor(ArtifactProcessor):
|
|
|
62
94
|
|
|
63
95
|
self._create_or_update_sandbox()
|
|
64
96
|
|
|
65
|
-
cc.
|
|
97
|
+
cc.step("Processing Python setup files")
|
|
66
98
|
|
|
67
99
|
files_to_process = []
|
|
68
100
|
for src_file, dest_file in bundle_map.all_mappings(
|
|
@@ -73,18 +105,55 @@ class NativeAppSetupProcessor(ArtifactProcessor):
|
|
|
73
105
|
)
|
|
74
106
|
files_to_process.append(src_file)
|
|
75
107
|
|
|
76
|
-
|
|
77
|
-
|
|
108
|
+
result = self._execute_in_sandbox(files_to_process)
|
|
109
|
+
if not result:
|
|
110
|
+
return # nothing to do
|
|
111
|
+
|
|
112
|
+
logs = result.get("logs", [])
|
|
113
|
+
for msg in logs:
|
|
114
|
+
log.debug(msg)
|
|
115
|
+
|
|
116
|
+
warnings = result.get("warnings", [])
|
|
117
|
+
for msg in warnings:
|
|
118
|
+
cc.warning(msg)
|
|
119
|
+
|
|
120
|
+
schema_version = result.get("schema_version")
|
|
121
|
+
if schema_version != "1":
|
|
122
|
+
raise ClickException(
|
|
123
|
+
f"Unsupported schema version returned from snowflake-app-python library: {schema_version}"
|
|
124
|
+
)
|
|
125
|
+
|
|
126
|
+
setup_script_mods = [
|
|
127
|
+
mod
|
|
128
|
+
for mod in result.get("modifications", [])
|
|
129
|
+
if mod.get("target") == "native_app:setup_script"
|
|
130
|
+
]
|
|
131
|
+
if setup_script_mods:
|
|
132
|
+
self._edit_setup_sql(setup_script_mods)
|
|
133
|
+
|
|
134
|
+
manifest_mods = [
|
|
135
|
+
mod
|
|
136
|
+
for mod in result.get("modifications", [])
|
|
137
|
+
if mod.get("target") == "native_app:manifest"
|
|
138
|
+
]
|
|
139
|
+
if manifest_mods:
|
|
140
|
+
self._edit_manifest(manifest_mods)
|
|
78
141
|
|
|
79
142
|
def _execute_in_sandbox(self, py_files: List[Path]) -> dict:
|
|
80
143
|
file_count = len(py_files)
|
|
81
144
|
cc.step(f"Processing {file_count} setup file{'s' if file_count > 1 else ''}")
|
|
82
145
|
|
|
146
|
+
manifest_path = find_manifest_file(deploy_root=self._bundle_ctx.deploy_root)
|
|
147
|
+
|
|
148
|
+
generated_root = self._bundle_ctx.generated_root
|
|
149
|
+
generated_root.mkdir(exist_ok=True, parents=True)
|
|
150
|
+
|
|
83
151
|
env_vars = {
|
|
84
152
|
"_SNOWFLAKE_CLI_PROJECT_PATH": str(self._bundle_ctx.project_root),
|
|
85
153
|
"_SNOWFLAKE_CLI_SETUP_FILES": os.pathsep.join(map(str, py_files)),
|
|
86
154
|
"_SNOWFLAKE_CLI_APP_NAME": str(self._bundle_ctx.package_name),
|
|
87
|
-
"_SNOWFLAKE_CLI_SQL_DEST_DIR": str(
|
|
155
|
+
"_SNOWFLAKE_CLI_SQL_DEST_DIR": str(generated_root),
|
|
156
|
+
"_SNOWFLAKE_CLI_MANIFEST_PATH": str(manifest_path),
|
|
88
157
|
}
|
|
89
158
|
|
|
90
159
|
try:
|
|
@@ -102,56 +171,68 @@ class NativeAppSetupProcessor(ArtifactProcessor):
|
|
|
102
171
|
)
|
|
103
172
|
|
|
104
173
|
if result.returncode == 0:
|
|
105
|
-
|
|
106
|
-
return sql_file_mappings
|
|
174
|
+
return json.loads(result.stdout)
|
|
107
175
|
else:
|
|
108
176
|
raise ClickException(
|
|
109
177
|
f"Failed to execute python setup script logic: {result.stderr}"
|
|
110
178
|
)
|
|
111
179
|
|
|
112
|
-
def
|
|
113
|
-
if not sql_file_mappings:
|
|
114
|
-
# Nothing to generate
|
|
115
|
-
return
|
|
116
|
-
|
|
117
|
-
generated_root = self.generated_root
|
|
118
|
-
generated_root.mkdir(exist_ok=True, parents=True)
|
|
119
|
-
|
|
180
|
+
def _edit_setup_sql(self, modifications: List[dict]) -> None:
|
|
120
181
|
cc.step("Patching setup script")
|
|
121
182
|
setup_file_path = find_setup_script_file(
|
|
122
183
|
deploy_root=self._bundle_ctx.deploy_root
|
|
123
184
|
)
|
|
124
|
-
with self.edit_file(setup_file_path) as f:
|
|
125
|
-
new_contents = [f.contents]
|
|
126
185
|
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
)
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
if
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
186
|
+
with self.edit_file(setup_file_path) as f:
|
|
187
|
+
prepended = []
|
|
188
|
+
appended = []
|
|
189
|
+
|
|
190
|
+
for mod in modifications:
|
|
191
|
+
for inst in mod.get("instructions", []):
|
|
192
|
+
if inst.get("type") == "insert":
|
|
193
|
+
default_loc = inst.get("default_location")
|
|
194
|
+
if default_loc == "end":
|
|
195
|
+
appended.append(self._setup_mod_instruction_to_sql(inst))
|
|
196
|
+
elif default_loc == "start":
|
|
197
|
+
prepended.append(self._setup_mod_instruction_to_sql(inst))
|
|
198
|
+
|
|
199
|
+
if prepended or appended:
|
|
200
|
+
f.edited_contents = "\n".join(prepended + [f.contents] + appended)
|
|
201
|
+
|
|
202
|
+
def _edit_manifest(self, modifications: List[dict]) -> None:
|
|
203
|
+
cc.step("Patching manifest")
|
|
204
|
+
manifest_path = find_manifest_file(deploy_root=self._bundle_ctx.deploy_root)
|
|
205
|
+
|
|
206
|
+
with self.edit_file(manifest_path) as f:
|
|
207
|
+
manifest = yaml.safe_load(f.contents)
|
|
208
|
+
|
|
209
|
+
for mod in modifications:
|
|
210
|
+
for inst in mod.get("instructions", []):
|
|
211
|
+
if inst.get("type") == "set":
|
|
212
|
+
payload = inst.get("payload")
|
|
213
|
+
if payload:
|
|
214
|
+
key = payload.get("key")
|
|
215
|
+
value = payload.get("value")
|
|
216
|
+
safe_set(manifest, *key.split("."), value=value)
|
|
217
|
+
f.edited_contents = yaml.safe_dump(manifest, sort_keys=False)
|
|
218
|
+
|
|
219
|
+
def _setup_mod_instruction_to_sql(self, mod_inst: dict) -> str:
|
|
220
|
+
payload = mod_inst.get("payload")
|
|
221
|
+
if not payload:
|
|
222
|
+
raise ClickException("Unsupported instruction received: no payload found")
|
|
223
|
+
|
|
224
|
+
payload_type = payload.get("type")
|
|
225
|
+
if payload_type == "execute immediate":
|
|
226
|
+
file_path = payload.get("file_path")
|
|
227
|
+
if file_path:
|
|
228
|
+
sql_file_path = self._bundle_ctx.generated_root / file_path
|
|
229
|
+
return f"EXECUTE IMMEDIATE FROM '/{to_stage_path(sql_file_path.relative_to(self._bundle_ctx.deploy_root))}';"
|
|
230
|
+
|
|
231
|
+
raise ClickException(f"Unsupported instruction type received: {payload_type}")
|
|
147
232
|
|
|
148
233
|
@property
|
|
149
234
|
def sandbox_root(self):
|
|
150
|
-
return self._bundle_ctx.bundle_root / "
|
|
151
|
-
|
|
152
|
-
@property
|
|
153
|
-
def generated_root(self):
|
|
154
|
-
return self._bundle_ctx.generated_root / "setup_py"
|
|
235
|
+
return self._bundle_ctx.bundle_root / "venv"
|
|
155
236
|
|
|
156
237
|
def _create_or_update_sandbox(self):
|
|
157
238
|
sandbox_root = self.sandbox_root
|
|
@@ -20,8 +20,11 @@ from pathlib import Path
|
|
|
20
20
|
import snowflake.app.context as ctx
|
|
21
21
|
from snowflake.app.sql import SQLGenerator
|
|
22
22
|
|
|
23
|
-
ctx.
|
|
24
|
-
ctx.
|
|
23
|
+
ctx.configure("project_path", os.environ.get("_SNOWFLAKE_CLI_PROJECT_PATH", None))
|
|
24
|
+
ctx.configure("manifest_path", os.environ.get("_SNOWFLAKE_CLI_MANIFEST_PATH", None))
|
|
25
|
+
ctx.configure("current_app_name", os.environ.get("_SNOWFLAKE_CLI_APP_NAME", None))
|
|
26
|
+
ctx.configure("enable_sql_generation", True)
|
|
27
|
+
|
|
25
28
|
__snowflake_internal_py_files = os.environ["_SNOWFLAKE_CLI_SETUP_FILES"].split(
|
|
26
29
|
os.pathsep
|
|
27
30
|
)
|
|
@@ -226,13 +226,9 @@ class SnowparkAnnotationProcessor(ArtifactProcessor):
|
|
|
226
226
|
edit_setup_script_with_exec_imm_sql(
|
|
227
227
|
collected_sql_files=collected_sql_files,
|
|
228
228
|
deploy_root=bundle_map.deploy_root(),
|
|
229
|
-
generated_root=self.
|
|
229
|
+
generated_root=self._bundle_ctx.generated_root,
|
|
230
230
|
)
|
|
231
231
|
|
|
232
|
-
@property
|
|
233
|
-
def _generated_root(self):
|
|
234
|
-
return self._bundle_ctx.generated_root / "snowpark"
|
|
235
|
-
|
|
236
232
|
def _normalize_imports(
|
|
237
233
|
self,
|
|
238
234
|
extension_fn: NativeAppExtensionFunction,
|
|
@@ -327,11 +323,8 @@ class SnowparkAnnotationProcessor(ArtifactProcessor):
|
|
|
327
323
|
predicate=is_python_file_artifact,
|
|
328
324
|
)
|
|
329
325
|
):
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
dest_file.relative_to(bundle_map.deploy_root())
|
|
333
|
-
)
|
|
334
|
-
)
|
|
326
|
+
src_file_name = src_file.relative_to(self._bundle_ctx.project_root)
|
|
327
|
+
cc.step(f"Processing Snowpark annotations from {src_file_name}")
|
|
335
328
|
collected_extension_function_json = _execute_in_sandbox(
|
|
336
329
|
py_file=str(dest_file.resolve()),
|
|
337
330
|
deploy_root=self._bundle_ctx.deploy_root,
|
|
@@ -366,7 +359,9 @@ class SnowparkAnnotationProcessor(ArtifactProcessor):
|
|
|
366
359
|
Generates a SQL filename for the generated root from the python file, and creates its parent directories.
|
|
367
360
|
"""
|
|
368
361
|
relative_py_file = py_file.relative_to(self._bundle_ctx.deploy_root)
|
|
369
|
-
sql_file = Path(
|
|
362
|
+
sql_file = Path(
|
|
363
|
+
self._bundle_ctx.generated_root, relative_py_file.with_suffix(".sql")
|
|
364
|
+
)
|
|
370
365
|
if sql_file.exists():
|
|
371
366
|
cc.warning(
|
|
372
367
|
f"""\
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
# Copyright (c) 2024 Snowflake Inc.
|
|
2
|
+
#
|
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
# you may not use this file except in compliance with the License.
|
|
5
|
+
# You may obtain a copy of the License at
|
|
6
|
+
#
|
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
#
|
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
# See the License for the specific language governing permissions and
|
|
13
|
+
# limitations under the License.
|
|
14
|
+
|
|
15
|
+
from __future__ import annotations
|
|
16
|
+
|
|
17
|
+
from pathlib import Path
|
|
18
|
+
from typing import Optional
|
|
19
|
+
|
|
20
|
+
import jinja2
|
|
21
|
+
from snowflake.cli._plugins.nativeapp.artifacts import BundleMap
|
|
22
|
+
from snowflake.cli._plugins.nativeapp.codegen.artifact_processor import (
|
|
23
|
+
ArtifactProcessor,
|
|
24
|
+
)
|
|
25
|
+
from snowflake.cli._plugins.nativeapp.exceptions import InvalidTemplateInFileError
|
|
26
|
+
from snowflake.cli.api.cli_global_context import get_cli_context
|
|
27
|
+
from snowflake.cli.api.console import cli_console as cc
|
|
28
|
+
from snowflake.cli.api.project.schemas.native_app.path_mapping import (
|
|
29
|
+
PathMapping,
|
|
30
|
+
ProcessorMapping,
|
|
31
|
+
)
|
|
32
|
+
from snowflake.cli.api.rendering.project_definition_templates import (
|
|
33
|
+
get_client_side_jinja_env,
|
|
34
|
+
has_client_side_templates,
|
|
35
|
+
)
|
|
36
|
+
from snowflake.cli.api.rendering.sql_templates import (
|
|
37
|
+
choose_sql_jinja_env_based_on_template_syntax,
|
|
38
|
+
has_sql_templates,
|
|
39
|
+
)
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def _is_sql_file(file: Path) -> bool:
|
|
43
|
+
return file.name.lower().endswith(".sql")
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
class TemplatesProcessor(ArtifactProcessor):
|
|
47
|
+
"""
|
|
48
|
+
Processor class to perform template expansion on all relevant artifacts (specified in the project definition file).
|
|
49
|
+
"""
|
|
50
|
+
|
|
51
|
+
def expand_templates_in_file(self, src: Path, dest: Path) -> None:
|
|
52
|
+
"""
|
|
53
|
+
Expand templates in the file.
|
|
54
|
+
"""
|
|
55
|
+
if src.is_dir():
|
|
56
|
+
return
|
|
57
|
+
|
|
58
|
+
with self.edit_file(dest) as file:
|
|
59
|
+
if not has_client_side_templates(file.contents) and not (
|
|
60
|
+
_is_sql_file(dest) and has_sql_templates(file.contents)
|
|
61
|
+
):
|
|
62
|
+
return
|
|
63
|
+
|
|
64
|
+
src_file_name = src.relative_to(self._bundle_ctx.project_root)
|
|
65
|
+
cc.step(f"Expanding templates in {src_file_name}")
|
|
66
|
+
with cc.indented():
|
|
67
|
+
try:
|
|
68
|
+
jinja_env = (
|
|
69
|
+
choose_sql_jinja_env_based_on_template_syntax(
|
|
70
|
+
file.contents, reference_name=src_file_name
|
|
71
|
+
)
|
|
72
|
+
if _is_sql_file(dest)
|
|
73
|
+
else get_client_side_jinja_env()
|
|
74
|
+
)
|
|
75
|
+
expanded_template = jinja_env.from_string(file.contents).render(
|
|
76
|
+
get_cli_context().template_context
|
|
77
|
+
)
|
|
78
|
+
|
|
79
|
+
# For now, we are printing the source file path in the error message
|
|
80
|
+
# instead of the destination file path to make it easier for the user
|
|
81
|
+
# to identify the file that has the error, and edit the correct file.
|
|
82
|
+
except jinja2.TemplateSyntaxError as e:
|
|
83
|
+
raise InvalidTemplateInFileError(src_file_name, e, e.lineno) from e
|
|
84
|
+
|
|
85
|
+
except jinja2.UndefinedError as e:
|
|
86
|
+
raise InvalidTemplateInFileError(src_file_name, e) from e
|
|
87
|
+
|
|
88
|
+
if expanded_template != file.contents:
|
|
89
|
+
file.edited_contents = expanded_template
|
|
90
|
+
|
|
91
|
+
def process(
|
|
92
|
+
self,
|
|
93
|
+
artifact_to_process: PathMapping,
|
|
94
|
+
processor_mapping: Optional[ProcessorMapping],
|
|
95
|
+
**kwargs,
|
|
96
|
+
) -> None:
|
|
97
|
+
"""
|
|
98
|
+
Process the artifact by executing the template expansion logic on it.
|
|
99
|
+
"""
|
|
100
|
+
|
|
101
|
+
bundle_map = BundleMap(
|
|
102
|
+
project_root=self._bundle_ctx.project_root,
|
|
103
|
+
deploy_root=self._bundle_ctx.deploy_root,
|
|
104
|
+
)
|
|
105
|
+
bundle_map.add(artifact_to_process)
|
|
106
|
+
|
|
107
|
+
for src, dest in bundle_map.all_mappings(
|
|
108
|
+
absolute=True,
|
|
109
|
+
expand_directories=True,
|
|
110
|
+
):
|
|
111
|
+
self.expand_templates_in_file(src, dest)
|
|
@@ -64,15 +64,15 @@ class MissingScriptError(ClickException):
|
|
|
64
64
|
super().__init__(f'Script "{relpath}" does not exist')
|
|
65
65
|
|
|
66
66
|
|
|
67
|
-
class
|
|
68
|
-
"""A referenced
|
|
67
|
+
class InvalidTemplateInFileError(ClickException):
|
|
68
|
+
"""A referenced templated file had syntax error(s)."""
|
|
69
69
|
|
|
70
70
|
def __init__(
|
|
71
71
|
self, relpath: str, err: jinja2.TemplateError, lineno: Optional[int] = None
|
|
72
72
|
):
|
|
73
73
|
lineno_str = f":{lineno}" if lineno is not None else ""
|
|
74
74
|
super().__init__(
|
|
75
|
-
f'
|
|
75
|
+
f'File "{relpath}{lineno_str}" does not contain a valid template: {err.message}'
|
|
76
76
|
)
|
|
77
77
|
self.err = err
|
|
78
78
|
|