snapctl 0.35.0__tar.gz → 0.38.0__tar.gz

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.

Potentially problematic release.


This version of snapctl might be problematic. Click here for more details.

@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: snapctl
3
- Version: 0.35.0
3
+ Version: 0.38.0
4
4
  Summary: Snapser CLI Tool
5
5
  Author: Ajinkya Apte
6
6
  Author-email: aj@snapser.com
@@ -264,6 +264,10 @@ snapctl byosnap upload-docs $byosnap_sid --tag $image_tag --path $code_root_path
264
264
  Publish a custom snap code image. This command executes, `build`, `push` and `upload-docs` one
265
265
  after the other.
266
266
 
267
+ **IMPORTANT**: Take note of the hardware architecture of machine and your Dockerfile commands.
268
+ Commands in docker file may be hardware architecture specific. Snapser throws a warning if it detects
269
+ a mismatch.
270
+
267
271
  ```
268
272
  # Help for the byosnap command
269
273
  snapctl byosnap publish-image --help
@@ -348,6 +352,10 @@ snapctl byogs push --tag $image_tag
348
352
  Publish your custom game server image. This commend replaces the old way of creating, publishing image and
349
353
  then publishing the byogs. Now all you have to do is publish your image and create a fleet using the web portal.
350
354
 
355
+ **IMPORTANT**: Take note of the hardware architecture of machine and your Dockerfile commands.
356
+ Commands in docker file may be hardware architecture specific. Snapser throws a warning if it detects
357
+ a mismatch.
358
+
351
359
  ```
352
360
  # Help for the byogs command
353
361
  snapctl byogs publish --help
@@ -245,6 +245,10 @@ snapctl byosnap upload-docs $byosnap_sid --tag $image_tag --path $code_root_path
245
245
  Publish a custom snap code image. This command executes, `build`, `push` and `upload-docs` one
246
246
  after the other.
247
247
 
248
+ **IMPORTANT**: Take note of the hardware architecture of machine and your Dockerfile commands.
249
+ Commands in docker file may be hardware architecture specific. Snapser throws a warning if it detects
250
+ a mismatch.
251
+
248
252
  ```
249
253
  # Help for the byosnap command
250
254
  snapctl byosnap publish-image --help
@@ -329,6 +333,10 @@ snapctl byogs push --tag $image_tag
329
333
  Publish your custom game server image. This commend replaces the old way of creating, publishing image and
330
334
  then publishing the byogs. Now all you have to do is publish your image and create a fleet using the web portal.
331
335
 
336
+ **IMPORTANT**: Take note of the hardware architecture of machine and your Dockerfile commands.
337
+ Commands in docker file may be hardware architecture specific. Snapser throws a warning if it detects
338
+ a mismatch.
339
+
332
340
  ```
333
341
  # Help for the byogs command
334
342
  snapctl byogs publish --help
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "snapctl"
3
- version = "0.35.0"
3
+ version = "0.38.0"
4
4
  description = "Snapser CLI Tool"
5
5
  authors = ["Ajinkya Apte <aj@snapser.com>"]
6
6
  readme = "README.md"
@@ -5,6 +5,7 @@ import base64
5
5
  from binascii import Error as BinasciiError
6
6
  import os
7
7
  import subprocess
8
+ import platform as sys_platform
8
9
  from sys import platform
9
10
  from typing import Union
10
11
 
@@ -13,8 +14,9 @@ from snapctl.config.constants import SNAPCTL_BYOGS_DEPENDENCY_MISSING, \
13
14
  SNAPCTL_BYOGS_ECR_LOGIN_ERROR, SNAPCTL_BYOGS_BUILD_ERROR, \
14
15
  SNAPCTL_BYOGS_TAG_ERROR, SNAPCTL_BYOGS_PUBLISH_ERROR, \
15
16
  SNAPCTL_BYOGS_PUBLISH_DUPLICATE_TAG_ERROR, SNAPCTL_INPUT_ERROR
16
- from snapctl.utils.helper import get_composite_token, snapctl_error, snapctl_success
17
- from snapctl.utils.echo import info
17
+ from snapctl.utils.helper import get_composite_token, snapctl_error, snapctl_success, \
18
+ check_dockerfile_architecture
19
+ from snapctl.utils.echo import info, warning
18
20
 
19
21
 
20
22
  class ByoGs:
@@ -150,6 +152,13 @@ class ByoGs:
150
152
  build_platform = self.token_parts[3]
