ScriptCollection 4.2.59__py3-none-any.whl → 4.2.60__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.
@@ -36,10 +36,10 @@ class VersionEcholon(Enum):
36
36
  LatestVersion = 3
37
37
 
38
38
  class Platform(Enum):
39
- WindowsAMD64 = 0
40
- LinuxAMD64 = 1
41
- LinuxARM64 = 2
42
- MacOSARM64 = 3
39
+ Windows_AMD64 = 0
40
+ Linux_AMD64 = 1
41
+ Linux_ARM64 = 2
42
+ MacOS_ARM64 = 3
43
43
 
44
44
 
45
45
  class Dependency:
@@ -1444,13 +1444,13 @@ class GeneralUtilities:
1444
1444
  machine = platform.machine().lower()
1445
1445
 
1446
1446
  if system == "windows" and machine in ("x86_64", "amd64"):
1447
- return Platform.WindowsAMD64
1447
+ return Platform.Windows_AMD64
1448
1448
  elif system == "linux" and machine in ("x86_64", "amd64"):
1449
- return Platform.LinuxAMD64
1449
+ return Platform.Linux_AMD64
1450
1450
  elif system == "linux" and machine in ("arm64", "aarch64"):
1451
- return Platform.LinuxARM64
1451
+ return Platform.Linux_ARM64
1452
1452
  elif system == "darwin" and machine in ("x86_64", "amd64"):
1453
- return Platform.MacOSARM64
1453
+ return Platform.MacOS_ARM64
1454
1454
  else:
1455
1455
  raise ValueError(f"Unsupported platform: {system}/{machine}")
1456
1456
 
@@ -1458,10 +1458,10 @@ class GeneralUtilities:
1458
1458
  @check_arguments
1459
1459
  def platform_to_short_str(platform_value: Platform) -> str:
1460
1460
  mapping = {
1461
- Platform.WindowsAMD64: "win-x64",
1462
- Platform.LinuxAMD64: "linux-x64",
1463
- Platform.LinuxARM64: "linux-arm64",
1464
- Platform.MacOSARM64: "osx-arm64",
1461
+ Platform.Windows_AMD64: "win-x64",
1462
+ Platform.Linux_AMD64: "linux-x64",
1463
+ Platform.Linux_ARM64: "linux-arm64",
1464
+ Platform.MacOS_ARM64: "osx-arm64",
1465
1465
  }
1466
1466
  return mapping[platform_value]
1467
1467
 
@@ -1469,10 +1469,10 @@ class GeneralUtilities:
1469
1469
  @check_arguments
1470
1470
  def platform_from_short_str(platform_str: str) -> Platform:
1471
1471
  mapping = {
1472
- "win-x64": Platform.WindowsAMD64,
1473
- "linux-x64": Platform.LinuxAMD64,
1474
- "linux-arm64": Platform.LinuxARM64,
1475
- "osx-arm64": Platform.MacOSARM64,
1472
+ "win-x64": Platform.Windows_AMD64,
1473
+ "linux-x64": Platform.Linux_AMD64,
1474
+ "linux-arm64": Platform.Linux_ARM64,
1475
+ "osx-arm64": Platform.MacOS_ARM64,
1476
1476
  }
1477
1477
  if platform_str not in mapping:
1478
1478
  raise ValueError(f"Unsupported platform string: {platform_str}")
@@ -1482,10 +1482,10 @@ class GeneralUtilities:
1482
1482
  @check_arguments
1483
1483
  def platform_to_dash_str(platform_value: Platform) -> str:
1484
1484
  mapping = {
1485
- Platform.WindowsAMD64: "Windows-x64",
1486
- Platform.LinuxAMD64: "Linux-x64",
1487
- Platform.LinuxARM64: "Linux-arm64",
1488
- Platform.MacOSARM64: "MacOS-arm64",
1485
+ Platform.Windows_AMD64: "Windows-x64",
1486
+ Platform.Linux_AMD64: "Linux-x64",
1487
+ Platform.Linux_ARM64: "Linux-arm64",
1488
+ Platform.MacOS_ARM64: "MacOS-arm64",
1489
1489
  }
1490
1490
  return mapping[platform_value]
1491
1491
 
@@ -1493,10 +1493,10 @@ class GeneralUtilities:
1493
1493
  @check_arguments
1494
1494
  def platform_from_dash_str(platform_str: str) -> Platform:
