forked from forcedotcom/datacloud-customcode-python-sdk
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathrun.py
More file actions
127 lines (109 loc) · 4.43 KB
/
run.py
File metadata and controls
127 lines (109 loc) · 4.43 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
# Copyright (c) 2025, Salesforce, Inc.
# SPDX-License-Identifier: Apache-2
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import importlib
import json
import os
from pathlib import Path
import runpy
import sys
from typing import (
List,
Optional,
Union,
)
from datacustomcode.config import config
from datacustomcode.scan import find_base_directory, get_package_type
def _set_config_option(config_obj, key: str, value: str) -> None:
"""Set an option on a config object if it exists and has options attribute.
Args:
config_obj: Config object (reader_config or writer_config)
key: Option key to set
value: Option value to set
"""
if config_obj and hasattr(config_obj, "options"):
config_obj.options[key] = value
def run_entrypoint(
entrypoint: str,
config_file: Union[str, None],
dependencies: List[str],
profile: str,
sf_cli_org: Optional[str] = None,
) -> None:
"""Run the entrypoint script with the given config and dependencies.
Args:
entrypoint: The entrypoint script to run.
config_file: The config file to use.
dependencies: The dependencies to import.
profile: The credentials profile to use.
sf_cli_org: Optional SF CLI org alias or username. If provided, credentials
are fetched via `sf org display` instead of from credentials.ini.
"""
add_py_folder(entrypoint)
# Read dataspace from config.json (required)
entrypoint_dir = os.path.dirname(entrypoint)
config_json_path = os.path.join(entrypoint_dir, "config.json")
if not os.path.exists(config_json_path):
raise FileNotFoundError(
f"config.json not found at {config_json_path}. config.json is required."
)
base_directory = find_base_directory(entrypoint)
package_type = get_package_type(base_directory)
try:
with open(config_json_path, "r") as f:
config_json = json.load(f)
except json.JSONDecodeError as err:
raise ValueError(
f"config.json at {config_json_path} is not valid JSON"
) from err
if package_type == "script":
# Require dataspace to be present in config.json
dataspace = config_json.get("dataspace")
if not dataspace:
raise ValueError(
f"config.json at {config_json_path} is missing required "
f"field 'dataspace'. "
f"Please ensure config.json contains a 'dataspace' field."
)
# Load config file first
if config_file:
config.load(config_file)
# Add dataspace to reader and writer config options
_set_config_option(config.reader_config, "dataspace", dataspace)
_set_config_option(config.writer_config, "dataspace", dataspace)
if sf_cli_org:
_set_config_option(config.reader_config, "sf_cli_org", sf_cli_org)
_set_config_option(config.writer_config, "sf_cli_org", sf_cli_org)
elif profile != "default":
_set_config_option(config.reader_config, "credentials_profile", profile)
_set_config_option(config.writer_config, "credentials_profile", profile)
for dependency in dependencies:
try:
importlib.import_module(dependency)
except ModuleNotFoundError as exc:
try:
if "." in dependency:
module_name, object_name = dependency.rsplit(".", 1)
module = importlib.import_module(module_name)
getattr(module, object_name)
else:
raise exc
except (ModuleNotFoundError, AttributeError) as inner_exc:
raise inner_exc from exc
runpy.run_path(entrypoint, init_globals=globals(), run_name="__main__")
def add_py_folder(entrypoint: str):
default_py_folder = "py-files" # Hardcoded folder name
cwd = Path.cwd().joinpath(entrypoint)
py_folder = cwd.parent.joinpath(default_py_folder)
sys.path.append(str(py_folder))