Skip to content

Commit 1848685

Browse files
1 parent 7d1360e commit 1848685

13 files changed

Lines changed: 144 additions & 80 deletions

src/pysonar_scanner/api.py

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@
3232
Key,
3333
)
3434
from pysonar_scanner.exceptions import MissingKeyException, SonarQubeApiException
35-
from pysonar_scanner.utils import Arch, Os, remove_trailing_slash
35+
from pysonar_scanner.utils import remove_trailing_slash, OsStr, ArchStr
3636

3737

3838
@dataclass(frozen=True)
@@ -211,12 +211,9 @@ def download_analysis_engine(self, handle: typing.BinaryIO) -> None:
211211
except requests.RequestException as e:
212212
raise SonarQubeApiException("Error while fetching the analysis engine") from e
213213

214-
def get_analysis_jres(self, os: Optional[Os] = None, arch: Optional[Arch] = None) -> list[JRE]:
214+
def get_analysis_jres(self, os: OsStr, arch: ArchStr) -> list[JRE]:
215215
try:
216-
params = {
217-
"os": os.value if os else None,
218-
"arch": arch.value if arch else None,
219-
}
216+
params = {"os": os, "arch": arch}
220217
res = requests.get(
221218
f"{self.base_urls.api_base_url}/analysis/jres",
222219
auth=self.auth,

src/pysonar_scanner/configuration/configuration_loader.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
from pysonar_scanner.configuration.pyproject_toml import TomlConfigurationLoader
2424
from pysonar_scanner.configuration.properties import SONAR_TOKEN, SONAR_PROJECT_BASE_DIR, Key
2525
from pysonar_scanner.configuration.properties import PROPERTIES
26-
from pysonar_scanner.configuration import sonar_project_properties, environment_variables
26+
from pysonar_scanner.configuration import sonar_project_properties, environment_variables, dynamic_defaults_loader
2727

2828
from pysonar_scanner.exceptions import MissingKeyException
2929

@@ -38,6 +38,7 @@ def load() -> dict[Key, any]:
3838
# each property loader is required to return NO default values.
3939
# E.g. if no property has been set, an empty dict must be returned.
4040
# Default values should be set through the get_static_default_properties() method
41+
4142
cli_properties = CliConfigurationLoader.load()
4243
# CLI properties have a higher priority than properties file,
4344
# but we need to resolve them first to load the properties file
@@ -48,6 +49,7 @@ def load() -> dict[Key, any]:
4849
toml_properties = TomlConfigurationLoader.load(toml_dir)
4950

5051
resolved_properties = get_static_default_properties()
52+
resolved_properties.update(dynamic_defaults_loader.load())
5153
resolved_properties.update(toml_properties.project_properties)
5254
resolved_properties.update(sonar_project_properties.load(base_dir))
5355
resolved_properties.update(toml_properties.sonar_properties)
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
#
2+
# Sonar Scanner Python
3+
# Copyright (C) 2011-2024 SonarSource SA.
4+
# mailto:info AT sonarsource DOT com
5+
#
6+
# This program is free software; you can redistribute it and/or
7+
# modify it under the terms of the GNU Lesser General Public
8+
# License as published by the Free Software Foundation; either
9+
# version 3 of the License, or (at your option) any later version.
10+
# This program is distributed in the hope that it will be useful,
11+
#
12+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
13+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14+
# Lesser General Public License for more details.
15+
#
16+
# You should have received a copy of the GNU Lesser General Public License
17+
# along with this program; if not, write to the Free Software Foundation,
18+
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19+
#
20+
import os
21+
from typing import Dict
22+
23+
from pysonar_scanner.configuration.properties import Key, SONAR_SCANNER_OS, SONAR_SCANNER_ARCH, SONAR_PROJECT_BASE_DIR
24+
from pysonar_scanner import utils
25+
26+
27+
def load() -> Dict[Key, any]:
28+
"""
29+
Load dynamically computed default properties
30+
"""
31+
properties = {
32+
SONAR_SCANNER_OS: utils.get_os(),
33+
SONAR_SCANNER_ARCH: utils.get_arch(),
34+
SONAR_PROJECT_BASE_DIR: os.getcwd(),
35+
}
36+
return properties

src/pysonar_scanner/configuration/properties.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -178,7 +178,7 @@ def env_variable_name(self) -> str:
178178
),
179179
Property(
180180
name=SONAR_USER_HOME,
181-
default_value="~/.sonar",
181+
default_value=None,
182182
cli_getter=lambda args: args.sonar_user_home
183183
),
184184
Property(

src/pysonar_scanner/jre.py

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -53,9 +53,11 @@ def from_string(path: str) -> "JREResolvedPath":
5353

5454

5555
class JREProvisioner:
56-
def __init__(self, api: SonarQubeApi, cache: Cache):
56+
def __init__(self, api: SonarQubeApi, cache: Cache, sonar_scanner_os: str, sonar_scanner_arch: str):
5757
self.api = api
5858
self.cache = cache
59+
self.sonar_scanner_os = sonar_scanner_os
60+
self.sonar_scanner_arch = sonar_scanner_arch
5961

6062
def provision(self) -> JREResolvedPath:
6163
jre, resolved_path = self.__attempt_provisioning_jre_with_retry()
@@ -67,7 +69,7 @@ def __attempt_provisioning_jre_with_retry(self) -> tuple[JRE, pathlib.Path]:
6769
jre_and_resolved_path = self.__attempt_provisioning_jre()
6870
if jre_and_resolved_path is None:
6971
raise ChecksumException(
70-
f"Failed to download and verify JRE for {utils.get_os().value} and {utils.get_arch().value}"
72+
f"Failed to download and verify JRE for {self.sonar_scanner_os} and {self.sonar_scanner_arch}"
7173
)
7274

7375
return jre_and_resolved_path
@@ -83,10 +85,10 @@ def __attempt_provisioning_jre(self) -> Optional[tuple[JRE, pathlib.Path]]:
8385
return (jre, jre_path) if jre_path is not None else None
8486

8587
def __get_available_jre(self) -> JRE:
86-
jres = self.api.get_analysis_jres(os=utils.get_os(), arch=utils.get_arch())
88+
jres = self.api.get_analysis_jres(os=self.sonar_scanner_os, arch=self.sonar_scanner_arch)
8789
if len(jres) == 0:
8890
raise NoJreAvailableException(
89-
f"No JREs are available for {utils.get_os().value} and {utils.get_arch().value}"
91+
f"No JREs are available for {self.sonar_scanner_os} and {self.sonar_scanner_arch}"
9092
)
9193
return jres[0]
9294

src/pysonar_scanner/scannerengine.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131

3232
from pysonar_scanner.api import SonarQubeApi
3333
from pysonar_scanner.cache import Cache, CacheFile
34+
from pysonar_scanner.configuration.properties import SONAR_SCANNER_OS, SONAR_SCANNER_ARCH
3435
from pysonar_scanner.exceptions import ChecksumException, SQTooOldException
3536
from pysonar_scanner.jre import JREProvisioner, JREResolvedPath, JREResolver, JREResolverConfiguration
3637
from subprocess import Popen, PIPE
@@ -175,6 +176,6 @@ def __version_check(self):
175176
)
176177

