Skip to content

Commit 0378c00

Browse files
SCANPY-145 Dynamically infer the OS and Architecture properties (#173)
1 parent 7dadf89 commit 0378c00

File tree

11 files changed

+161
-85
lines changed

11 files changed

+161
-85
lines changed

src/pysonar_scanner/__main__.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@
3030
SONAR_SCANNER_SONARCLOUD_URL,
3131
SONAR_SCANNER_PROXY_PORT,
3232
SONAR_SCANNER_JAVA_EXE_PATH,
33+
SONAR_SCANNER_OS,
34+
SONAR_SCANNER_ARCH,
3335
)
3436
from pysonar_scanner.exceptions import SQTooOldException
3537
from pysonar_scanner.jre import JREResolvedPath, JREProvisioner, JREResolver, JREResolverConfiguration
@@ -89,6 +91,6 @@ def create_scanner_engine(api, cache_manager, config):
8991

9092

9193
def create_jre(api, cache, config: dict[str, any]) -> JREResolvedPath:
92-
jre_provisioner = JREProvisioner(api, cache)
94+
jre_provisioner = JREProvisioner(api, cache, config[SONAR_SCANNER_OS], config[SONAR_SCANNER_ARCH])
9395
jre_resolver = JREResolver(JREResolverConfiguration.from_dict(config), jre_provisioner)
9496
return jre_resolver.resolve_jre()

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, InconsistentConfiguration
35-
from pysonar_scanner.utils import Arch, Os, remove_trailing_slash
35+
from pysonar_scanner.utils import remove_trailing_slash, OsStr, ArchStr
3636

3737
GLOBAL_SONARCLOUD_URL = "https://sonarcloud.io"
3838
US_SONARCLOUD_URL = "https://sonarqube.us"
@@ -231,12 +231,9 @@ def download_analysis_engine(self, handle: typing.BinaryIO) -> None:
231231
except requests.RequestException as e:
232232
raise SonarQubeApiException("Error while fetching the analysis engine") from e
233233