151
153
  # Build your snap
152
154
  docker_file_path = os.path.join(self.path, self.dockerfile)
155
+ # Warning check for architecture specific commands
156
+ info(f'Building on system architecture {sys_platform.machine()}')
157
+ check_response = check_dockerfile_architecture(
158
+ docker_file_path, sys_platform.machine())
159
+ if check_response['error']:
160
+ warning(check_response['message'])
161
+ # Build the image
153
162
  if platform == "win32":
154
163
  response = subprocess.run([
155
164
  # f"docker build --no-cache -t {tag} {path}"
@@ -160,7 +169,8 @@ class ByoGs:
160
169
  else:
161
170
  response = subprocess.run([
162
171
  # f"docker build --no-cache -t {tag} {path}"
163
- f"docker build --platform {build_platform} -t {self.input_tag} "
172
+ f"docker build --platform {
173
+ build_platform} -t {self.input_tag} "
164
174
  f"-f {docker_file_path} {self.path}"
165
175
  ], shell=True, check=False)
166
176
  # stdout=subprocess.DEVNULL, stderr=subprocess.STDOUT)
@@ -247,7 +257,8 @@ class ByoGs:
247
257
  # Check subcommand
248
258
  if not self.subcommand in ByoGs.SUBCOMMANDS:
249
259
  snapctl_error(
250
- f"Invalid command. Valid commands are {', '.join(ByoGs.SUBCOMMANDS)}.",
260
+ f"Invalid command. Valid commands are {
261
+ ', '.join(ByoGs.SUBCOMMANDS)}.",
251
262
  SNAPCTL_INPUT_ERROR)
252
263
  # Validation for subcommands
253
264
  if self.token_parts is None:
@@ -7,6 +7,7 @@ import json
7
7
  import os
8
8
  import re
9
9
  import subprocess
10
+ import platform as sys_platform
10
11
  from sys import platform
11
12
  from typing import Union
12
13
  import requests
@@ -22,8 +23,9 @@ from snapctl.config.constants import HTTP_ERROR_SERVICE_VERSION_EXISTS, \
22
23
  SNAPCTL_BYOSNAP_CREATE_DUPLICATE_NAME_ERROR, SNAPCTL_BYOSNAP_CREATE_PERMISSION_ERROR, \
23
24
  SNAPCTL_BYOSNAP_CREATE_ERROR, SNAPCTL_BYOSNAP_PUBLISH_VERSION_DUPLICATE_TAG_ERROR, \
24
25
  SNAPCTL_BYOSNAP_PUBLISH_VERSION_ERROR
25
- from snapctl.utils.echo import success, info
26
- from snapctl.utils.helper import get_composite_token, snapctl_error, snapctl_success
26
+ from snapctl.utils.echo import success, info, warning
27
+ from snapctl.utils.helper import get_composite_token, snapctl_error, snapctl_success, \
28
+ check_dockerfile_architecture
27
29
 
28
30
 
29
31
  class ByoSnap:
@@ -41,13 +43,16 @@ class ByoSnap:
41
43
  TAG_CHARACTER_LIMIT = 80
42
44
  VALID_CPU_MARKS = [100, 250, 500, 750, 1000, 1500, 2000, 3000]
43
45
  VALID_MEMORY_MARKS = [0.125, 0.25, 0.5, 1, 2, 3, 4]
46
+ MAX_READINESS_TIMEOUT = 30
47
+ MAX_MIN_REPLICAS = 4
44
48
 
45
49
  def __init__(
46
50
  self, subcommand: str, base_url: str, api_key: str | None, sid: str, name: str,
47
51
  desc: str, platform_type: str, language: str, input_tag: Union[str, None],
48
52
  path: Union[str, None], dockerfile: str, prefix: str, version: Union[str, None],
49
53
  http_port: Union[int, None], byosnap_profile: Union[str, None],
50
- skip_build: bool = False
54
+ skip_build: bool = False, readiness_path: Union[str, None] = None,
55
+ readiness_delay: Union[int, None] = None
51
56
  ) -> None:
52
57
  self.subcommand: str = subcommand
53
58
  self.base_url: str = base_url
@@ -74,6 +79,8 @@ class ByoSnap:
74
79
  self.http_port: Union[int, None] = http_port
75
80
  self.byosnap_profile: Union[str, None] = byosnap_profile
76
81
  self.skip_build: bool = skip_build
