fosslight-util 2.0.0__py3-none-any.whl → 2.1.29__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.
@@ -5,7 +5,6 @@
5
5
  import logging
6
6
  import re
7
7
  import requests
8
- from npm.bindings import npm_run
9
8
  from lastversion import latest
10
9
  from bs4 import BeautifulSoup
11
10
  from urllib.request import urlopen
@@ -14,120 +13,480 @@ import fosslight_util.constant as constant
14
13
  logger = logging.getLogger(constant.LOGGER_NAME)
15
14
 
16
15
 
17
- def extract_name_version_from_link(link):
16
+ def version_exists(pkg_type, origin_name, version):
17
+ try:
18
+ if pkg_type in ['npm', 'npm2']:
19
+ r = requests.get(f"https://registry.npmjs.org/{origin_name}", timeout=5)
20
+ if r.status_code == 200:
21
+ data = r.json()
22
+ return version in data.get('versions', {})
23
+ elif pkg_type == 'pypi':
24
+ r = requests.get(f"https://pypi.org/pypi/{origin_name}/{version}/json", timeout=5)
25
+ return r.status_code == 200
26
+ elif pkg_type == 'maven':
27
+ r = requests.get(f'https://api.deps.dev/v3alpha/systems/maven/packages/{origin_name}', timeout=5)
28
+ if r.status_code == 200:
29
+ versions = r.json().get('versions', [])
30
+ for vobj in versions:
31
+ vkey = vobj.get('versionKey') or {}
32
+ if vkey.get('version') == version:
33
+ return True
34
+ return False
35
+ elif pkg_type == 'pub':
36
+ r = requests.get(f'https://pub.dev/api/packages/{origin_name}', timeout=5)
37
+ if r.status_code == 200:
38
+ versions = r.json().get('versions', [])
39
+ return any(v.get('version') == version for v in versions if isinstance(v, dict))
40
+ elif pkg_type == 'go':
41
+ if not version.startswith('v'):
42
+ version = f'v{version}'
43
+ r = requests.get(f'https://proxy.golang.org/{origin_name}/@v/list', timeout=5)
44
+ if r.status_code == 200:
45
+ listed = r.text.splitlines()
46
+ return version in listed
47
+ except Exception as e:
48
+ logger.info(f'version_exists check failed ({pkg_type}:{origin_name}:{version}) {e}')
49
+ return True
50
+ return False
51
+
52
+
53
+ def extract_name_version_from_link(link, checkout_version):
18
54
  oss_name = ""
19
55
  oss_version = ""
56
+ matched = False
57
+ direct_maven = False
58
+
20
59
  if link.startswith("www."):
21
60
  link = link.replace("www.", "https://www.", 1)