1495
1495
  mapping = {
1496
- "Windows-x64": Platform.WindowsAMD64,
1497
- "Linux-x64": Platform.LinuxAMD64,
1498
- "Linux-arm64": Platform.LinuxARM64,
1499
- "MacOS-arm64": Platform.MacOSARM64,
1496
+ "Windows-x64": Platform.Windows_AMD64,
1497
+ "Linux-x64": Platform.Linux_AMD64,
1498
+ "Linux-arm64": Platform.Linux_ARM64,
1499
+ "MacOS-arm64": Platform.MacOS_ARM64,
1500
1500
  }
1501
1501
  if platform_str not in mapping:
1502
1502
  raise ValueError(f"Unsupported platform string: {platform_str}")
@@ -1506,10 +1506,10 @@ class GeneralUtilities:
1506
1506
  @check_arguments
1507
1507
  def platform_to_docker_platform_str(platform_value: Platform) -> str:
1508
1508
  mapping = {
1509
- Platform.WindowsAMD64: "windows/amd64",
1510
- Platform.LinuxAMD64: "linux/amd64",
1511
- Platform.LinuxARM64: "linux/arm64",
1512
- Platform.MacOSARM64: "linux/arm64", # macOS → linux container
1509
+ Platform.Windows_AMD64: "windows/amd64",
1510
+ Platform.Linux_AMD64: "linux/amd64",
1511
+ Platform.Linux_ARM64: "linux/arm64",
1512
+ Platform.MacOS_ARM64: "linux/arm64", # macOS → linux container
1513
1513
  }
1514
1514
  return mapping[platform_value]
1515
1515
 
@@ -1517,10 +1517,10 @@ class GeneralUtilities:
1517
1517
  @check_arguments
1518
1518
  def platform_to_dotnet_runtime_identifier(platform_value: Platform) -> str:
1519
1519
  mapping = {
1520
- Platform.WindowsAMD64: "win-x64",
1521
- Platform.LinuxAMD64: "linux-x64",
1522
- Platform.LinuxARM64: "linux-arm64",
1523
- Platform.MacOSARM64: "osx-arm64",
1520
+ Platform.Windows_AMD64: "win-x64",
1521
+ Platform.Linux_AMD64: "linux-x64",
1522
+ Platform.Linux_ARM64: "linux-arm64",
1523
+ Platform.MacOS_ARM64: "osx-arm64",
1524
1524
  }
1525
1525
  return mapping[platform_value]
1526
1526
 
@@ -1528,9 +1528,9 @@ class GeneralUtilities:
1528
1528
  @check_arguments
1529
1529
  def get_all_platforms() -> list[Platform]:
1530
1530
  return [
1531
- Platform.WindowsAMD64,
1532
- Platform.LinuxAMD64,
1533
- Platform.LinuxARM64,
1534
- Platform.MacOSARM64,
1531
+ Platform.Windows_AMD64,
1532
+ Platform.Linux_AMD64,
1533
+ Platform.Linux_ARM64,
1534
+ Platform.MacOS_ARM64,
1535
1535
  ]
1536
1536
 
@@ -36,7 +36,7 @@ from .ProgramRunnerBase import ProgramRunnerBase
36
36
  from .ProgramRunnerPopen import ProgramRunnerPopen
37
37
  from .SCLog import SCLog, LogLevel
38
38
 
39
- version = "4.2.59"
39
+ version = "4.2.60"
40
40
  __version__ = version
41
41
 
42
42
  class VSCodeWorkspaceShellTask:
@@ -215,22 +215,30 @@ class ScriptCollectionCore:
215
215
 
216
216
  def registry_contains_image(self,registry_url:str,image:str,registry_username:str,registry_password:str)->bool:
217
217
  """This function assumes that the registry is a custom deployed docker-registry (see https://hub.docker.com/_/registry )"""
218
- if "/" in image:
219
- image=image.rsplit("/", 1)[-1]
220
- registry_username,registry_password=self.__load_credentials_if_required_and_available(registry_url,registry_username,registry_password)
221
- catalog_url = f"{registry_url}/v2/_catalog"
222
- response = requests.get(catalog_url, auth=(registry_username, registry_password),timeout=20)
223
- response.raise_for_status() # check if statuscode = 200
224
- data = response.json()
225
- # expected: {"repositories": ["nginx", "myapp"]}
226
- images = data.get("repositories", [])
227
- result=image in images
228
- return result
218
+ try:
219
+ if "/" in image:
220
+ image=image.rsplit("/", 1)[-1]
221
+ registry_username,registry_password=self.__load_credentials_if_required_and_available(registry_url,registry_username,registry_password)
222
+ catalog_url = f"{registry_url}/v2/_catalog"
223
+ response = requests.get(catalog_url, auth=(registry_username, registry_password),timeout=20)
224
+ response.raise_for_status() # check if statuscode = 200
225
+ data = response.json()
226
+ # expected: {"repositories": ["nginx", "myapp"]}
227
+ images = data.get("repositories", [])
228
+ if not (image in images):
229
+ return False
230
+
231
+ if self.get_tags_of_images_from_registry(registry_url,image,registry_username,registry_password)<1:
232
+ return False
233
+
234
+ return True
235
+ except Exception:
236
+ return False
229
237
 