82
+ self.readiness_path: Union[str, None] = readiness_path
83
+ self.readiness_delay: Union[int, None] = readiness_delay
77
84
  # Validate the input
78
85
  self.validate_input()
79
86
 
@@ -179,6 +186,13 @@ class ByoSnap:
179
186
  try:
180
187
  # Build your snap
181
188
  docker_file_path = os.path.join(self.path, self.dockerfile)
189
+ # Warning check for architecture specific commands
190
+ info(f'Building on system architecture {sys_platform.machine()}')
191
+ check_response = check_dockerfile_architecture(
192
+ docker_file_path, sys_platform.machine())
193
+ if check_response['error']:
194
+ warning(check_response['message'])
195
+ # Build the image
182
196
  if platform == "win32":
183
197
  response = subprocess.run([
184
198
  # f"docker build --no-cache -t {tag} {path}"
@@ -189,7 +203,8 @@ class ByoSnap:
189
203
  else:
190
204
  response = subprocess.run([
191
205
  # f"docker build --no-cache -t {tag} {path}"
192
- f"docker build --platform {build_platform} -t {self.input_tag} "
206
+ f"docker build --platform {
207
+ build_platform} -t {self.input_tag} "
193
208
  f"-f {docker_file_path} {self.path}"
194
209
  ], shell=True, check=False)
195
210
  # stdout=subprocess.DEVNULL, stderr=subprocess.STDOUT)
@@ -300,6 +315,7 @@ class ByoSnap:
300
315
  SNAPCTL_INPUT_ERROR
301
316
  )
302
317
  for profile in ['dev_template', 'stage_template', 'prod_template']:
318
+ # Currently, not checking for 'min_replicas' not in profile_data[profile]
303
319
  if 'cpu' not in profile_data[profile] or \
304
320
  'memory' not in profile_data[profile] or \
305
321
  'cmd' not in profile_data[profile] or \
@@ -312,13 +328,25 @@ class ByoSnap:
312
328
  if profile_data[profile]['cpu'] not in ByoSnap.VALID_CPU_MARKS:
313
329
  snapctl_error(
314
330
  'Invalid CPU value in BYOSnap profile. '
315
- f'Valid values are {", ".join(map(str, ByoSnap.VALID_CPU_MARKS))}',
331
+ f'Valid values are {
332
+ ", ".join(map(str, ByoSnap.VALID_CPU_MARKS))}',
316
333
  SNAPCTL_INPUT_ERROR
317
334
  )
318
335
  if profile_data[profile]['memory'] not in ByoSnap.VALID_MEMORY_MARKS:
319
336
  snapctl_error(
320
337
  'Invalid Memory value in BYOSnap profile. '
321
- f'Valid values are {", ".join(map(str, ByoSnap.VALID_MEMORY_MARKS))}',
338
+ f'Valid values are {
339
+ ", ".join(map(str, ByoSnap.VALID_MEMORY_MARKS))}',
340
+ SNAPCTL_INPUT_ERROR
341
+ )
342
+ if 'min_replicas' in profile_data[profile] and \
343
+ (not isinstance(profile_data[profile]['min_replicas'], int) or
344
+ int(profile_data[profile]['min_replicas']) < 0 or
345
+ int(profile_data[profile]['min_replicas']) > ByoSnap.MAX_MIN_REPLICAS):
346
+ snapctl_error(
347
+ 'Invalid Min Replicas value in BYOSnap profile. '
348
+ f'Minimum replicas should be between 0 and {
349
+ ByoSnap.MAX_MIN_REPLICAS}',
322
350
  SNAPCTL_INPUT_ERROR
323
351
  )
324
352
 
@@ -342,13 +370,15 @@ class ByoSnap:
342
370
  # Validate the SID
343
371
  if not self.sid.startswith(ByoSnap.ID_PREFIX):
344
372
  snapctl_error(
345
- f"Invalid Snap ID. Valid Snap IDs start with {ByoSnap.ID_PREFIX}.",
373
+ f"Invalid Snap ID. Valid Snap IDs start with {
374
+ ByoSnap.ID_PREFIX}.",
346
375
  SNAPCTL_INPUT_ERROR
347
376
  )
348
377
  if len(self.sid) > ByoSnap.SID_CHARACTER_LIMIT:
349
378
  snapctl_error(
350
379
  "Invalid Snap ID. "
351
- f"Snap ID should be less than {ByoSnap.SID_CHARACTER_LIMIT} characters",
380
+ f"Snap ID should be less than {
381
+ ByoSnap.SID_CHARACTER_LIMIT} characters",
352
382
  SNAPCTL_INPUT_ERROR