22
- for key, value in constant.PKG_PATTERN.items():
23
- p = re.compile(value)
24
- match = p.match(link)
25
- if match:
26
- try:
27
- origin_name = match.group(1)
28
- if (key == "pypi") or (key == "pypi2"):
29
- oss_name = f"pypi:{origin_name}"
30
- oss_name = re.sub(r"[-_.]+", "-", oss_name).lower()
31
- oss_version = match.group(2)
32
- elif key == "maven":
33
- artifact = match.group(2)
34
- oss_name = f"{origin_name}:{artifact}"
35
- origin_name = oss_name
36
- oss_version = match.group(3)
37
- elif key == "npm" or key == "npm2":
38
- oss_name = f"npm:{origin_name}"
39
- oss_version = match.group(2)
40
- elif key == "pub":
41
- oss_name = f"pub:{origin_name}"
42
- oss_version = match.group(2)
43
- elif key == "cocoapods":
44
- oss_name = f"cocoapods:{origin_name}"
45
- except Exception as ex:
46
- logger.info(f"extract_name_version_from_link {key}:{ex}")
47
- if oss_name and (not oss_version):
48
- if key in ["pypi", "maven", "npm", "npm2", "pub"]:
49
- oss_version, link = get_latest_package_version(link, key, origin_name)
50
- logger.debug(f'Try to download with the latest version:{link}')
51
- break
52
- return oss_name, oss_version, link, key
61
+
62
+ if (not matched and (
63
+ link.startswith('https://repo1.maven.org/maven2/') or
64
+ link.startswith('https://dl.google.com/android/maven2/')
65
+ )):
66
+ parsed = parse_direct_maven_url(link)
67
+ if parsed:
68
+ origin_name, parsed_version = parsed
69
+ oss_name = origin_name # groupId:artifactId
70
+ oss_version = parsed_version or ""
71
+ matched = True
72
+ direct_maven = True
73
+ pkg_type = 'maven'
74
+
75
+ for direct_key in ["maven_repo1", "maven_google"]:
76
+ pattern = constant.PKG_PATTERN.get(direct_key)
77
+ if pattern and re.match(pattern, link):
78
+ parsed = parse_direct_maven_url(link)
79
+ if parsed:
80
+ origin_name, parsed_version = parsed
81
+ oss_name = origin_name
82
+ oss_version = parsed_version or ""
83
+ matched = True
84
+ direct_maven = True
85
+ pkg_type = 'maven'
86
+ break
87
+
88
+ if not matched:
89
+ for key, value in constant.PKG_PATTERN.items():
90
+ if key in ["maven_repo1", "maven_google"]:
91
+ continue
92
+ p = re.compile(value)
93
+ match = p.match(link)
94
+ if match:
95
+ try:
96
+ pkg_type = key
97
+ origin_name = match.group(1)
98
+ if (key == "pypi") or (key == "pypi2"):
99
+ oss_name = f"pypi:{origin_name}"
100
+ oss_name = re.sub(r"[-_.]+", "-", oss_name)
101
+ oss_version = match.group(2)
102
+ pkg_type = 'pypi'
103
+ elif key == "maven":
104
+ artifact = match.group(2)
105
+ oss_name = f"{origin_name}:{artifact}"
106
+ origin_name = oss_name
107
+ oss_version = match.group(3)
108
+ elif key == "npm" or key == "npm2":
109
+ oss_name = f"npm:{origin_name}"
110
+ oss_version = match.group(2)
111
+ elif key == "pub":
112
+ oss_name = f"pub:{origin_name}"
113
+ oss_version = match.group(2)
114
+ elif key == "cocoapods":
115
+ oss_name = f"cocoapods:{origin_name}"
116
+ elif key == "go":
117
+ if origin_name.endswith('/'):
118
+ origin_name = origin_name[:-1]
119
+ oss_name = f"go:{origin_name}"
120
+ oss_version = match.group(2)
121
+ elif key == "cargo":
122
+ oss_name = f"cargo:{origin_name}"
123
+ oss_version = match.group(2)
124
+ except Exception as ex:
125
+ logger.info(f"extract_name_version_from_link {key}:{ex}")
126
+ if oss_name:
127
+ matched = True
128
+ break
129
+
130
+ if not matched:
131
+ return "", "", link, ""
132
+ else:
133
+ need_latest = False
134
+ if not oss_version and checkout_version:
135
+ oss_version = checkout_version.strip()
136
+ if pkg_type in ["pypi", "maven", "npm", "npm2", "pub", "go"]:
137
+ if oss_version:
138
+ try:
139
+ if not version_exists(pkg_type, origin_name, oss_version):
140
+ logger.info(f'Version {oss_version} not found for {oss_name}; will attempt latest fallback')
141
+ need_latest = True
142
+ except Exception as e:
143
+ logger.info(f'Version validation failed ({oss_name}:{oss_version}) {e}; will attempt latest fallback')
144
+ need_latest = True
145
+ else:
146
+ need_latest = True
147
+ if need_latest:
148
+ latest_ver = get_latest_package_version(link, pkg_type, origin_name)
149
+ if latest_ver:
150
+ if oss_version and latest_ver != oss_version:
151
+ logger.info(f'Fallback to latest version {latest_ver} (previous invalid: {oss_version})')
152
+ elif not oss_version:
153
+ logger.info(f'Using latest version {latest_ver} (no version detected)')
154
+ oss_version = latest_ver
155
+
156
+ try:
157
+ if oss_version:
158
+ if pkg_type == 'maven' and direct_maven:
159
+ # Skip if oss_name malformed
160
+ if ':' in oss_name:
161
+ parts = oss_name.split(':', 1)
162
+ group_id, artifact_id = parts[0], parts[1]
163
+ group_path = group_id.replace('.', '/')
164
+ if (
165
+ link.startswith('https://repo1.maven.org/maven2/') or
166
+ link.startswith('http://repo1.maven.org/maven2/')
167
+ ):
168
+ if not re.search(r'/\d[^/]*/*$', link.rstrip('/')):
169
+ link = (
170
+ f'https://repo1.maven.org/maven2/{group_path}/'
171
+ f'{artifact_id}/{oss_version}'
172
+ )
173
+ elif (
174
+ link.startswith('https://dl.google.com/android/maven2/') or
175
+ link.startswith('http://dl.google.com/android/maven2/')
176
+ ):
177
+ if not re.search(r'/\d[^/]*/*$', link.rstrip('/')):
178
+ link = (
179
+ f'https://dl.google.com/android/maven2/{group_path}/'
180
+ f'{artifact_id}/{oss_version}/{artifact_id}-{oss_version}-sources.jar'
181
+ )
182
+ else:
183
+ logger.debug(f'Skip maven normalization due to invalid oss_name: {oss_name}')
184
+ else:
185
+ link = get_new_link_with_version(link, pkg_type, origin_name, oss_version)
186
+ except Exception as _e:
187
+ logger.info(f'Failed to build versioned link for {oss_name or origin_name}:{oss_version} {_e}')
188
+
189
+ return oss_name, oss_version, link, pkg_type
190
+
191
+
192
+ def parse_direct_maven_url(url):
193
+ try:
194
+ clean_url = url.replace('https://', '').replace('http://', '')
195
+ if clean_url.startswith('repo1.maven.org/maven2/'):
196
+ base_path = clean_url[len('repo1.maven.org/maven2/'):]
197
+ elif clean_url.startswith('dl.google.com/android/maven2/'):
198
+ base_path = clean_url[len('dl.google.com/android/maven2/'):]
199
+ else:
200
+ return None
201
+
202
+ base_path = base_path.rstrip('/')
203
+ # Strip file name if ends with known artifact extension.
204
+ if any(base_path.endswith(ext) for ext in ['.jar', '.pom', '.aar']):
205
+ base_path = '/'.join(base_path.split('/')[:-1])
206
+
207
+ parts = base_path.split('/')
208
+ if len(parts) < 2:
209
+ return None
210
+
211
+ version = None
212
+ artifact_id = None
213
+ if len(parts) >= 3:
214
+ potential_version = parts[-1]
215
+ potential_artifact = parts[-2]
216
+ if re.search(r'\d', potential_version):
217
+ version = potential_version
218
+ artifact_id = potential_artifact
219
+ group_parts = parts[:-2]
220
+ else:
221
+ artifact_id = parts[-1]
222
+ group_parts = parts[:-1]
223
+ else:
224
+ artifact_id = parts[-1]
225
+ group_parts = parts[:-1]
226
+
227
+ group_id = '.'.join(group_parts)
228
+ if not group_id or not artifact_id:
229
+ return None
230
+
231
+ maven_name = f"{group_id}:{artifact_id}"
232
+ return maven_name, version
233
+ except Exception as e:
234
+ logger.debug(f'Failed to parse direct Maven URL {url}: {e}')
235
+ return None
236
+
237
+
238
+ def get_new_link_with_version(link, pkg_type, oss_name, oss_version):
239
+ if pkg_type == "pypi":
240
+ link = f'https://pypi.org/project/{oss_name}/{oss_version}'
241
+ elif pkg_type == "maven":
242
+ oss_name = oss_name.replace(':', '/')
243
+ link = f'https://mvnrepository.com/artifact/{oss_name}/{oss_version}'
244
+ elif pkg_type == "npm" or pkg_type == "npm2":
245
+ link = f'https://www.npmjs.com/package/{oss_name}/v/{oss_version}'
246
+ elif pkg_type == "pub":
247
+ link = f'https://pub.dev/packages/{oss_name}/versions/{oss_version}'
248
+ elif pkg_type == "go":
249
+ if not oss_version.startswith('v'):
250
+ oss_version = f'v{oss_version}'
251
+ link = f'https://pkg.go.dev/{oss_name}@{oss_version}'
252
+ elif pkg_type == "cargo":
253
+ link = f'https://crates.io/crates/{oss_name}/{oss_version}'
254
+ return link
53
255
 