177178
def __resolve_jre(self, config: dict[str, any]) -> JREResolvedPath:
178-
jre_provisionner = JREProvisioner(self.api, self.cache)
179+
jre_provisionner = JREProvisioner(self.api, self.cache, config[SONAR_SCANNER_OS], config[SONAR_SCANNER_ARCH])
179180
jre_resolver = JREResolver(JREResolverConfiguration.from_dict(config), jre_provisionner)
180181
return jre_resolver.resolve_jre()

src/pysonar_scanner/utils.py

Lines changed: 13 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,9 @@
2121
import pathlib
2222
import platform
2323
import typing
24-
from enum import Enum
24+
25+
OsStr = typing.Literal["windows", "linux", "mac", "alpine", "other"]
26+
ArchStr = typing.Literal["x86_64", "aarch64", "x86"]
2527

2628

2729
def remove_trailing_slash(url: str) -> str:
@@ -35,15 +37,7 @@ def calculate_checksum(filehandle: typing.BinaryIO) -> str:
3537
return sha256_hash.hexdigest()
3638

3739

38-
class Os(Enum):
39-
WINDOWS = "windows"
40-
LINUX = "linux"
41-
MACOS = "mac"
42-
ALPINE = "alpine"
43-
OTHER = "other"
44-
45-
46-
def get_os() -> Os:
40+
def get_os() -> OsStr:
4741
def is_alpine() -> bool:
4842
try:
4943
os_release = pathlib.Path("/etc/os-release")
@@ -58,30 +52,24 @@ def is_alpine() -> bool:
5852

