rtems-proxy 2.0.0__tar.gz → 2.1.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.
Files changed (53) hide show
  1. {rtems_proxy-2.0.0 → rtems_proxy-2.1.0}/PKG-INFO +1 -1
  2. {rtems_proxy-2.0.0 → rtems_proxy-2.1.0}/requirements.txt +1 -1
  3. {rtems_proxy-2.0.0 → rtems_proxy-2.1.0}/rtems-proxy.code-workspace +0 -3
  4. {rtems_proxy-2.0.0 → rtems_proxy-2.1.0}/src/rtems_proxy/__main__.py +19 -5
  5. {rtems_proxy-2.0.0 → rtems_proxy-2.1.0}/src/rtems_proxy/_version.py +3 -3
  6. {rtems_proxy-2.0.0 → rtems_proxy-2.1.0}/src/rtems_proxy/configure.py +1 -1
  7. rtems_proxy-2.1.0/src/rtems_proxy/connect.py +102 -0
  8. {rtems_proxy-2.0.0 → rtems_proxy-2.1.0}/src/rtems_proxy/copy.py +29 -0
  9. {rtems_proxy-2.0.0 → rtems_proxy-2.1.0}/src/rtems_proxy/globals.py +1 -1
  10. {rtems_proxy-2.0.0 → rtems_proxy-2.1.0}/src/rtems_proxy/telnet.py +33 -90
  11. {rtems_proxy-2.0.0 → rtems_proxy-2.1.0}/src/rtems_proxy.egg-info/PKG-INFO +1 -1
  12. {rtems_proxy-2.0.0 → rtems_proxy-2.1.0}/src/rtems_proxy.egg-info/SOURCES.txt +1 -0
  13. {rtems_proxy-2.0.0 → rtems_proxy-2.1.0}/.copier-answers.yml +0 -0
  14. {rtems_proxy-2.0.0 → rtems_proxy-2.1.0}/.devcontainer/devcontainer.json +0 -0
  15. {rtems_proxy-2.0.0 → rtems_proxy-2.1.0}/.github/CONTRIBUTING.md +0 -0
  16. {rtems_proxy-2.0.0 → rtems_proxy-2.1.0}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
  17. {rtems_proxy-2.0.0 → rtems_proxy-2.1.0}/.github/ISSUE_TEMPLATE/issue.md +0 -0
  18. {rtems_proxy-2.0.0 → rtems_proxy-2.1.0}/.github/PULL_REQUEST_TEMPLATE/pull_request_template.md +0 -0
  19. {rtems_proxy-2.0.0 → rtems_proxy-2.1.0}/.github/copilot-instructions.md +0 -0
  20. {rtems_proxy-2.0.0 → rtems_proxy-2.1.0}/.github/pages/index.html +0 -0
  21. {rtems_proxy-2.0.0 → rtems_proxy-2.1.0}/.github/pages/make_switcher.py +0 -0
  22. {rtems_proxy-2.0.0 → rtems_proxy-2.1.0}/.github/workflows/_container.yml +0 -0
  23. {rtems_proxy-2.0.0 → rtems_proxy-2.1.0}/.github/workflows/_dist.yml +0 -0
  24. {rtems_proxy-2.0.0 → rtems_proxy-2.1.0}/.github/workflows/_pypi.yml +0 -0
  25. {rtems_proxy-2.0.0 → rtems_proxy-2.1.0}/.github/workflows/_release.yml +0 -0
  26. {rtems_proxy-2.0.0 → rtems_proxy-2.1.0}/.github/workflows/_test.yml +0 -0
  27. {rtems_proxy-2.0.0 → rtems_proxy-2.1.0}/.github/workflows/_tox.yml +0 -0
  28. {rtems_proxy-2.0.0 → rtems_proxy-2.1.0}/.github/workflows/ci.yml +0 -0
  29. {rtems_proxy-2.0.0 → rtems_proxy-2.1.0}/.gitignore +0 -0
  30. {rtems_proxy-2.0.0 → rtems_proxy-2.1.0}/.gitleaks.toml +0 -0
  31. {rtems_proxy-2.0.0 → rtems_proxy-2.1.0}/.pre-commit-config.yaml +0 -0
  32. {rtems_proxy-2.0.0 → rtems_proxy-2.1.0}/.python-version +0 -0
  33. {rtems_proxy-2.0.0 → rtems_proxy-2.1.0}/.vscode/extensions.json +0 -0
  34. {rtems_proxy-2.0.0 → rtems_proxy-2.1.0}/.vscode/launch.json +0 -0
  35. {rtems_proxy-2.0.0 → rtems_proxy-2.1.0}/.vscode/settings.json +0 -0
  36. {rtems_proxy-2.0.0 → rtems_proxy-2.1.0}/.vscode/tasks.json +0 -0
  37. {rtems_proxy-2.0.0 → rtems_proxy-2.1.0}/Dockerfile +0 -0
  38. {rtems_proxy-2.0.0 → rtems_proxy-2.1.0}/LICENSE +0 -0
  39. {rtems_proxy-2.0.0 → rtems_proxy-2.1.0}/README.md +0 -0
  40. {rtems_proxy-2.0.0 → rtems_proxy-2.1.0}/pyproject.toml +0 -0
  41. {rtems_proxy-2.0.0 → rtems_proxy-2.1.0}/renovate.json +0 -0
  42. {rtems_proxy-2.0.0 → rtems_proxy-2.1.0}/setup.cfg +0 -0
  43. {rtems_proxy-2.0.0 → rtems_proxy-2.1.0}/src/rtems_proxy/__init__.py +0 -0
  44. {rtems_proxy-2.0.0 → rtems_proxy-2.1.0}/src/rtems_proxy/rsync.sh.jinja +0 -0
  45. {rtems_proxy-2.0.0 → rtems_proxy-2.1.0}/src/rtems_proxy/trace.py +0 -0
  46. {rtems_proxy-2.0.0 → rtems_proxy-2.1.0}/src/rtems_proxy/utils.py +0 -0
  47. {rtems_proxy-2.0.0 → rtems_proxy-2.1.0}/src/rtems_proxy.egg-info/dependency_links.txt +0 -0
  48. {rtems_proxy-2.0.0 → rtems_proxy-2.1.0}/src/rtems_proxy.egg-info/entry_points.txt +0 -0
  49. {rtems_proxy-2.0.0 → rtems_proxy-2.1.0}/src/rtems_proxy.egg-info/requires.txt +0 -0
  50. {rtems_proxy-2.0.0 → rtems_proxy-2.1.0}/src/rtems_proxy.egg-info/top_level.txt +0 -0
  51. {rtems_proxy-2.0.0 → rtems_proxy-2.1.0}/tests/conftest.py +0 -0
  52. {rtems_proxy-2.0.0 → rtems_proxy-2.1.0}/tests/test_cli.py +0 -0
  53. {rtems_proxy-2.0.0 → rtems_proxy-2.1.0}/uv.lock +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: rtems-proxy