54
256
 
55
257
  def get_latest_package_version(link, pkg_type, oss_name):
56
258
  find_version = ''
57
- link_with_version = link
58
259
 
59
260
  try:
60
261
  if pkg_type in ['npm', 'npm2']:
61
- stderr, stdout = npm_run('view', oss_name, 'version')
62
- if stdout:
63
- find_version = stdout.strip()
64
- link_with_version = f'https://www.npmjs.com/package/{oss_name}/v/{find_version}'
262
+ npm_response = requests.get(f"https://registry.npmjs.org/{oss_name}")
263
+ if npm_response.status_code == 200:
264
+ find_version = npm_response.json().get("dist-tags", {}).get("latest")
65
265
  elif pkg_type == 'pypi':
66
266
  find_version = str(latest(oss_name, at='pip', output_format='version', pre_ok=True))
67
- link_with_version = f'https://pypi.org/project/{oss_name}/{find_version}'
68
267
  elif pkg_type == 'maven':
69
268
  maven_response = requests.get(f'https://api.deps.dev/v3alpha/systems/maven/packages/{oss_name}')
70
269
  if maven_response.status_code == 200:
71
- find_version = maven_response.json().get('versions')[-1].get('versionKey').get('version')
72
- oss_name = oss_name.replace(':', '/')
73
- link_with_version = f'https://mvnrepository.com/artifact/{oss_name}/{find_version}'
270
+ versions = maven_response.json().get('versions', [])
271
+ if versions:
272
+ # Some version entries may miss publishedAt; fallback to semantic version ordering.
273
+ def sem_key(vstr: str):
274
+ # Parse semantic version with optional prerelease label
275
+ # Examples: 1.9.0, 1.10.0-alpha, 2.0.0-rc
276
+ m = re.match(r'^(\d+)(?:\.(\d+))?(?:\.(\d+))?(?:[-.]([A-Za-z0-9]+))?$', vstr)
277
+ if not m:
278
+ return (0, 0, 0, 999)
279
+ major = int(m.group(1) or 0)
280
+ minor = int(m.group(2) or 0)
281
+ patch = int(m.group(3) or 0)
282
+ label = (m.group(4) or '').lower()
283
+ # Assign label weights: stable > rc > beta > alpha
284
+ label_weight_map = {
285
+ 'alpha': -3,
286
+ 'beta': -2,
287
+ 'rc': -1
288
+ }
289
+ weight = label_weight_map.get(label, 0 if label == '' else -4)
290
+ return (major, minor, patch, weight)
291
+
292
+ with_pub = [v for v in versions if v.get('publishedAt')]
293
+ if with_pub:
294
+ cand = max(with_pub, key=lambda v: v.get('publishedAt'))
295
+ else:
296
+ decorated = []
297
+ for v in versions:
298
+ vkey = v.get('versionKey', {})
299
+ ver = vkey.get('version', '')
300
+ if ver:
301
+ decorated.append((sem_key(ver), ver, v))
302
+ if decorated:
303
+ decorated.sort(key=lambda t: t[0])
304
+ stable_candidates = [t for t in decorated if t[0][3] == 0]
305
+ if stable_candidates:
306
+ cand = stable_candidates[-1][2]
307
+ else:
308
+ cand = decorated[-1][2]
309
+ else:
310
+ cand = versions[-1]
311
+ find_version = cand.get('versionKey', {}).get('version', '')
74
312
  elif pkg_type == 'pub':