234-
def get_analysis_jres(self, os: Optional[Os] = None, arch: Optional[Arch] = None) -> list[JRE]:
234+
def get_analysis_jres(self, os: OsStr, arch: ArchStr) -> list[JRE]:
235235
try:
236-
params = {
237-
"os": os.value if os else None,
238-
"arch": arch.value if arch else None,
239-
}
236+
params = {"os": os, "arch": arch}
240237
res = requests.get(
241238
f"{self.base_urls.api_base_url}/analysis/jres",
242239
auth=self.auth,

src/pysonar_scanner/configuration/configuration_loader.py

Lines changed: 2 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

@@ -48,6 +48,7 @@ def load() -> dict[Key, any]:
4848
toml_properties = TomlConfigurationLoader.load(toml_dir)
4949

5050
resolved_properties = get_static_default_properties()
51+
resolved_properties.update(dynamic_defaults_loader.load())
5152
resolved_properties.update(toml_properties.project_properties)
5253
resolved_properties.update(sonar_project_properties.load(base_dir))
5354
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().value,
33+
SONAR_SCANNER_ARCH: utils.get_arch().value,
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
@@ -206,7 +206,7 @@ def env_variable_name(self) -> str:
206206
),
207207
Property(
208208
name=SONAR_USER_HOME,
209-
default_value="~/.sonar",
209+
default_value=None,
210210
cli_getter=lambda args: args.sonar_user_home
211211
),
212212
Property(

src/pysonar_scanner/jre.py

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

5555

5656
class JREProvisioner:
57-
def __init__(self, api: SonarQubeApi, cache: Cache):
57+
def __init__(self, api: SonarQubeApi, cache: Cache, sonar_scanner_os: str, sonar_scanner_arch: str):
5858
self.api = api
5959
self.cache = cache
60+
self.sonar_scanner_os = sonar_scanner_os
61+
self.sonar_scanner_arch = sonar_scanner_arch
6062

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

7476
return jre_and_resolved_path
@@ -84,10 +86,10 @@ def __attempt_provisioning_jre(self) -> Optional[tuple[JRE, pathlib.Path]]:
8486
return (jre, jre_path) if jre_path is not None else None
8587

8688
def __get_available_jre(self) -> JRE:
87-
jres = self.api.get_analysis_jres(os=utils.get_os(), arch=utils.get_arch())
89+
jres = self.api.get_analysis_jres(os=self.sonar_scanner_os, arch=self.sonar_scanner_arch)
8890
if len(jres) == 0:
8991
raise NoJreAvailableException(
90-
f"No JREs are available for {utils.get_os().value} and {utils.get_arch().value}"
92+
f"No JREs are available for {self.sonar_scanner_os} and {self.sonar_scanner_arch}"
9193
)
9294
return jres[0]
9395

src/pysonar_scanner/utils.py

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,9 @@
2323
import typing
2424
from enum import Enum
2525

26+
OsStr = typing.Literal["windows", "linux", "mac", "alpine", "other"]
27+
ArchStr = typing.Literal["x64", "aarch64", "other"]
28+
2629

2730
def remove_trailing_slash(url: str) -> str:
2831
return url.rstrip("/ ").lstrip()
@@ -36,11 +39,11 @@ def calculate_checksum(filehandle: typing.BinaryIO) -> str:
3639

3740

3841
class Os(Enum):
39-
WINDOWS = "windows"
40-
LINUX = "linux"
41-
MACOS = "mac"
42-
ALPINE = "alpine"
43-
OTHER = "other"
42+
WINDOWS: OsStr = "windows"
43+
LINUX: OsStr = "linux"
44+
MACOS: OsStr = "mac"
45+
ALPINE: OsStr = "alpine"
46+
OTHER: OsStr = "other"
4447

4548

4649
def get_os() -> Os:
@@ -70,9 +73,9 @@ def is_alpine() -> bool:
7073

7174

7275
class Arch(Enum):
73-
X64 = "x64"
74-
AARCH64 = "aarch64"
75-
OTHER = "other"
76+
X64: ArchStr = "x64"
77+
AARCH64: ArchStr = "aarch64"
78+
OTHER: ArchStr = "other"
7679

7780

7881
def get_arch() -> Arch:

tests/unit/sq_api_utils.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -80,9 +80,9 @@ def mock_analysis_engine_download(self, body: bytes = b"", status: int = 200) ->
8080
def mock_analysis_jres(
8181
self,
8282
body: Optional[list[dict]] = None,
83-
os_matcher: Optional[str] = None,
84-
arch_matcher: Optional[str] = None,
8583
status: int = 200,
84+
os_matcher: Optional[str] = "linux",
85+
arch_matcher: Optional[str] = "x64",
8686
) -> responses.BaseResponse:
8787
return self.rsps.get(
8888
url=f"{self.api_url}/analysis/jres",

tests/unit/test_api.py

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -364,10 +364,17 @@ def test_get_analysis_jres(self):
364364
),
365365
]
366366

367-
with self.subTest("get_analysis_jres works"), sq_api_mocker() as mocker:
367+
with self.subTest("get_analysis_jres works (linux)"), sq_api_mocker() as mocker:
368368
mocker.mock_analysis_jres([sq_api_utils.jre_to_dict(jre) for jre in expected_jres])
369369

370-
actual_jres = self.sq.get_analysis_jres()
370+
actual_jres = self.sq.get_analysis_jres(os="linux", arch="x64")
371+
self.assertEqual(actual_jres, expected_jres)
372+
373+
with self.subTest("get_analysis_jres works (windows)"), sq_api_mocker() as mocker:
374+
mocker.mock_analysis_jres(
375+
[sq_api_utils.jre_to_dict(jre) for jre in expected_jres], os_matcher="windows", arch_matcher="aarch64"
376+
)
377+
actual_jres = self.sq.get_analysis_jres(os="windows", arch="aarch64")
371378
self.assertEqual(actual_jres, expected_jres)
372379

373380
with (
@@ -376,15 +383,15 @@ def test_get_analysis_jres(self):
376383
self.assertRaises(SonarQubeApiException),
377384
):
378385
mocker.mock_analysis_jres(status=404)
379-
self.sq.get_analysis_jres()
386+
self.sq.get_analysis_jres(os="linux", arch="x64")
380387

381388
with (
382389
self.subTest("get_analysis_jres returns error when keys are missing"),
383390
sq_api_mocker() as mocker,
384391
self.assertRaises(SonarQubeApiException),
385392
):
386393
mocker.mock_analysis_jres([{"id": "jre1"}])
387-
self.sq.get_analysis_jres()
394+
self.sq.get_analysis_jres(os="linux", arch="x64")
388395

389396
def test_download_analysis_jre(self):
390397
jre_id = "jre1"

0 commit comments

Comments
 (0)