3
- Version: 2.0.0
3
+ Version: 2.1.0
4
4
  Summary: Support for a K8S proxy container in controlling and monitoring RTEMS EPICS IOCs
5
5
  Author-email: Giles Knap <giles.knap@diamond.ac.uk>
6
6
  License: Apache License
@@ -1,3 +1,3 @@
1
1
  # these requirements are for additional python packages to install into the
2
2
  # container
3
- ibek==3.1.3
3
+ ibek==3.3.1
@@ -8,9 +8,6 @@
8
8
  },
9
9
  {
10
10
  "path": "../i04-services"
11
- },
12
- {
13
- "path": "../rf-services"
14
11
  }
15
12
  ],
16
13
  "settings": {}
@@ -11,9 +11,9 @@ from rtems_proxy.utils import run_command
11
11
 
12
12
  from . import __version__
13
13
  from .configure import Configure
14
- from .copy import copy_rtems
14
+ from .connect import ioc_connect, motboot_connect, report
15
+ from .copy import check_new_version, copy_rtems, save_current_version
15
16
  from .globals import GLOBALS
16
- from .telnet import ioc_connect, motboot_connect, report
17
17
 
18
18
  __all__ = ["main"]
19
19
 
@@ -52,6 +52,9 @@ def start(
52
52
  reboot: bool = typer.Option(
53
53
  True, "--reboot/--no-reboot", help="reboot the IOC first"
54
54
  ),
55
+ configure: bool = typer.Option(
56
+ True, "--configure/--no-configure", help="configure motBoot when rebooting"
57
+ ),
55
58
  raise_errors: bool = typer.Option(
56
59
  True, "--raise-errors/--no-raise-errors", help="raise errors instead of exiting"
57
60
  ),
@@ -78,11 +81,23 @@ def start(
78
81
  )
79
82
  if copy:
80
83
  copy_rtems()
84
+
85
+ # always reboot if the IOC definition has changed
86
+ if check_new_version():
87
+ report("IOC definition has changed, forcing reboot to pick up changes")
88
+ reboot = True
89
+
81
90
  if connect:
82
91
  assert GLOBALS.RTEMS_CONSOLE, "No RTEMS console defined"
83
92
  ioc_connect(
84
- GLOBALS.RTEMS_CONSOLE, reboot=reboot, attach=True, raise_errors=raise_errors
93
+ GLOBALS.RTEMS_CONSOLE,
94
+ reboot=reboot,
95
+ attach=True,
96
+ raise_errors=raise_errors,
97
+ configure=configure,
85
98
  )
99
+ # now we have rebooted into the IOC we can save the current version
100
+ save_current_version()
86
101
  else:
87
102
  report("IOC console connection disabled. ")
88
103
 
@@ -189,9 +204,8 @@ def configure(
189
204
  else:
190
205
  assert GLOBALS.RTEMS_CONSOLE, "No RTEMS console defined"
191
206
 
192
- config = Configure(None, debug=debug)
193
207
  telnet = motboot_connect(GLOBALS.RTEMS_CONSOLE, use_console=use_console)
194
- config = Configure(telnet, debug=debug, dry_run=dry_run)
208
+ config = Configure(telnet, debug=debug, dry_run=False)
195
209
  config.apply_settings()
196
210
  telnet.close()
197
211
  if attach:
@@ -28,7 +28,7 @@ version_tuple: VERSION_TUPLE
28
28
  commit_id: COMMIT_ID
29
29
  __commit_id__: COMMIT_ID
30
30
 
31
- __version__ = version = '2.0.0'
32
- __version_tuple__ = version_tuple = (2, 0, 0)
31
+ __version__ = version = '2.1.0'
32
+ __version_tuple__ = version_tuple = (2, 1, 0)
33
33
 
34
- __commit_id__ = commit_id = 'g9b4243c59'
34
+ __commit_id__ = commit_id = 'gb348b0264'
@@ -35,7 +35,7 @@ class Configure:
35
35
  else:
36
36
  self.telnet.sendline(f"gevE {variable}")
37
37
  self.telnet.expect(r"\(Blank line terminates input.\)")
38
- self.telnet.sendline(value or "")
38
+ self.telnet.sendline(value)
39
39
  self.telnet.sendline("")
40
40
  self.telnet.expect(r"\?")
41
41
  self.telnet.sendline("Y")
@@ -0,0 +1,102 @@
1
+ from time import sleep
2
+
3
+ import pexpect
4
+
5
+ from .configure import Configure
6
+ from .telnet import CannotConnectError, RtemsState, TelnetRTEMS
7
+ from .utils import run_command
8
+
9
+
10
+ def report(message):
11
+ """
12
+ print a message that is noticeable amongst all the other output
13
+ """
14
+ print(f"\n>>>> {message} <<<<\n")
15
+
16
+
17
+ def ioc_connect(
18
+ host_and_port: str,
19
+ reboot: bool = False,
20
+ configure: bool = True,
21
+ attach: bool = True,
22
+ raise_errors: bool = False,
23
+ ):
24
+ """
25
+ Entrypoint to make a connection to an RTEMS IOC over telnet.
26
+ Once connected, enters an interactive user session with the IOC.
27
+
28
+ args:
29
+ host_and_port: 'hostname:port' of the IOC to connect to
30
+ reboot: reboot the IOC to pick up new binaries/startup/epics db
31
+ """
32
+ telnet = TelnetRTEMS(host_and_port, reboot)
33
+
34
+ try:
35
+ telnet.connect()
36
+
37
+ # this will untangle a partially executed gevEdit command
38
+ for _ in range(3):
39
+ telnet.sendline("\r")
40
+
41
+ current = telnet.check_prompt(retries=6, timeout=10)
42
+ match current:
43
+ case RtemsState.MOT:
44
+ report("At MOTBoot prompt")
45
+ reboot = True
46
+ case RtemsState.UNKNOWN:
47
+ report("Current IOC state unknown, attempting reboot ...")
48
+ reboot = True
49
+ case RtemsState.IOC:
50
+ report("At IOC shell prompt")
51
+
52
+ if reboot:
53
+ if configure:
54
+ report("Rebooting to configure motBoot settings")
55
+ telnet.get_boot_prompt(retries=10)
56
+ sleep(1)
57
+ cfg = Configure(telnet)
58
+ cfg.apply_settings()
59
+ else:
60
+ report("Rebooting into IOC shell")
61
+
62
+ telnet.get_epics_prompt(retries=10)
63
+ else:
64
+ report("Auto reboot disabled. Skipping reboot")
65
+
66
+ except (CannotConnectError, pexpect.exceptions.TIMEOUT):
67
+ report("Connection failed, Exiting.")
68
+ telnet.close()
69
+ raise
70
+
71
+ except Exception as e:
72
+ # flush any remaining buffered output to stdout
73
+ telnet.flush_remaining_output()
74
+ report(f"An error occurred: {e}")
75
+ telnet.close()
76
+ if raise_errors:
77
+ raise
78
+
79
+ telnet.close()
80
+ if attach:
81
+ report("Connecting to IOC console, hit enter for a prompt")
82
+ run_command(telnet.command)
83
+
84
+
85
+ def motboot_connect(
86
+ host_and_port: str, reboot: bool = False, use_console: bool = False
87
+ ) -> TelnetRTEMS:
88
+ """
89
+ Connect to the MOTBoot bootloader prompt, rebooting if needed.
90
+
91
+ Returns a TelnetRTEMS object that is connected to the MOTBoot bootloader
92
+ """
93
+ telnet = TelnetRTEMS(host_and_port, ioc_reboot=reboot, use_console=use_console)
94
+ telnet.connect()
95
+
96
+ # this will untangle a partially executed gevEdit command
97
+ for _ in range(3):
98
+ telnet.sendline("\r")
99
+
100
+ telnet.get_boot_prompt()
101
+
102
+ return telnet
@@ -9,6 +9,35 @@ from pathlib import Path
9
9
  from .globals import GLOBALS
10
10
 
11
11
 
12
+ def save_current_version():
13
+ """
14
+ Save the current version string to a file in the NFS root so that the IOC
15
+ can report its version on startup
16
+
17
+ We use the env IOC_ORIGINAL_LOCATION as a proxy for the version string
18
+ """
19
+ version_file = Path(GLOBALS.RTEMS_NFS_ROOT_PATH) / "rtems_proxy_version.txt"
20
+ with open(version_file, "w") as vf:
21
+ vf.write(str(GLOBALS.IOC_ORIGINAL_LOCATION) + "\n")
22
+
23
+
24
+ def check_new_version():
25
+ """
26
+ Check if the version string saved in the NFS root matches the current
27
+ version string.
28
+
29
+ We use the env IOC_ORIGINAL_LOCATION as a proxy for the version string
30
+ """
31
+ version_file = Path(GLOBALS.RTEMS_NFS_ROOT_PATH) / "rtems_proxy_version.txt"
32
+ if not version_file.exists():
33
+ return True
34
+
35
+ with open(version_file) as vf:
36
+ saved_version = vf.read().strip()
37
+
38
+ return saved_version != str(GLOBALS.IOC_ORIGINAL_LOCATION)
39
+
40
+
12
41
  def copy_rtems(debug: bool = False):
13
42
  """
14
43
  Copy RTEMS IOC binary and startup assets to a location where the RTEMS IOC
@@ -22,7 +22,7 @@ class _Globals:
22
22
  self.RTEMS_TFTP_ROOT_PATH = Path("/ioc_tftp")
23
23
  """ root folder of a mounted PVC in which to place IOC binaries """
24
24
  self.RTEMS_NFS_ROOT_PATH = Path("/ioc_nfs")
25
- """ root folder of a mounted NFS folder in which to place IOC binaries """
25
+ """ root folder of a mounted NFS folder in which to place IOC runtime files """
26
26
 
27
27
  ########################################################################
28
28
  ## Beamline level config from global.env in services/values.yaml
@@ -5,8 +5,6 @@ from time import sleep
5
5
 
6
6
  import pexpect
7
7
 
8
- from .utils import run_command
9
-
10
8
 
11
9
  class CannotConnectError(Exception):
12
10
  pass
@@ -78,6 +76,7 @@ class TelnetRTEMS:
78
76
  logfile=sys.stdout,
79
77
  echo=False,
80
78
  codec_errors="ignore",
79
+ timeout=5,
81
80
  )
82
81
  try:
83
82
  # first check for connection refusal
@@ -89,7 +88,7 @@ class TelnetRTEMS:
89
88
  report("Cannot connect to remote IOC, connection in use?")
90
89
  raise CannotConnectError
91
90
 
92
- def check_prompt(self, retries) -> RtemsState:
91
+ def check_prompt(self, retries, timeout=15) -> RtemsState:
93
92
  """
94
93
  Determine if we are currently seeing an IOC shell prompt or
95
94
  bootloader. Because there is a possibility that we are in the middle
@@ -104,24 +103,33 @@ class TelnetRTEMS:
104
103
  self._child.sendline(self.IOC_CHECK)
105
104
  self._child.expect(self.IOC_RESPONSE, timeout=1)
106
105
  except pexpect.exceptions.TIMEOUT:
107
- try:
108
- # see if we are in the bootloader
109
- self._child.sendline()
110
- self._child.expect(self.MOT_PROMPT, timeout=1)
111
- except pexpect.exceptions.TIMEOUT:
112
- # current state unknown. wait and retry
113
- sleep(15)
114
- else:
115
- report("Currently in bootloader")
116
- return RtemsState.MOT
106
+ pass
117
107
  else:
118
- report("Currently in IOC shell")
119
108
  return RtemsState.IOC
120
109
 
110
+ try:
111
+ # see if we are in the bootloader
112
+ self._child.sendline()
113
+ self._child.expect(self.MOT_PROMPT, timeout=1)
114
+ except pexpect.exceptions.TIMEOUT:
115
+ pass
116
+ else:
117
+ return RtemsState.MOT
118
+
119
+ try:
120
+ # current state unknown. check for mot start prompt
121
+ # in case we are in a boot loop
122
+ self._child.expect(self.CONTINUE, timeout=timeout)
123
+ except pexpect.exceptions.TIMEOUT:
124
+ pass
125
+ else:
126
+ # send escape to get into the bootloader
127
+ self._child.sendline(chr(27))
128
+ return RtemsState.MOT
129
+
121
130
  report(f"Retry {retry + 1} of get current status")
122
131
 
123
- report("Current state UNKNOWN")
124
- raise CannotConnectError("Current state of remote IOC unknown")
132
+ return RtemsState.UNKNOWN
125
133
 
126
134
  def reboot(self, into: RtemsState):
127
135
  """
@@ -145,6 +153,8 @@ class TelnetRTEMS:
145
153
  # send space to boot the IOC
146
154
  self._child.send(" ")
147
155
 
156
+ self.ioc_rebooted = True
157
+
148
158
  def get_epics_prompt(self, retries=5):
149
159
  """
150
160
  Get to the IOC shell prompt, if the IOC is not already running, reboot
@@ -153,27 +163,26 @@ class TelnetRTEMS:
153
163
  """
154
164
  assert self._child, "must call connect before get_epics_prompt"
155
165
 
156
- current = self.check_prompt(retries=10)
166
+ current = self.check_prompt(retries=retries)
157
167
 
158
168
  if current != RtemsState.IOC or (self._ioc_reboot and not self.ioc_rebooted):
159
169
  sleep(0.5)
160
- report("Rebooting the IOC")
161
170
 
171
+ report("Rebooting into IOC shell")
162
172
  self.reboot(RtemsState.IOC)
163
- self.ioc_rebooted = True
164
173
 
165
- current = self.check_prompt(retries=10)
174
+ current = self.check_prompt(retries=retries)
166
175
  if current != RtemsState.IOC:
167
176
  raise CannotConnectError("Failed to reboot into IOC shell")
168
177
 
169
- def get_boot_prompt(self):
178
+ def get_boot_prompt(self, retries=5):
170
179
  """
171
180
  Get to the bootloader prompt, if the IOC shell is running then exit
172
181
  and send appropriate commands to get to the bootloader
173
182
  """
174
183
  assert self._child, "must call connect before get_boot_prompt"
175
184
 
176
- current = self.check_prompt(retries=10)
185
+ current = self.check_prompt(retries=retries)
177
186
  if current != RtemsState.MOT:
178
187
  # get out of the IOC and return to MOT
179
188
  self.reboot(RtemsState.MOT)
@@ -185,8 +194,9 @@ class TelnetRTEMS:
185
194
  """
186
195
  Send a command to the telnet session
187
196
  """
197
+ # always pause a little to allow the previous expect to complete
188
198
  assert self._child, "must call connect before send"
189
- self._child.sendline(command)
199
+ self._child.sendline(command + "\r")
190
200
 
191
201
  def expect(self, pattern, timeout=10) -> None:
192
202
  """
@@ -221,70 +231,3 @@ def report(message):
221
231
  print a message that is noticeable amongst all the other output
222
232
  """
223
233
  print(f"\n>>>> {message} <<<<\n")
224
-
225
-
226
- def ioc_connect(
227
- host_and_port: str,
228
- reboot: bool = False,
229
- attach: bool = True,
230
- raise_errors: bool = False,
231
- ):
232
- """
233
- Entrypoint to make a connection to an RTEMS IOC over telnet.
234
- Once connected, enters an interactive user session with the IOC.
235
-
236
- args:
237
- host_and_port: 'hostname:port' of the IOC to connect to
238
- reboot: reboot the IOC to pick up new binaries/startup/epics db
239
- """
240
- telnet = TelnetRTEMS(host_and_port, reboot)
241
-
242
- try:
243
- telnet.connect()
244
-
245
- # this will untangle a partially executed gevEdit command
246
- for _ in range(3):
247
- telnet.sendline("\r")
248
-
249
- if reboot:
250
- telnet.get_epics_prompt(retries=10)
251
- else:
252
- report("Auto reboot disabled. Skipping reboot")
253
-
254
- except (CannotConnectError, pexpect.exceptions.TIMEOUT):
255
- report("Connection failed, Exiting.")
256
- telnet.close()
257
- raise
258
-
259
- except Exception as e:
260
- # flush any remaining buffered output to stdout
261
- telnet.flush_remaining_output()
262
- report(f"An error occurred: {e}")
263
- telnet.close()
264
- if raise_errors:
265
- raise
266
-
267
- telnet.close()
268
- if attach:
269
- report("Connecting to IOC console, hit enter for a prompt")
270
- run_command(telnet.command)
271
-
272
-
273
- def motboot_connect(
274
- host_and_port: str, reboot: bool = False, use_console: bool = False
275
- ) -> TelnetRTEMS:
276
- """
277
- Connect to the MOTBoot bootloader prompt, rebooting if needed.
278
-
279
- Returns a TelnetRTEMS object that is connected to the MOTBoot bootloader
280
- """
281
- telnet = TelnetRTEMS(host_and_port, ioc_reboot=reboot, use_console=use_console)
282
- telnet.connect()
283
-
284
- # this will untangle a partially executed gevEdit command
285
- for _ in range(3):
286
- telnet.sendline("\r")
287
-
288
- telnet.get_boot_prompt()
289
-
290
- return telnet
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: rtems-proxy
3
- Version: 2.0.0
3
+ Version: 2.1.0
4
4
  Summary: Support for a K8S proxy container in controlling and monitoring RTEMS EPICS IOCs
5
5
  Author-email: Giles Knap <giles.knap@diamond.ac.uk>
6
6
  License: Apache License
@@ -34,6 +34,7 @@ src/rtems_proxy/__init__.py
34
34
  src/rtems_proxy/__main__.py
35
35
  src/rtems_proxy/_version.py
36
36
  src/rtems_proxy/configure.py
37
+ src/rtems_proxy/connect.py
37
38
  src/rtems_proxy/copy.py
38
39
  src/rtems_proxy/globals.py
39
40
  src/rtems_proxy/rsync.sh.jinja
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes