Skip to content

Commit c9cc204

Browse files
author
Mike Cayanan
committed
Consolidate helper functions into get_package_resource_path
- Replace 4 separate functions with 1 master function - Keep backward-compatible wrappers for existing code - Reduces code duplication and improves maintainability - Supports file, dir, and auto resource type detection
1 parent 41a9fc1 commit c9cc204

1 file changed

Lines changed: 66 additions & 120 deletions

File tree

sdscli/adapters/hysds/fabfile.py

Lines changed: 66 additions & 120 deletions
Original file line numberDiff line numberDiff line change
@@ -172,177 +172,123 @@ def is_pypi_install():
172172
return os.path.exists(os.path.join(site_packages, 'hysds'))
173173

174174

175-
def get_package_config_dir(package_name, config_subdir, remote=False):
176-
"""Get config directory from installed package or editable install.
175+
def get_package_resource_path(package_name, resource_path, remote=False, resource_type='auto'):
176+
"""Get path to package resource for both PyPI and editable installs.
177+
178+
This is the master function that handles all package resource path resolution.
177179
178180
Priority:
179-
1. Installed package shared-data location (PyPI install)
180-
2. Editable install location (development)
181+
1. PyPI install: share/package/resource_path
182+
2. Editable install: ops/package/resource_path
181183
182184
:param package_name: Package name (e.g., 'hysds', 'grq2', 'mozart')
183-
:param config_subdir: Config subdirectory (e.g., 'settings', 'configs/supervisor')
185+
:param resource_path: Relative path to resource (e.g., 'scripts/db_create.py', 'configs/settings')
184186
:param remote: If True, check remote host; if False, check local machine
185-
:return: Full path to config directory
187+
:param resource_type: 'file', 'dir', or 'auto' (auto-detect based on test results)
188+
:return: Full path to resource
186189
"""
187-
import sys
188190
import sysconfig
189191

190192
base_map = {'hysds': 'mozart', 'grq2': 'sciflo', 'pele': 'sciflo', 'mozart': 'mozart'}
191193
base = base_map.get(package_name, 'mozart')
192194

193195
if remote:
194196
# Check remote host using fabric run()
195-
logger.debug(f'[get_package_config_dir] Called with package={package_name}, config_subdir={config_subdir}, remote=True')
197+
logger.debug(f'[get_package_resource_path] Called with package={package_name}, resource={resource_path}, remote=True, type={resource_type}')
196198

197-
pypi_path_cmd = f'python -c "import sysconfig, os; print(os.path.join(sysconfig.get_path(\'data\'), \'share\', \'{package_name}\', \'{config_subdir}\'))"'
198-
logger.debug(f'[get_package_config_dir] Running on remote: {pypi_path_cmd}')
199+
# Get PyPI path from remote
200+
pypi_path_cmd = f'python -c "import sysconfig, os; print(os.path.join(sysconfig.get_path(\'data\'), \'share\', \'{package_name}\', \'{resource_path}\'))"'
201+
logger.debug(f'[get_package_resource_path] Running on remote: {pypi_path_cmd}')
199202
pypi_path_result = run(pypi_path_cmd, warn_only=True)
200-
logger.debug(f'[get_package_config_dir] Result succeeded={pypi_path_result.succeeded}, return_code={pypi_path_result.return_code}')
203+
logger.debug(f'[get_package_resource_path] Result succeeded={pypi_path_result.succeeded}, return_code={pypi_path_result.return_code}')
201204

202205
if pypi_path_result.succeeded:
203206
pypi_path = pypi_path_result.strip()
204-
logger.debug(f'[get_package_config_dir] PyPI path from remote: {pypi_path}')
207+
logger.debug(f'[get_package_resource_path] PyPI path from remote: {pypi_path}')
205208

206-
logger.debug(f'[get_package_config_dir] Checking if directory exists: test -d {pypi_path}')
207-
check_result = run(f'test -d {pypi_path}', warn_only=True)
208-
logger.debug(f'[get_package_config_dir] Directory exists check succeeded={check_result.succeeded}')
209+
# Determine test command based on resource type
210+
if resource_type == 'file':
211+
test_cmd = f'test -f {pypi_path}'
212+
elif resource_type == 'dir':
213+
test_cmd = f'test -d {pypi_path}'
214+
else: # auto
215+
# Try file first, then directory
216+
test_cmd = f'test -f {pypi_path} || test -d {pypi_path}'
217+
218+
logger.debug(f'[get_package_resource_path] Checking if resource exists: {test_cmd}')
219+
check_result = run(test_cmd, warn_only=True)
220+
logger.debug(f'[get_package_resource_path] Resource exists check succeeded={check_result.succeeded}')
209221

210222
if check_result.succeeded:
211-
logger.debug(f'[get_package_config_dir] Returning PyPI path: {pypi_path}')
223+
logger.debug(f'[get_package_resource_path] Returning PyPI path: {pypi_path}')
212224
return pypi_path
213225
else:
214-
logger.debug(f'[get_package_config_dir] Directory not found at PyPI location: {pypi_path}')
226+
logger.debug(f'[get_package_resource_path] Resource not found at PyPI location: {pypi_path}')
215227
else:
216-
logger.debug(f'[get_package_config_dir] Failed to get PyPI path from remote')
228+
logger.debug(f'[get_package_resource_path] Failed to get PyPI path from remote')
217229

218230
# Fallback to editable install location
219-
fallback_path = f'~/{base}/ops/{package_name}/{config_subdir}'
220-
logger.debug(f'[get_package_config_dir] Returning fallback path: {fallback_path}')
231+
fallback_path = f'~/{base}/ops/{package_name}/{resource_path}'
232+
logger.debug(f'[get_package_resource_path] Returning fallback path: {fallback_path}')
221233
return fallback_path
222234
else:
223235
# Check local machine
224-
share_dir = os.path.join(sysconfig.get_path('data'), 'share', package_name, config_subdir)
225-
if os.path.exists(share_dir):
226-
return share_dir
236+
pypi_path = os.path.join(sysconfig.get_path('data'), 'share', package_name, resource_path)
237+
238+
# Check if resource exists based on type
239+
resource_exists = False
240+
if resource_type == 'file':
241+
resource_exists = os.path.isfile(pypi_path)
242+
elif resource_type == 'dir':
243+
resource_exists = os.path.isdir(pypi_path)
244+
else: # auto
245+
resource_exists = os.path.exists(pypi_path)
246+
247+
if resource_exists:
248+
return pypi_path
227249

228250
# Fallback to editable install location
229-
editable_dir = os.path.join(ops_dir, 'mozart/ops', package_name, config_subdir)
230-
if os.path.exists(editable_dir):
231-
return editable_dir
251+
editable_path = os.path.join(ops_dir, 'mozart/ops', package_name, resource_path)
252+
if os.path.exists(editable_path):
253+
return editable_path
232254

233255
# Last resort: return the editable path even if it doesn't exist
234-
# (will fail later with a clear error message)
235-
return editable_dir
256+
return editable_path
257+
258+
259+
# Backward compatibility wrappers
260+
def get_package_config_dir(package_name, config_subdir, remote=False):
261+
"""Get config directory from installed package or editable install.
262+
263+
This is a wrapper around get_package_resource_path for backward compatibility.
264+
"""
265+
return get_package_resource_path(package_name, config_subdir, remote=remote, resource_type='dir')
236266

237267

238268
def get_package_script_path(package_name, script_relative_path):
239269
"""Get full path to a package script file on remote host.
240270
241-
For PyPI installs: Returns path in share/package/scripts/
242-
For editable installs: Returns path in ops/package/scripts/
243-
244-
This function checks the REMOTE host to determine the correct path.
245-
246-
:param package_name: Package name (e.g., 'hysds', 'grq2', 'mozart')
247-
:param script_relative_path: Relative path to script (e.g., 'scripts/install_base_es_template.sh')
248-
:return: Full path to script on remote host
271+
This is a wrapper around get_package_resource_path for backward compatibility.
249272
"""
250-
base_map = {'hysds': 'mozart', 'grq2': 'sciflo', 'pele': 'sciflo', 'mozart': 'mozart'}
251-
base = base_map.get(package_name, 'mozart')
252-
253-
logger.debug(f'[get_package_script_path] Called with package={package_name}, script={script_relative_path}')
254-
255-
# Try PyPI location first by checking on remote host
256-
pypi_path_cmd = f'python -c "import sysconfig, os; print(os.path.join(sysconfig.get_path(\'data\'), \'share\', \'{package_name}\', \'{script_relative_path}\'))"'
257-
logger.debug(f'[get_package_script_path] Running on remote: {pypi_path_cmd}')
258-
pypi_path_result = run(pypi_path_cmd, warn_only=True)
259-
logger.debug(f'[get_package_script_path] Result succeeded={pypi_path_result.succeeded}, return_code={pypi_path_result.return_code}')
260-
261-
if pypi_path_result.succeeded:
262-
pypi_path = pypi_path_result.strip()
263-
logger.debug(f'[get_package_script_path] PyPI path from remote: {pypi_path}')
264-
265-
# Check if file exists at PyPI location on remote host
266-
logger.debug(f'[get_package_script_path] Checking if file exists: test -f {pypi_path}')
267-
check_result = run(f'test -f {pypi_path}', warn_only=True)
268-
logger.debug(f'[get_package_script_path] File exists check succeeded={check_result.succeeded}')
269-
270-
if check_result.succeeded:
271-
logger.debug(f'[get_package_script_path] Returning PyPI path: {pypi_path}')
272-
return pypi_path
273-
else:
274-
logger.debug(f'[get_package_script_path] File not found at PyPI location: {pypi_path}')
275-
else:
276-
logger.debug(f'[get_package_script_path] Failed to get PyPI path from remote')
277-
278-
# Fallback to editable install location
279-
fallback_path = os.path.join(ops_dir, f'{base}/ops/{package_name}/{script_relative_path}')
280-
logger.debug(f'[get_package_script_path] Returning fallback path: {fallback_path}')
281-
return fallback_path
273+
return get_package_resource_path(package_name, script_relative_path, remote=True, resource_type='file')
282274

283275

284276
def copy_package_config_file(package_name, config_relative_path, dest):
285277
"""Copy a package config file to destination on remote host.
286278
287-
For PyPI installs: Copies from share/package/config_relative_path
288-
For editable installs: Copies from ops/package/config_relative_path
289-
290-
This function runs entirely on the remote host.
291-
292-
:param package_name: Package name (e.g., 'hysds', 'grq2', 'mozart')
293-
:param config_relative_path: Relative path to config (e.g., 'configs/orchestrator/orchestrator_jobs.json')
294-
:param dest: Destination path on remote host
279+
This is a wrapper around get_package_resource_path for backward compatibility.
295280
"""
296-
base_map = {'hysds': 'mozart', 'grq2': 'sciflo', 'pele': 'sciflo', 'mozart': 'mozart'}
297-
base = base_map.get(package_name, 'mozart')
298-
299-
# Try PyPI location first
300-
pypi_path_cmd = f'python -c "import sysconfig, os; print(os.path.join(sysconfig.get_path(\'data\'), \'share\', \'{package_name}\', \'{config_relative_path}\'))"'
301-
pypi_path_result = run(pypi_path_cmd, warn_only=True)
302-
303-
if pypi_path_result.succeeded:
304-
pypi_path = pypi_path_result.strip()
305-
check_result = run(f'test -f {pypi_path}', warn_only=True)
306-
307-
if check_result.succeeded:
308-
run(f'cp {pypi_path} {dest}')
309-
return
310-
311-
# Fallback to editable install location
312-
fallback_path = f'~/{base}/ops/{package_name}/{config_relative_path}'
313-
run(f'cp {fallback_path} {dest}')
281+
src_path = get_package_resource_path(package_name, config_relative_path, remote=True, resource_type='file')
282+
run(f'cp {src_path} {dest}')
314283

315284

316285
def copy_package_dir(package_name, dir_relative_path, dest):
317286
"""Copy a package directory to destination on remote host.
318287
319-
For PyPI installs: Copies from share/package/dir_relative_path
320-
For editable installs: Copies from ops/package/dir_relative_path
321-
322-
This function runs entirely on the remote host.
323-
324-
:param package_name: Package name (e.g., 'hysds', 'grq2', 'mozart')
325-
:param dir_relative_path: Relative path to directory (e.g., 'scripts/job_creators')
326-
:param dest: Destination path on remote host
288+
This is a wrapper around get_package_resource_path for backward compatibility.
327289
"""
328-
base_map = {'hysds': 'mozart', 'grq2': 'sciflo', 'pele': 'sciflo', 'mozart': 'mozart'}
329-
base = base_map.get(package_name, 'mozart')
330-
331-
# Try PyPI location first
332-
pypi_path_cmd = f'python -c "import sysconfig, os; print(os.path.join(sysconfig.get_path(\'data\'), \'share\', \'{package_name}\', \'{dir_relative_path}\'))"'
333-
pypi_path_result = run(pypi_path_cmd, warn_only=True)
334-
335-
if pypi_path_result.succeeded:
336-
pypi_path = pypi_path_result.strip()
337-
check_result = run(f'test -d {pypi_path}', warn_only=True)
338-
339-
if check_result.succeeded:
340-
run(f'cp -rp {pypi_path} {dest}')
341-
return
342-
343-
# Fallback to editable install location
344-
fallback_path = f'~/{base}/ops/{package_name}/{dir_relative_path}'
345-
run(f'cp -rp {fallback_path} {dest}')
290+
src_path = get_package_resource_path(package_name, dir_relative_path, remote=True, resource_type='dir')
291+
run(f'cp -rp {src_path} {dest}')
346292

347293

348294
def resolve_files_dir(fname, files_dir):

0 commit comments

Comments
 (0)