75
313
  pub_response = requests.get(f'https://pub.dev/api/packages/{oss_name}')
76
314
  if pub_response.status_code == 200:
77
315
  find_version = pub_response.json().get('latest').get('version')
78
- link_with_version = f'https://pub.dev/packages/{oss_name}/versions/{find_version}'
316
+ elif pkg_type == 'go':
317
+ go_response = requests.get(f'https://proxy.golang.org/{oss_name}/@latest')
318
+ if go_response.status_code == 200:
319
+ find_version = go_response.json().get('Version')
320
+ if find_version.startswith('v'):
321
+ find_version = find_version[1:]
79
322
  except Exception as e:
80
- logger.debug(f'Fail to get latest package version({link}:{e})')
81
- return find_version, link_with_version
323
+ logger.info(f'Fail to get latest package version({link}:{e})')
324
+ return find_version
82
325
 
83
326
 
84
- def get_downloadable_url(link):
327
+ def get_downloadable_url(link, checkout_version):
85
328
 
86
329
  ret = False
87
330
  result_link = link
88
331
 
89
- oss_name, oss_version, new_link, pkg_type = extract_name_version_from_link(link)
332
+ oss_name, oss_version, new_link, pkg_type = extract_name_version_from_link(link, checkout_version)
90
333
  new_link = new_link.replace('http://', '')