5953
os_name = platform.system()
6054
if os_name == "Windows":
61-
return Os.WINDOWS
55+
return "windows"
6256
elif os_name == "Darwin":
63-
return Os.MACOS
57+
return "mac"
6458
elif os_name == "Linux":
6559
if is_alpine():
66-
return Os.ALPINE
60+
return "alpine"
6761
else:
68-
return Os.LINUX
69-
return Os.OTHER
70-
71-
72-
class Arch(Enum):
73-
X64 = "x64"
74-
AARCH64 = "aarch64"
75-
OTHER = "other"
62+
return "linux"
63+
return "other"
7664

7765

78-
def get_arch() -> Arch:
66+
def get_arch() -> ArchStr:
7967
machine = platform.machine().lower()
8068
if machine in ["amd64", "x86_64"]:
81-
return Arch.X64
69+
return "x64"
8270
elif machine == "arm64":
83-
return Arch.AARCH64
84-
return Arch.OTHER
71+
return "aarch64"
72+
return "other"
8573

8674

8775
def filter_none_values(dictionary: dict) -> dict:

tests/sq_api_utils.py

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -79,8 +79,6 @@ def mock_analysis_engine_download(self, body: bytes = b"", status: int = 200) ->
7979
def mock_analysis_jres(
8080
self,
8181
body: Optional[list[dict]] = None,
82-
os_matcher: Optional[str] = None,
83-
arch_matcher: Optional[str] = None,
8482
status: int = 200,
8583
) -> responses.BaseResponse:
8684
return self.rsps.get(
@@ -89,7 +87,6 @@ def mock_analysis_jres(
8987
status=status,
9088
match=[
9189
matchers.header_matcher({"Accept": "application/json"}),
92-
matchers.query_param_matcher(utils.filter_none_values({"os": os_matcher, "arch": arch_matcher})),
9390
],
9491
)
9592

tests/test_api.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -320,7 +320,7 @@ def test_get_analysis_jres(self):
320320
with self.subTest("get_analysis_jres works"), sq_api_mocker() as mocker:
321321
mocker.mock_analysis_jres([sq_api_utils.jre_to_dict(jre) for jre in expected_jres])
322322

323-
actual_jres = self.sq.get_analysis_jres()
323+
actual_jres = self.sq.get_analysis_jres(os="linux", arch="x86_64")
324324
self.assertEqual(actual_jres, expected_jres)
325325

326326
with (
@@ -329,15 +329,15 @@ def test_get_analysis_jres(self):
329329
self.assertRaises(SonarQubeApiException),
330330
):
331331
mocker.mock_analysis_jres(status=404)
332-
self.sq.get_analysis_jres()
332+
self.sq.get_analysis_jres(os="linux", arch="x86_64")
333333

334334
with (
335335
self.subTest("get_analysis_jres returns error when keys are missing"),
336336
sq_api_mocker() as mocker,
337337
self.assertRaises(SonarQubeApiException),
338338
):
339339
mocker.mock_analysis_jres([{"id": "jre1"}])
340-
self.sq.get_analysis_jres()
340+
self.sq.get_analysis_jres(os="linux", arch="x86_64")
341341

342342
def test_download_analysis_jre(self):
343343
jre_id = "jre1"

0 commit comments

Comments
 (0)