Skip to content

Commit 031ca2c

Browse files
authored
Merge pull request #28 from marcelmamula/latest
software_center_download: Add option to search for latest packages
2 parents f1fe7e8 + ff4c332 commit 031ca2c

File tree

3 files changed

+467
-62
lines changed

3 files changed

+467
-62
lines changed

plugins/module_utils/sap_launchpad_software_center_download_runner.py

Lines changed: 94 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -10,34 +10,85 @@
1010
from . import constants as C
1111
from .sap_api_common import _request, https_session
1212
from .sap_id_sso import _get_sso_endpoint_meta
13+
from .sap_launchpad_software_center_download_search_fuzzy import *
1314

1415
logger = logging.getLogger(__name__)
1516

1617
_HAS_DOWNLOAD_AUTHORIZATION = None
1718
MAX_RETRY_TIMES = 3
1819

1920

20-
def search_software_filename(name, deduplicate):
21-
"""Return a single software that matched the filename
21+
def search_software_filename(name, deduplicate, search_alternatives):
2222
"""
23-
search_results = _search_software(name)
24-
softwares = [r for r in search_results if r['Title'] == name or r['Description'] == name]
25-
num_files=len(softwares)
26-
if num_files == 0:
27-
raise ValueError(f'no result found for {name}')
28-
elif num_files > 1 and deduplicate == '':
29-
names = [s['Title'] for s in softwares]
30-
raise ValueError('more than one results were found: %s. '
23+
Execute search for SAP Software or its alternative when search_alternatives is true.
24+
25+
Args:
26+
name: The filename name to check (e.g. 'SAPCAR_1115-70006178.EXE').
27+
deduplicate: Select deduplication logic from 'first', 'last'
28+
search_alternatives: Boolean for enabling fuzzy search.
29+
30+
Returns:
31+
download_link: Download link of matched SAP Software.
32+
filename: File name of matched SAP Software.
33+
alternative_found: True if alternative search was successful.
34+
"""
35+
36+
alternative_found = False
37+
software_search = _search_software(name)
38+
software_filtered = [r for r in software_search if r['Title'] == name or r['Description'] == name]
39+
40+
files_count=len(software_filtered)
41+
if files_count == 0:
42+
# Run fuzzy search if search_alternatives was selected
43+
if search_alternatives:
44+
software_fuzzy_found = search_software_fuzzy(name)
45+
software_fuzzy_filtered, suggested_filename = filter_fuzzy_search(software_fuzzy_found, name)
46+
if len(software_fuzzy_filtered) == 0:
47+
raise ValueError(f'File {name} is not available to download and has no alternatives')
48+
49+
software_fuzzy_alternatives = software_fuzzy_filtered[0].get('Title')
50+
51+
# Search has to be filtered again, because API call can get
52+
# duplicates like 70SWPM10SP43_2-20009701.sar for SWPM10SP43_2-20009701.SAR
53+
software_search_alternatives = _search_software(software_fuzzy_alternatives)
54+
software_search_alternatives_filtered = [
55+
file for file in software_search_alternatives
56+
if file.get('Title', '').startswith(suggested_filename)
57+
]
58+
alternatives_count=len(software_search_alternatives_filtered)
59+
if alternatives_count == 0:
60+
raise ValueError(f'File {name} is not available to download and has no alternatives')
61+
elif alternatives_count > 1 and deduplicate == '':
62+
names = [s['Title'] for s in software_search_alternatives_filtered]
63+
raise ValueError('More than one results were found: %s. '
64+
'please use the correct full filename' % names)
65+
elif alternatives_count > 1 and deduplicate == 'first':
66+
software_found = software_search_alternatives_filtered[0]
67+
alternative_found = True
68+
elif alternatives_count > 1 and deduplicate == 'last':
69+
software_found = software_search_alternatives_filtered[alternatives_count-1]
70+
alternative_found = True
71+
else:
72+
software_found = software_search_alternatives_filtered[0]
73+
alternative_found = True
74+
else:
75+
raise ValueError(f'File {name} is not available to download. Enable "search_alternatives" to search for alternatives.')
76+
77+
elif files_count > 1 and deduplicate == '':
78+
names = [s['Title'] for s in software_filtered]
79+
raise ValueError('More than one results were found: %s. '
3180
'please use the correct full filename' % names)
32-
elif num_files > 1 and deduplicate == 'first':
33-
software = softwares[0]
34-
elif num_files > 1 and deduplicate == 'last':
35-
software = softwares[num_files-1]
81+
elif files_count > 1 and deduplicate == 'first':
82+
software_found = software_filtered[0]
83+
elif files_count > 1 and deduplicate == 'last':
84+
software_found = software_filtered[files_count-1]
3685
else:
37-
software = softwares[0]
86+
software_found = software_filtered[0]
3887

39-
download_link, filename = software['DownloadDirectLink'], name
40-
return (download_link, filename)
88+
download_link = software_found['DownloadDirectLink']
89+
filename = _get_valid_filename(software_found)
90+
91+
return (download_link, filename, alternative_found)
4192

4293

4394
def download_software(download_link, filename, output_dir, retry=0):
@@ -151,6 +202,7 @@ def download_software_via_legacy_api(username, password, download_link,
151202

152203

153204
def _search_software(keyword):
205+
154206
url = C.URL_SOFTWARE_CENTER_SERVICE + '/SearchResultSet'
155207
params = {
156208
'SEARCH_MAX_RESULT': 500,
@@ -167,7 +219,7 @@ def _search_software(keyword):
167219
j = json.loads(res.text)
168220
results = j['d']['results']
169221
except json.JSONDecodeError:
170-
# When use has no authority to search some specified softwares,
222+
# When use has no authority to search some specified files,
171223
# it will return non-json response, which is actually expected.
172224
# So just return an empty list.
173225
logger.warning('Non-JSON response returned for software searching')
@@ -246,3 +298,27 @@ def _is_checksum_matched(f, etag):
246298
for chunk in iter(lambda: f.read(4096 * hash.block_size), b""):
247299
hash.update(chunk)
248300
return hash.hexdigest() == checksum
301+
302+
303+
def _get_valid_filename(software_found):
304+
"""
305+
Ensure that CD Media have correct filenames from description.
306+
Example: S4CORE105_INST_EXPORT_1.zip downloads as 19118000000000004323
307+
308+
Args:
309+
software_found: List[0] with dictionary of file.
310+
311+
Returns:
312+
Valid filename for CD Media files, where applicable.
313+
"""
314+
315+
# Check if Title contains filename and extension
316+
if re.match(r'^[^/\\\0]+\.[^/\\\0]+$', software_found['Title']):
317+
return software_found['Title']
318+
else:
319+
# Check if Description contains filename and extension
320+
if re.match(r'^[^/\\\0]+\.[^/\\\0]+$', software_found['Description']):
321+
return software_found['Description']
322+
else:
323+
# Default to Title if Description does not help
324+
return software_found['Title']

0 commit comments

Comments
 (0)