91
334
  new_link = new_link.replace('https://', '')
92
335
 
93
336
  if pkg_type == "pypi":
94
337
  ret, result_link = get_download_location_for_pypi(new_link)
95
- elif pkg_type == "maven" or new_link.startswith('repo1.maven.org/'):
338
+ elif pkg_type == "maven" or new_link.startswith('repo1.maven.org/') or new_link.startswith('dl.google.com/android/maven2/'):
96
339
  ret, result_link = get_download_location_for_maven(new_link)
97
340
  elif (pkg_type in ["npm", "npm2"]) or new_link.startswith('registry.npmjs.org/'):
98
341
  ret, result_link = get_download_location_for_npm(new_link)
99
342
  elif pkg_type == "pub":
100
343
  ret, result_link = get_download_location_for_pub(new_link)
344
+ elif pkg_type == "go":
345
+ ret, result_link = get_download_location_for_go(new_link)
346
+ elif pkg_type == "cargo":
347
+ ret, result_link = get_download_location_for_cargo(new_link)
348
+ return ret, result_link, oss_name, oss_version, pkg_type
349
+
350
+
351
+ def get_download_location_for_cargo(link):
352
+ # get the url for downloading source file: https://crates.io/api/v1/crates/<name>/<version>/download
353
+ ret = False
354
+ new_link = ''
355
+ host = 'https://crates.io/api/v1/crates'
356
+
357
+ try:
358
+ dn_loc_re = re.findall(r'crates.io\/crates\/([^\/]+)\/?([^\/]*)', link)
359
+ if dn_loc_re:
360
+ oss_name = dn_loc_re[0][0]
361
+ oss_version = dn_loc_re[0][1]
362
+
363
+ new_link = f'{host}/{oss_name}/{oss_version}/download'
364
+ res = urlopen(new_link)
365
+ if res.getcode() == 200:
366
+ ret = True
367
+ else:
368
+ logger.warning(f'Cannot find the valid link for cargo (url:{new_link}')
369
+ except Exception as error:
370
+ ret = False
371
+ logger.warning(f'Cannot find the link for cargo (url:{link}({(new_link)})): {error}')
372
+
373
+ return ret, new_link
101
374
 