230
238
  def docker_platform_to_slug(self,platform_value: Platform) -> str:
231
- if platform_value == Platform.LinuxAMD64:
239
+ if platform_value == Platform.Linux_AMD64:
232
240
  return "linux-amd64"
233
- elif platform_value == Platform.LinuxARM64:
241
+ elif platform_value == Platform.Linux_ARM64:
234
242
  return "linux-arm64"
235
243
  raise ValueError(f"Unsupported platform: {platform_value}")
236
244
 
@@ -3234,3 +3242,22 @@ OCR-content:
3234
3242
  files=self.get_all_files_in_git_repository(repository_folder,ignore_ignored_files,include_submodules)
3235
3243
  GeneralUtilities.ensure_file_exists(target_file)
3236
3244
  GeneralUtilities.write_lines_to_file(target_file, files)
3245
+
3246
+ @GeneralUtilities.check_arguments
3247
+ def get_all_commits_in_git_repository(self,repository_folder:str,include_all_heads:bool=False) -> list[str]:
3248
+ """Returns a textual visualization of all commits in a git-repository."""
3249
+ #do 'git log --reverse --all --pretty=format:"%ci | %H | %cn <%ce> | %s"'
3250
+ args = ["log", "--reverse", "--pretty=format:%ci | %H | %cn <%ce> | %s"]
3251
+ if include_all_heads:
3252
+ args.append("--all")
3253
+ result=self.run_program_argsasarray("git", args, repository_folder, throw_exception_if_exitcode_is_not_zero=True)
3254
+ return result[1]
3255
+
3256
+ @GeneralUtilities.check_arguments
3257
+ def write_commit_list_for_repository(self,repository_folder:str,target_file:str,include_all_heads:bool=False) -> None:
3258
+ if os.path.isabs(target_file):
3259
+ target_file=GeneralUtilities.resolve_relative_path(target_file,repository_folder)
3260
+ target_file=GeneralUtilities.normalize_path(target_file)
3261
+ commits=self.get_all_commits_in_git_repository(repository_folder, include_all_heads)
3262
+ GeneralUtilities.ensure_file_exists(target_file)
3263
+ GeneralUtilities.write_lines_to_file(target_file, commits)
@@ -23,22 +23,22 @@ class TFCPS_CodeUnitSpecific_Docker_Functions(TFCPS_CodeUnitSpecific_Base):
23
23
  codeunitversion = self.tfcps_Tools_General.get_version_of_codeunit(codeunit_file)
24
24
  if custom_arguments is None:
25
25
  custom_arguments=dict[str,str]()
26
+ artifacts_folder = GeneralUtilities.resolve_relative_path("Other/Artifacts", codeunit_folder)
27
+ app_artifacts_folder = os.path.join(artifacts_folder, "BuildResult_OCIImage")
28
+ GeneralUtilities.ensure_folder_exists_and_is_empty(app_artifacts_folder)
26
29
  for platform in platforms:
27
30
  #builder must be created once before with "docker buildx create --use"
28
- args = ["buildx","build", "--platform",GeneralUtilities.platform_to_docker_platform_str(platform), "--pull", "--force-rm", "--progress=plain", "--build-arg", f"TargetEnvironmentType={self.get_target_environment_type()}", "--build-arg", f"CodeUnitName={codeunitname}", "--build-arg", f"CodeUnitVersion={codeunitversion}", "--build-arg", f"CodeUnitOwnerName={self.tfcps_Tools_General.get_codeunit_owner_name(self.get_codeunit_file())}", "--build-arg", f"CodeUnitOwnerEMailAddress={self.tfcps_Tools_General.get_codeunit_owner_emailaddress(self.get_codeunit_file())}"]
31
+ args = ["buildx","build", "--platform",GeneralUtilities.platform_to_docker_platform_str(platform), "--pull", "--force-rm", "--progress=plain", "--build-arg", f"TargetEnvironmentType={self.get_target_environment_type()}", "--build-arg", f"CodeUnitName={codeunitname}", "--build-arg", f"CodeUnitVersion={codeunitversion}", "--build-arg", f"CodeUnitOwnerName={self.tfcps_Tools_General.get_codeunit_owner_name(self.get_codeunit_file())}", "--build-arg", f"CodeUnitOwnerEMailAddress={self.tfcps_Tools_General.get_codeunit_owner_emailaddress(self.get_codeunit_file())}", "--build-arg", f"Platform={GeneralUtilities.platform_to_dash_str(platform)}", "--build-arg", f"DotNetRuntime={GeneralUtilities.platform_to_dotnet_runtime_identifier(platform)}"]
29
32
  for custom_argument_key, custom_argument_value in custom_arguments.items():