353
383
  )
354
384
  # Validation for subcommands
@@ -391,7 +421,8 @@ class ByoSnap:
391
421
  # Check path
392
422
  if not self.skip_build and not os.path.isfile(f"{self.path}/{self.dockerfile}"):
393
423
  snapctl_error(
394
- f"Unable to find {self.dockerfile} at path {self.path}",
424
+ f"Unable to find {
425
+ self.dockerfile} at path {self.path}",
395
426
  SNAPCTL_INPUT_ERROR)
396
427
  # elif self.subcommand == 'push':
397
428
  # if not self.input_tag:
@@ -405,7 +436,8 @@ class ByoSnap:
405
436
  if not self.input_tag:
406
437
  snapctl_error(
407
438
  "Missing required parameter: tag", SNAPCTL_INPUT_ERROR)
408
- if len(self.input_tag.split()) > 1 or len(self.input_tag) > ByoSnap.TAG_CHARACTER_LIMIT:
439
+ if len(self.input_tag.split()) > 1 or \
440
+ len(self.input_tag) > ByoSnap.TAG_CHARACTER_LIMIT:
409
441
  snapctl_error(
410
442
  "Tag should be a single word with maximum of "
411
443
  f"{ByoSnap.TAG_CHARACTER_LIMIT} characters",
@@ -431,6 +463,18 @@ class ByoSnap:
431
463
  if not self.http_port.isdigit():
432
464
  snapctl_error("Ingress HTTP Port should be a number",
433
465
  SNAPCTL_INPUT_ERROR)
466
+ if self.readiness_path is not None:
467
+ if self.readiness_path.strip() == '':
468
+ snapctl_error("Readiness path cannot be empty",
469
+ SNAPCTL_INPUT_ERROR)
470
+ if not self.readiness_path.strip().startswith('/'):
471
+ snapctl_error("Readiness path has to start with /",
472
+ SNAPCTL_INPUT_ERROR)
473
+ if self.readiness_delay is not None:
474
+ if self.readiness_delay < 0 or \
475
+ self.readiness_delay > ByoSnap.MAX_READINESS_TIMEOUT:
476
+ snapctl_error("Readiness delay should be between 0 "
477
+ f"and {ByoSnap.MAX_READINESS_TIMEOUT}", SNAPCTL_INPUT_ERROR)
434
478
  # Check byosnap_profile path
435
479
  self._validate_byosnap_profile()
436
480
 
@@ -495,7 +539,8 @@ class ByoSnap:
495
539
  info('Unable to upload your swagger.json')
496
540
  except RequestException as e:
497
541
  info(
498
- f'Exception: Unable to find swagger.json at {self.path} {e}'
542
+ f'Exception: Unable to find swagger.json at {
543
+ self.path} {e}'
499
544
  )
500
545
  else:
501
546
  info(f'No swagger.json found at {self.path}'
@@ -561,7 +606,8 @@ class ByoSnap:
561
606
  if "api_error_code" in response_json and "message" in response_json:
562
607
  if response_json['api_error_code'] == HTTP_ERROR_SERVICE_VERSION_EXISTS:
563
608
  snapctl_error(
564
- f'BYOSnap {self.name} already exists. Please use a different name',
609
+ f'BYOSnap {
610
+ self.name} already exists. Please use a different name',
565
611
  SNAPCTL_BYOSNAP_CREATE_DUPLICATE_NAME_ERROR,
566
612
  progress
567
613
  )
@@ -628,6 +674,10 @@ class ByoSnap:
628
674
  "image_tag": self.input_tag,
629
675
  "base_url": f"{self.prefix}/{self.sid}",
630
676
  "http_port": self.http_port,
677
+ "readiness_probe_config": {
678
+ "path": self.readiness_path,
679
+ "initial_delay_seconds": self.readiness_delay
680
+ },
631
681
  "dev_template": profile_data['dev_template'],
632
682
  "stage_template": profile_data['stage_template'],
633
683
  "prod_template": profile_data['prod_template']
@@ -2,7 +2,7 @@
2
2
  Constants used by snapctl