102
- return ret, result_link, oss_name, oss_version
375
+
376
+ def get_download_location_for_go(link):
377
+ # get the url for downloading source file: https://proxy.golang.org/<module>/@v/VERSION.zip
378
+ ret = False
379
+ new_link = ''
380
+ host = 'https://proxy.golang.org'
381
+
382
+ try:
383
+ dn_loc_re = re.findall(r'pkg.go.dev\/([^\@]+)\@?([^\/]*)', link)
384
+ if dn_loc_re:
385
+ oss_name = dn_loc_re[0][0]
386
+ if oss_name.endswith('/'):
387
+ oss_name = oss_name[:-1]
388
+ oss_version = dn_loc_re[0][1]
389
+
390
+ new_link = f'{host}/{oss_name}/@v/{oss_version}.zip'
391
+ try:
392
+ res = urlopen(new_link)
393
+ if res.getcode() == 200:
394
+ ret = True
395
+ else:
396
+ logger.warning(f'Cannot find the valid link for go (url:{new_link}')
397
+ except Exception as e:
398
+ logger.warning(f'Fail to find the valid link for go (url:{new_link}: {e}')
399
+ except Exception as error:
400
+ ret = False
401
+ logger.warning(f'Cannot find the link for go (url:{link}({(new_link)})): {error}')
402
+
403
+ return ret, new_link
404
+
405
+
406
+ def get_available_wheel_urls(name, version):
407
+ try:
408
+ api_url = f'https://pypi.org/pypi/{name}/{version}/json'
409
+ response = requests.get(api_url)
410
+ if response.status_code == 200:
411
+ data = response.json()
412
+ wheel_urls = []
413
+
414
+ for file_info in data.get('urls', []):
415
+ if file_info.get('packagetype') == 'bdist_wheel':
416
+ wheel_urls.append(file_info.get('url'))
417
+
418
+ return wheel_urls
419
+ else:
420
+ logger.warning(f'Cannot get PyPI API data for {name}({version})')
421
+ return []
422
+
423
+ except Exception as error:
424
+ logger.warning(f'Failed to get wheel URLs from PyPI API: {error}')
425
+ return []
103
426
 
104
427
 
105
428
  def get_download_location_for_pypi(link):
106
- # get the url for downloading source file in pypi.org/project/(oss_name)/(oss_version)/#files
429
+ # get the url for downloading source file: https://docs.pypi.org/api/ Predictable URLs
107
430
  ret = False
108
431
  new_link = ''
432
+ host = 'https://files.pythonhosted.org'
109
433
 
110
434
  try:
111
435
  dn_loc_re = re.findall(r'pypi.org\/project\/?([^\/]*)\/?([^\/]*)', link)
112
436
  oss_name = dn_loc_re[0][0]
437
+ oss_name = re.sub(r"[-_.]+", "-", oss_name)
113
438
  oss_version = dn_loc_re[0][1]
114
439
 
115
- pypi_url = 'https://pypi.org/project/' + oss_name + '/' + oss_version + '/#files'
116
-
117
- content = urlopen(pypi_url).read().decode('utf8')
118
- bs_obj = BeautifulSoup(content, 'html.parser')
119
-
120
- card_file_list = bs_obj.findAll('div', {'class': 'card file__card'})
121
-
122
- for card_file in card_file_list:
123
- file_code = card_file.find('code').text
124
- if file_code.lower() == "source":
125
- new_link = card_file.find('a').attrs['href']
440
+ # 1. Source distribution 시도
441
+ new_link = f'{host}/packages/source/{oss_name[0]}/{oss_name}/{oss_name}-{oss_version}.tar.gz'
442
+ try:
443
+ res = urlopen(new_link)
444
+ if res.getcode() == 200:
126
445
  ret = True
127
- break
446
+ return ret, new_link
447
+ except Exception:
448
+ oss_name = re.sub(r"[-]+", "_", oss_name)
449
+ new_link = f'{host}/packages/source/{oss_name[0]}/{oss_name}/{oss_name}-{oss_version}.tar.gz'
450
+ try:
451
+ res = urlopen(new_link)
452
+ if res.getcode() == 200:
453
+ ret = True
454
+ return ret, new_link
455
+ except Exception:
456
+ pass
457
+
458
+ # 2. Source distribution이 없으면 wheel 파일들을 시도
459
+ wheel_urls = get_available_wheel_urls(oss_name, oss_version)
460
+
461
+ if wheel_urls:
462
+ # Pure Python wheel을 우선적으로 찾기
463
+ for wheel_url in wheel_urls:
464
+ if 'py3-none-any' in wheel_url or 'py2.py3-none-any' in wheel_url:
465
+ try:
466
+ res = urlopen(wheel_url)
467
+ if res.getcode() == 200:
468
+ ret = True
469
+ new_link = wheel_url
470
+ logger.info(f'Using wheel file : {wheel_url}')
471
+ return ret, new_link
472
+ except Exception:
473
+ continue
474
+
475
+ # Pure Python wheel이 없으면 첫 번째 wheel 시도
476
+ if wheel_urls:
477
+ try:
478
+ res = urlopen(wheel_urls[0])
479
+ if res.getcode() == 200:
480
+ ret = True
481
+ new_link = wheel_urls[0]
482
+ logger.info(f'Using wheel file : {wheel_urls[0]}')
483
+ return ret, new_link
484
+ except Exception:
485
+ pass
486
+
128
487
  except Exception as error:
129
488
  ret = False
130
- logger.warning('Cannot find the link for pypi (url:'+link+') '+str(error))
489
+ logger.warning(f'Cannot find the link for pypi (url:{link}({new_link})) e:{str(error)}')
131
490
 
132
491
  return ret, new_link
133
492
 
@@ -140,19 +499,52 @@ def get_download_location_for_maven(link):
140
499
 
141
500
  try:
142
501
  if link.startswith('mvnrepository.com/artifact/'):
143
- dn_loc_split = link.replace('mvnrepository.com/', '').split('/')
144
- group_id = dn_loc_split[1].replace('.', '/')
145
- dn_loc = 'https://repo1.maven.org/maven2/' + group_id + '/' + dn_loc_split[2] + '/' + dn_loc_split[3]
502
+ parts = link.replace('mvnrepository.com/artifact/', '').split('/')
503
+ if len(parts) < 2:
504
+ raise Exception('invalid mvnrepository artifact url')
505
+ group_raw = parts[0]
506
+ artifact_id = parts[1]
507
+ version = parts[2] if len(parts) > 2 and parts[2] else ''
508
+ group_path = group_raw.replace('.', '/')
509
+
510
+ repo_base = f'https://repo1.maven.org/maven2/{group_path}/{artifact_id}'
511
+ try:
512
+ urlopen(repo_base)
513
+ if version:
514
+ dn_loc = f'{repo_base}/{version}'
515
+ else:
516
+ new_link = repo_base
517
+ ret = True
518
+ return ret, new_link
519
+ except Exception:
520
+ google_base = f'https://dl.google.com/android/maven2/{group_path}/{artifact_id}'
521
+ if version:
522
+ google_sources = f'{google_base}/{version}/{artifact_id}-{version}-sources.jar'
523
+ try:
524
+ res_g = urlopen(google_sources)
525
+ if res_g.getcode() == 200:
526
+ ret = True
527
+ return ret, google_sources
528
+ except Exception:
529
+ pass
530
+ new_link = google_base
531
+ ret = True
532
+ return ret, new_link
146
533
 
147
534
  elif link.startswith('repo1.maven.org/maven2/'):
148
- dn_loc_split = link.replace('repo1.maven.org/maven2/', '').split('/')
149
-
150
535
  if link.endswith('.tar.gz') or link.endswith('.jar') or link.endswith('.tar.xz'):
151
536
  new_link = 'https://' + link
152
537
  ret = True
153
538
  return ret, new_link
154
539
  else:
155
540
  dn_loc = 'https://' + link
541
+ elif link.startswith('dl.google.com/android/maven2/'):
542
+ if link.endswith('.jar'):
543
+ new_link = 'https://' + link
544
+ ret = True
545
+ return ret, new_link
546
+ else:
547
+ dn_loc = 'https://' + link
156
548
  else:
157
549
  raise Exception("not valid url for maven")
158
550
 
@@ -4,7 +4,9 @@
4
4
  # SPDX-License-Identifier: Apache-2.0
5
5
 
6
6
  import logging
7
+ from typing import List, Dict
7
8
  from fosslight_util.constant import LOGGER_NAME
9
+ from fosslight_util.oss_item import FileItem
8
10
 
9
11
  logger = logging.getLogger(LOGGER_NAME)
10
12
  VERSION = 'version'
@@ -12,7 +14,7 @@ LICENSE = 'license'
12
14
  NAME = 'name'
13
15
 
14
16
 
15
- def compare_yaml(before_fileitems, after_fileitems):
17
+ def compare_yaml(before_fileitems: List[FileItem], after_fileitems: List[FileItem]) -> Dict[str, List]:
16
18
  bf_raw = []
17
19
  af_raw = []
18
20
  for bf in before_fileitems:
@@ -35,13 +35,17 @@ SHEET_NAME_FOR_SCANNER = {
35
35
  # pub: https://pub.dev/packages/(package)/versions/(version)
36
36
  # Cocoapods : https://cocoapods.org/(package)
37
37
  # go : https://pkg.go.dev/(package_name_with_slash)@(version)
38
+ # cargo : https://crates.io/crates/(crate_name)/(version)
38
39
  PKG_PATTERN = {
39
40
  "pypi": r'https?:\/\/pypi\.org\/project\/([^\/]+)[\/]?([^\/]*)',
40
41
  "pypi2": r'https?:\/\/files\.pythonhosted\.org\/packages\/source\/[\w]\/([^\/]+)\/[\S]+-([^\-]+)\.tar\.gz',
41
42
  "maven": r'https?:\/\/mvnrepository\.com\/artifact\/([^\/]+)\/([^\/]+)\/?([^\/]*)',
43
+ "maven_repo1": r'https?:\/\/repo1\.maven\.org\/maven2\/(.*)',
44
+ "maven_google": r'https?:\/\/dl\.google\.com\/android\/maven2\/(.*)',
42
45
  "npm": r'https?:\/\/www\.npmjs\.com\/package\/([^\/\@]+)(?:\/v\/)?([^\/]*)',
43
46
  "npm2": r'https?:\/\/www\.npmjs\.com\/package\/(\@[^\/]+\/[^\/]+)(?:\/v\/)?([^\/]*)',
44
47
  "pub": r'https?:\/\/pub\.dev\/packages\/([^\/]+)(?:\/versions\/)?([^\/]*)',
45
48
  "cocoapods": r'https?:\/\/cocoapods\.org\/pods\/([^\/]+)',
46
- "go": r'https?:\/\/pkg.go.dev\/([^\@]+)\@?v?([^\/]*)'
49
+ "go": r'https?:\/\/pkg.go.dev\/([^\@]+)\@?v?([^\/]*)',
50
+ "cargo": r'https?:\/\/crates\.io\/crates\/([^\/]+)\/?([^\/]*)',
47
51
  }