30
33
  args.append("--build-arg")
31
34
  args.append(f"{custom_argument_key}={custom_argument_value}")
32
35
  args = args+["--tag", f"{codeunitname_lower}:latest", "--tag", f"{codeunitname_lower}:{codeunitversion}", "--file", f"{codeunitname}/Dockerfile"]
33
36
  if not self.use_cache():
34
37
  args.append("--no-cache")
38
+ args.append("--load")
35
39
  args.append(".")
36
- codeunit_content_folder = os.path.join(codeunit_folder)
40
+ codeunit_content_folder = codeunit_folder
37
41
  GeneralUtilities.retry_action(lambda a=args, f=codeunit_content_folder: self._protected_sc.run_program_argsasarray("docker", a, f, print_errors_as_information=True), 3)
38
- artifacts_folder = GeneralUtilities.resolve_relative_path("Other/Artifacts", codeunit_folder)
39
- app_artifacts_folder = os.path.join(artifacts_folder, "BuildResult_OCIImage")
40
- GeneralUtilities.ensure_directory_does_not_exist(app_artifacts_folder)
41
- GeneralUtilities.ensure_directory_exists(app_artifacts_folder)
42
42
 
43
43
  self._protected_sc.run_program_argsasarray("docker", ["save", "--output", f"{codeunitname}_v{codeunitversion}_{GeneralUtilities.platform_to_dash_str(platform)}.tar", f"{codeunitname_lower}:{codeunitversion}"], app_artifacts_folder, print_errors_as_information=True)
44
44
  self.__generate_sbom_for_docker_image()
@@ -98,10 +98,21 @@ class TFCPS_CodeUnitSpecific_Docker_Functions(TFCPS_CodeUnitSpecific_Base):
98
98
  if environment_variables is None:
99
99
  environment_variables={}
100
100
  current_platform = GeneralUtilities.get_current_platform()
101
+ platform_for_test:Platform=None
102
+ if current_platform == Platform.Windows_AMD64:
103
+ platform_for_test=Platform.Linux_AMD64
104
+ elif current_platform == Platform.Linux_AMD64:
105
+ platform_for_test=Platform.Linux_AMD64
106
+ elif current_platform == Platform.Linux_ARM64:
107
+ platform_for_test=Platform.Linux_ARM64
108
+ elif current_platform == Platform.MacOS_ARM64:
109
+ platform_for_test=Platform.Linux_ARM64
110
+ else:
111
+ raise ValueError(f"Current platform {current_platform} is not supported for testing.")
101
112
  oci_image_artifacts_folder :str= GeneralUtilities.resolve_relative_path("Other/Artifacts/BuildResult_OCIImage", self.get_codeunit_folder())
102
113
  container_name:str=f"{self.get_codeunit_name()}finaltest".lower()
103
114
  self.tfcps_Tools_General.ensure_containers_are_not_running([container_name])
104
- self.tfcps_Tools_General.load_docker_image(oci_image_artifacts_folder,current_platform)
115
+ self.tfcps_Tools_General.load_docker_image(oci_image_artifacts_folder,platform_for_test)
105
116
  codeunit_file:str=os.path.join(self.get_codeunit_folder(),f"{self.get_codeunit_name()}.codeunit.xml")
106
117
  image=f"{self.get_codeunit_name()}:{self.tfcps_Tools_General.get_version_of_codeunit(codeunit_file)}".lower()
107
118
  argument=f"run -d --name {container_name}"
@@ -650,13 +650,13 @@ class TFCPS_Tools_General:
650
650
  if update:
651
651
  platform_str:str=None
652
652
  match architecture:
653
- case Platform.WindowsAMD64:
653
+ case Platform.Windows_AMD64:
654
654
  platform_str = "windows_amd64"
655
- case Platform.LinuxARM64:
655
+ case Platform.Linux_ARM64:
656
656
  platform_str = "linux_arm64"
657
- case Platform.LinuxAMD64:
657
+ case Platform.Linux_AMD64:
658
658
  platform_str = "linux_amd64"
659
- case Platform.MacOSARM64:
659
+ case Platform.MacOS_ARM64:
660
660
  platform_str = "darwin_arm64"
661
661
  case _:
662
662
  raise ValueError(f"Unknown platform: {str(architecture)}")
@@ -678,10 +678,10 @@ class TFCPS_Tools_General:
678
678
  else:
679
679
  raise ValueError(f"Unknown extension: \"{extension}\"")
680
680
 
681
- download_and_extract("Windows", "windows", "zip",Platform.WindowsAMD64)
682
- download_and_extract("Linux", "linux", "tar.gz",Platform.LinuxAMD64)
683
- download_and_extract("Linux", "linux", "tar.gz",Platform.LinuxARM64)
684
- download_and_extract("MacOS", "darwin", "tar.gz",Platform.MacOSARM64)
681
+ download_and_extract("Windows", "windows", "zip",Platform.Windows_AMD64)
682
+ download_and_extract("Linux", "linux", "tar.gz",Platform.Linux_AMD64)
683
+ download_and_extract("Linux", "linux", "tar.gz",Platform.Linux_ARM64)
684
+ download_and_extract("MacOS", "darwin", "tar.gz",Platform.MacOS_ARM64)
685
685
 
686
686
  @GeneralUtilities.check_arguments
687
687
  def clone_repository_as_resource(self, local_repository_folder: str, remote_repository_link: str, resource_name: str, repository_subname: str = None,use_cache:bool=True) -> None:
@@ -1161,7 +1161,7 @@ class TFCPS_Tools_General:
1161
1161
  GeneralUtilities.write_text_to_file(version_file, latest_version_function)
1162
1162
 
1163
1163
  @GeneralUtilities.check_arguments
1164
- def push_docker_build_artifact(self, push_artifacts_file: str, registry: str, push_readme: bool, repository_folder_name: str, remote_image_name: str = None,default_platform:Platform=None) -> None:
1164
+ def push_docker_build_artifact(self, push_artifacts_file: str, registry: str, push_readme: bool, repository_folder_name: str, remote_image_name: str = None) -> None:
1165
1165
  folder_of_this_file = os.path.dirname(push_artifacts_file)
1166
1166
  filename = os.path.basename(push_artifacts_file)
1167
1167
  codeunitname_regex: str = "([a-zA-Z0-9]+)"
@@ -1169,8 +1169,7 @@ class TFCPS_Tools_General:
1169
1169
  if match := re.search(filename_regex, filename, re.IGNORECASE):
1170
1170
  codeunitname = match.group(1)
1171
1171
  else:
1172
- raise ValueError(f"Expected push-artifacts-file to match the regex \"{filename_regex}\" where \"{codeunitname_regex}\" represents the codeunit-name.")
1173
-
1172
+ raise ValueError(f"Expected push-artifacts-file to match the regex \"{filename_regex}\" where \"{codeunitname_regex}\" represents the codeunit-name.")
1174
1173
  repository_folder = GeneralUtilities.resolve_relative_path(f"..{os.path.sep}..{os.path.sep}Submodules{os.path.sep}{repository_folder_name}", folder_of_this_file)
1175
1174
  codeunit_folder = os.path.join(repository_folder, codeunitname)
1176
1175
  artifacts_folder = os.path.join(repository_folder,codeunitname, "Other", "Artifacts")
@@ -1178,40 +1177,78 @@ class TFCPS_Tools_General:
1178
1177
  codeunit_version = self.get_version_of_codeunit(os.path.join(codeunit_folder, f"{codeunitname}.codeunit.xml"))
1179
1178
  if remote_image_name is None:
1180
1179
  remote_image_name = codeunitname
1180
+ tar_files=[f for f in GeneralUtilities.get_direct_files_of_folder(applicationimage_folder) if f.endswith(".tar")]
1181
+ target_image_address=f"{registry}/{remote_image_name}"
1182
+ tar_files_with_platforms: list[tuple[str, str, str]] = []
1183
+ for tar_file in tar_files:
1184
+ filename=os.path.basename(tar_file)#filename looks like "{codeunitname}_v{codeunitversion}_{GeneralUtilities.platform_to_dash_str(platform)}.tar"
1185
+ platform:Platform=self.platform_from_filename(filename)#GeneralUtilities.platform_from_dash_str( filename.split("_")[-1].split(".")[0])
1186
+ platform_os_in_docker_format :str = None
1187
+ platform_arch_in_docker_format :str = None
1188
+ if platform==Platform.Windows_AMD64:
1189
+ raise NotImplementedError("Building docker images for Windows is not implemented yet.")
1190
+ elif platform==Platform.Linux_AMD64:
1191
+ platform_os_in_docker_format = "linux"
1192
+ platform_arch_in_docker_format = "amd64"
1193
+ elif platform==Platform.Linux_ARM64:
1194
+ platform_os_in_docker_format = "linux"
1195
+ platform_arch_in_docker_format = "arm64"
1196
+ elif platform==Platform.MacOS_ARM64:
1197
+ raise NotImplementedError("Building docker images for MacOS is not implemented yet.")
1198
+ else:
1199
+ raise ValueError(f"Unsupported platform {platform} extracted from filename {filename}.")
1200
+ tar_files_with_platforms.append((tar_file, platform_os_in_docker_format, platform_arch_in_docker_format))
1201
+ self.push_docker_build_artifact_as_multi_arch_artifact(tar_files_with_platforms,target_image_address, "v"+codeunit_version)
1202
+ self.push_docker_build_artifact_as_multi_arch_artifact(tar_files_with_platforms,target_image_address, "latest")
1203
+ if push_readme:
1204
+ self.__sc.run_program_with_retry("docker-pushrm", target_image_address, codeunit_folder)
1205
+
1206
+ def push_docker_build_artifact_as_multi_arch_artifact(self,tar_files: list[tuple[str, str, str]], image_address: str, tag: str):
1207
+ """
1208
+ tar_files: list of (tar_path, os, arch) tuples
1209
+ for example [
1210
+ ("MyApp.Linux.arm64.tar", "linux", "arm64"),
1211
+ ("MyApp.Linux.amd64.tar", "linux", "amd64")
1212
+ ]
1213
+ image_address for example: "myregistry.example.com/myapp"
1214
+ tag for example: "1.0.0"
1215
+ """
1216
+ arch_tags = []
1217
+
1218
+ for tar_path, os_name, arch in tar_files:
1219
+ arch_tag = f"{image_address}:{tag}-{os_name}-{arch}"
1220
+ arch_tags.append(arch_tag)
1221
+
1222
+ # Load tar → local image
1223
+ print(f"Loading {tar_path}...")
1224
+ result = self.__sc.run_program_argsasarray("docker",[ "load", "-i", tar_path], capture_output=True)
1225
+ # docker load outputs: "Loaded image: sha256:abc123..." or "Loaded image ID: ..."
1226
+ # we need the loaded image ID
1227
+ loaded_id = None
1228
+ for line in GeneralUtilities.string_to_lines(result[1]):
1229
+ if "Loaded image" in line:
1230
+ loaded_id = line.split(":", 1)[1].strip()
1231
+ break
1232
+
1233
+ if not loaded_id:
1234
+ raise RuntimeError(f"Could not determine loaded image from output: \"{result[1]}\"")
1235
+
1236
+ # Retag + push
1237
+ self.__sc.run_program_argsasarray("docker",[ "tag", loaded_id, arch_tag])
1238
+ self.__sc.run_program_argsasarray("docker",[ "push", arch_tag])
1239
+
1240
+ # Create multi-arch manifest
1241
+ final_tag = f"{image_address}:{tag}"
1242
+ self.__sc.run_program_argsasarray("docker", [ "buildx", "imagetools", "create", "--tag", final_tag] + arch_tags)
1181
1243
 
1182
- def push_image(tar_file:str,tag:str,remote_image_name:str):
1183
- GeneralUtilities.assert_condition(tag==tag.lower(), f"Tag \"{tag}\" must be in lower-case.")
1184
- remote_image_name = remote_image_name.lower()
1185
- local_image_name = codeunitname.lower()
1186
- remote_repo = f"{registry}/{remote_image_name}"
1187
- remote_image_version = f"{remote_repo}:{tag}"
1188
- self.__sc.log.log("Load image...")
1189
- self.__sc.run_program("docker", f"load --input {tar_file}", applicationimage_folder)
1190
- self.__sc.log.log("Tag image...")
1191
- self.__sc.run_program_with_retry("docker", f"tag {local_image_name}:{tag} {remote_image_version}")
1192
- self.__sc.log.log("Push image...")
1193
- self.__sc.run_program_with_retry("docker", f"push {remote_image_version}")
1194
- if push_readme:
1195
- self.__sc.run_program_with_retry("docker-pushrm", f"{remote_repo}", codeunit_folder)
1196
-
1197
- default_tar_image_file:str=None
1198
- for image_file in GeneralUtilities.get_direct_files_of_folder(applicationimage_folder):
1199
- image_filename = os.path.basename(image_file)
1200
- platform:Platform=self.platform_from_filename(image_filename)
1201
- tag=codeunit_version+"-"+GeneralUtilities.platform_to_short_str(platform).lower()
1202
- if platform == default_platform:
1203
- default_tar_image_file:str=image_file
1204
- push_image(image_file,tag,remote_image_name)
1205
- if default_tar_image_file is not None:
1206
- push_image(default_tar_image_file,"latest",remote_image_name)
1207
- push_image(default_tar_image_file,codeunit_version,remote_image_name)
1208
1244
 