3
3
  """
4
4
  COMPANY_NAME = 'Snapser'
5
- VERSION = '0.35.0'
5
+ VERSION = '0.38.0'
6
6
  CONFIG_FILE_MAC = '~/.snapser/config'
7
7
  CONFIG_FILE_WIN = '%homepath%\\.snapser\\config'
8
8
 
@@ -149,7 +149,7 @@ SNAPEND_MANIFEST_TYPES: dict[str, dict[str, str]] = {
149
149
  },
150
150
  }
151
151
 
152
- SERVICE_IDS = [
152
+ SERVICE_IDS: list[str] = [
153
153
  'analytics', 'auth', 'client-logs', 'events', 'experiments', 'gdpr', 'guilds', 'hades', 'iap',
154
154
  'inventory', 'leaderboards', 'matchmaking', 'notifications', 'parties', 'profiles', 'quests',
155
155
  'relay', 'remote-config', 'scheduler', 'sequencer', 'social-graph', 'statistics', 'storage',
@@ -159,6 +159,7 @@ SERVICE_IDS = [
159
159
  DEFAULT_BYOSNAP_DEV_TEMPLATE = {
160
160
  'cpu': 100,
161
161
  'memory': 0.125,
162
+ 'min_replicas': 1,
162
163
  'cmd': '',
163
164
  'args': [],
164
165
  'env_params': [{'key': "SNAPSER_ENVIRONMENT", 'value': "DEVELOPMENT"}]
@@ -167,6 +168,7 @@ DEFAULT_BYOSNAP_DEV_TEMPLATE = {
167
168
  DEFAULT_BYOSNAP_STAGE_TEMPLATE = {
168
169
  'cpu': 100,
169
170
  'memory': 0.125,
171
+ 'min_replicas': 1,
170
172
  'cmd': '',
171
173
  'args': [],
172
174
  'env_params': [{'key': "SNAPSER_ENVIRONMENT", 'value': "STAGING"}]
@@ -175,6 +177,7 @@ DEFAULT_BYOSNAP_STAGE_TEMPLATE = {
175
177
  DEFAULT_BYOSNAP_PROD_TEMPLATE = {
176
178
  'cpu': 100,
177
179
  'memory': 0.125,
180
+ 'min_replicas': 2,
178
181
  'cmd': '',
179
182
  'args': [],
180
183
  'env_params': [{'key': "SNAPSER_ENVIRONMENT", 'value': "PRODUCTION"}]
@@ -185,3 +188,10 @@ BYOSNAP_TEMPLATE = {
185
188
  'stage_template': DEFAULT_BYOSNAP_STAGE_TEMPLATE,
186
189
  'prod_template': DEFAULT_BYOSNAP_PROD_TEMPLATE
187
190
  }
191
+
192
+ ARCHITECTURE_MAPPING: dict[str, str] = {
193
+ 'x86_64': 'amd64',
194
+ 'arm64': 'arm64',
195
+ 'aarch64': 'arm64',
196
+ 'amd64': 'amd64'
197
+ }
@@ -76,7 +76,8 @@ def extract_config(extract_key: str, profile: str | None = None) -> object:
76
76
  result['location'] = f'"{config_file_path}:profile {profile}"'
77
77
  config_profile = f'profile {profile}'
78
78
  info(
79
- f'Trying to extract API KEY from "{config_file_path}:profile {profile}"'
79
+ f'Trying to extract API KEY from "{
80
+ config_file_path}:profile {profile}"'
80
81
  )
81
82
  result['value'] = config.get(
82
83
  config_profile, extract_key, fallback=None, raw=True
@@ -338,7 +339,12 @@ def byosnap(
338
339
  skip_build: bool = typer.Option(
339
340
  False, "--skip-build", help="(optional: publish-image) Skip the build step. You have to pass the image tag you used during the build step."
340
341
  ),
341
-
342
+ readiness_path: str = typer.Option(
343
+ None, "--readiness-path", help="(req: publish-version) Readiness path for your snap"
344
+ ),
345
+ readiness_delay: int = typer.Option(
346
+ None, "--readiness-delay", help="(req: publish-version) Delay before readiness check"
347
+ ),
342
348
  # overrides
343
349
  api_key: Union[str, None] = typer.Option(
344
350
  None, "--api-key", help="API Key override.", callback=api_key_context_callback
@@ -354,7 +360,8 @@ def byosnap(
354
360
  byosnap_obj: ByoSnap = ByoSnap(
355
361
  subcommand, ctx.obj['base_url'], ctx.obj['api_key'], sid,
356
362
  name, desc, platform_type, language, tag, path, docker_file,
357
- prefix, version, http_port, byosnap_profile, skip_build
363
+ prefix, version, http_port, byosnap_profile, skip_build,
364
+ readiness_path, readiness_delay
358
365
  )
359
366
  getattr(byosnap_obj, subcommand.replace('-', '_'))()
360
367
  success(f"BYOSnap {subcommand} complete")
@@ -20,6 +20,13 @@ def error(msg: str, code: int = SNAPCTL_ERROR, data: object = None) -> None:
20
20
  typer.echo(json.dumps(error_response.to_dict()), err=True)
21
21
 
22
22
 
23
+ def warning(msg: str) -> None:
24
+ """
25
+ Prints a warning message to the console.
26
+ """
27
+ print(f"[bold yellow]Warning[/bold yellow] {msg}")
28
+
29
+
23
30
  def info(msg: str) -> None:
24
31
  """