1209
1245
  @GeneralUtilities.check_arguments
1210
1246
  def platform_from_filename(self,filename: str) -> Platform:
1211
1247
  match = re.search(r'_([^_]+)\.tar', filename)
1212
- if not match:
1213
- raise ValueError(f"Cannot extract platform from filename: {filename}")
1214
- return GeneralUtilities.platform_from_dash_str(match.group(1))
1248
+ if match:
1249
+ return GeneralUtilities.platform_from_dash_str(match.group(1))
1250
+ else:
1251
+ raise ValueError(f"Cannot extract platform from filename: \"{filename}\"")
1215
1252
 
1216
1253
  def prepare_building_codeunits(self,repository_folder:str,use_cache:bool,generate_development_certificate:bool):
1217
1254
  if generate_development_certificate:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ScriptCollection
3
- Version: 4.2.59
3
+ Version: 4.2.60
4
4
  Summary: The ScriptCollection is the place for reusable scripts.
5
5
  Home-page: https://github.com/anionDev/ScriptCollection
6
6
  Author: Marius Göcke
@@ -1,7 +1,7 @@
1
1
  ScriptCollection/AnionBuildPlatform.py,sha256=K-PHarX802A0PU8uRu0GNcEZiXujFoXHACe-X9YJsAQ,11711
2
2
  ScriptCollection/CertificateUpdater.py,sha256=Pa6eyjQSx7IIvj4PQVMI0IwMs01KQrNSB7Qa-7lRfBs,9375
3
3
  ScriptCollection/Executables.py,sha256=qpo0g5peWdlK5uLIUCyLDB9c3JCk0ETbtmOJXZwuHh4,44510
4
- ScriptCollection/GeneralUtilities.py,sha256=_7R_t46G1u8JNeUEl4HsgQ2mBGARFR6nIX_NUY2VNQY,64846
4
+ ScriptCollection/GeneralUtilities.py,sha256=FEjJEfA3riVT7G4sL8bzKPb7w0SN8YjONNWMtiBo_j8,64882
5
5
  ScriptCollection/HTTPMaintenanceOverheadHelper.py,sha256=TToNtyO1XzsMbBsTBf3o0xgOK0v4Jf03qw2Z0xb2nCk,2007
6
6
  ScriptCollection/ProcessesRunner.py,sha256=o5raxIt3lknNPoPrjNzJ2bprRPJ3SnL0rrR7crraD7E,1523
7
7
  ScriptCollection/ProgramRunnerBase.py,sha256=4A2eQgSg_rRgQcgSi-LYtUlM-uSQEpS7qFWn0tWt4uo,2171
@@ -9,7 +9,7 @@ ScriptCollection/ProgramRunnerMock.py,sha256=uTu-aFle1W_oKjeQEmuPsFPQpvo0kRf2FrR
9
9
  ScriptCollection/ProgramRunnerPopen.py,sha256=BPY7-ZMIlqT7JOKz8qlB5c0laF2Js-ijzqk09GxZC48,3821
10
10
  ScriptCollection/ProgramRunnerSudo.py,sha256=_khC3xuTdrPoLluBJZWfldltmmuKltABJPcbjZSFW-4,4835
11
11
  ScriptCollection/SCLog.py,sha256=8TRy1LeYMsPOIuWUcnUNNbO5pd-cNBS-3cn-kdzP8FU,4768
12
- ScriptCollection/ScriptCollectionCore.py,sha256=8U9gYLcex7DcrafJ6zP6_CN6YP5ebd-aLh5givt8SHo,175443
12
+ ScriptCollection/ScriptCollectionCore.py,sha256=k9Jxim56NM5dr6wAZrITk-bxZhKKxeXi1gb1zkfcDUo,176930
13
13
  ScriptCollection/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
14
14
  ScriptCollection/OCIImages/AbstractImageHandler.py,sha256=83qDMILwxhH9DbC0sb358Vu8PXEysmJJyap_6gECZqs,1627
15
15
  ScriptCollection/OCIImages/OCIImageManager.py,sha256=aBogkSXNDyi8NO11N-s03nuFJEv7PyJ-wjHuYYeZfvs,6662
@@ -30,9 +30,9 @@ ScriptCollection/TFCPS/TFCPS_Generic.py,sha256=O-0guM_LJCcZmPZJhMgTvXD2RXUJEBWWv
30
30
  ScriptCollection/TFCPS/TFCPS_MergeToMain.py,sha256=-Ev9D3bZDlUk2WFQhcmvzQ3FCS97OdsVUd0koAdmpZc,7474
31
31
  ScriptCollection/TFCPS/TFCPS_MergeToStable.py,sha256=Ajfy2pLajTuU6UpwItHt4C2a-gLF3gPc4z6BktL3Cio,22163
32
32
  ScriptCollection/TFCPS/TFCPS_PreBuildCodeunitsScript.py,sha256=f0Uq1cA_4LvmL72cal0crrbKF6PcxL13D9wBKuQ1YBw,2328
33
- ScriptCollection/TFCPS/TFCPS_Tools_General.py,sha256=zkdO9kHgPY-BHb13E9TbEIy06JD3EnKe2CWTx-6i5tM,96034
33
+ ScriptCollection/TFCPS/TFCPS_Tools_General.py,sha256=RCwtEwuZUds-gyHa2qCitWZUgapM3-IZJKF9e5Zwxck,98000
34
34
  ScriptCollection/TFCPS/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
35
- ScriptCollection/TFCPS/Docker/TFCPS_CodeUnitSpecific_Docker.py,sha256=VE1jAEP7trndm8u_5UR7YgWbHOvZJvRDaKUmPvtT4CM,11052
35
+ ScriptCollection/TFCPS/Docker/TFCPS_CodeUnitSpecific_Docker.py,sha256=xMuj-GoEwDnmUWbmdF536dNQL7jnTaw9aQ-gcDqUkgQ,11743
36
36
  ScriptCollection/TFCPS/Docker/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
37
37
  ScriptCollection/TFCPS/DotNet/CertificateGeneratorInformationBase.py,sha256=bT6Gd5pQpZCw4OQz6HWkPCSn5z__eUUEisABLDSxd0o,200
38
38
  ScriptCollection/TFCPS/DotNet/CertificateGeneratorInformationGenerate.py,sha256=QyjOfMY22JWCvKjMelHiDWbJiWqotOfebpJpgDUaoO4,237
@@ -47,8 +47,8 @@ ScriptCollection/TFCPS/NodeJS/TFCPS_CodeUnitSpecific_NodeJS.py,sha256=kL37qJNwH6
47
47
  ScriptCollection/TFCPS/NodeJS/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
48
48
  ScriptCollection/TFCPS/Python/TFCPS_CodeUnitSpecific_Python.py,sha256=KFKDdfV9DFHE5n7TI6m1Ra1Qw2JwL_JQjneBfqcRQ_w,13467
49
49
  ScriptCollection/TFCPS/Python/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
50
- scriptcollection-4.2.59.dist-info/METADATA,sha256=2AVlFcG9tMUQIWyeWjV0L4xuq46zScDA77h04vgkmco,7690
51
- scriptcollection-4.2.59.dist-info/WHEEL,sha256=aeYiig01lYGDzBgS8HxWXOg3uV61G9ijOsup-k9o1sk,91
52
- scriptcollection-4.2.59.dist-info/entry_points.txt,sha256=27XwAJEcaMEc1be0Ec1vKHCbiU4Ziu8jKL-SqsrYOIQ,4680
53
- scriptcollection-4.2.59.dist-info/top_level.txt,sha256=hY2hOVH0V0Ce51WB76zKkIWTUNwMUdHo4XDkR2vYVwg,17
54
- scriptcollection-4.2.59.dist-info/RECORD,,
50
+ scriptcollection-4.2.60.dist-info/METADATA,sha256=dQYQcvTQgiDemUjezOsxBCyPOkzYt6DkBe7HSGQUxf4,7690
51
+ scriptcollection-4.2.60.dist-info/WHEEL,sha256=aeYiig01lYGDzBgS8HxWXOg3uV61G9ijOsup-k9o1sk,91
52
+ scriptcollection-4.2.60.dist-info/entry_points.txt,sha256=27XwAJEcaMEc1be0Ec1vKHCbiU4Ziu8jKL-SqsrYOIQ,4680
53
+ scriptcollection-4.2.60.dist-info/top_level.txt,sha256=hY2hOVH0V0Ce51WB76zKkIWTUNwMUdHo4XDkR2vYVwg,17
54
+ scriptcollection-4.2.60.dist-info/RECORD,,