25
32
  Prints an info message to the console.
@@ -1,16 +1,18 @@
1
1
  """
2
2
  Helper functions for snapctl
3
3
  """
4
+ import re
4
5
  import requests
5
6
  import typer
6
7
  from requests.exceptions import RequestException
7
8
  from rich.progress import Progress
8
9
  from snapctl.config.constants import HTTP_NOT_FOUND, HTTP_FORBIDDEN, HTTP_UNAUTHORIZED, \
9
10
  SERVER_CALL_TIMEOUT, SNAPCTL_CONFIGURATION_ERROR, SNAPCTL_SUCCESS
11
+ from snapctl.config.hashes import ARCHITECTURE_MAPPING
10
12
  from snapctl.utils.echo import error, success
11
13
 
12
14
 
13
- def validate_api_key(base_url: str, api_key: str | None):
15
+ def validate_api_key(base_url: str, api_key: str | None) -> bool:
14
16
  """
15
17
  This function validates the API Key
16
18
  """
@@ -74,6 +76,63 @@ def get_composite_token(base_url: str, api_key: str | None, action: str, params:
74
76
  return res.json()['token']
75
77
 
76
78
 
79
+ def check_dockerfile_architecture(dockerfile_path: str, system_arch: str) -> dict[str, object]:
80
+ """
81
+ Check the Dockerfile for architecture specific commands
82
+ """
83
+ response = {
84
+ 'error': False,
85
+ 'message': ''
86
+ }
87
+ # Normalize system architecture
88
+ system_arch = ARCHITECTURE_MAPPING.get(system_arch, system_arch)
89
+ try:
90
+ lines = []
91
+ with open(dockerfile_path, 'r') as file:
92
+ lines = file.readlines()
93
+ for line_number, line in enumerate(lines, 1):
94
+ if line.startswith('#'):
95
+ continue
96
+ # Checking various build and run commands for architecture specifics
97
+ patterns = [
98
+ # FROM with platform
99
+ r'FROM --platform=linux/(\w+)',
100
+ # dotnet runtime
101
+ r'-r linux-(\w+)',
102
+ # Build args specifying arch
103
+ r'--build-arg ARCH=(\w+)',
104
+ # Environment variables setting arch
105
+ r'ENV ARCH=(\w+)',
106
+ # cmake specifying arch
107
+ r'cmake.*?-DARCH=(\w+)',
108
+ # make specifying arch
109
+ r'make.*?ARCH=(\w+)'
110
+ ]
111
+
112
+ for pattern in patterns:
113
+ match = re.search(pattern, line)
114
+ if match and ARCHITECTURE_MAPPING.get(match.group(1)) != system_arch:
115
+ response['error'] = True
116
+ response['message'] = (
117
+ f'[Architecture Mismatch] Line {line_number}: "{
118
+ line.strip()}" '
119
+ f' of Dockerfile {dockerfile_path}'
120
+ f' specifies architecture {
121
+ match.group(1)}, which does not match the '
122
+ f' systems ({system_arch}).'
123
+ )
124
+ return response
125
+ except FileNotFoundError:
126
+ response['error'] = True
127
+ response['message'] = f'Dockerfile not found at {dockerfile_path}'
128
+ return response
129
+ except Exception as e:
130
+ response['error'] = True
131
+ response['message'] = f'Exception {e}'
132
+ return response
133
+ return response
134
+
135
+
77
136
  def snapctl_success(message: str, progress: Progress | None = None, no_exit: bool = False):
78
137
  """
79
138
  This function exits the snapctl
File without changes
File without changes
File without changes