RemoteRF 0.0.7.48__tar.gz → 0.0.7.52__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 (37) hide show
  1. {remoterf-0.0.7.48/src/remoteRF.egg-info → remoterf-0.0.7.52}/PKG-INFO +1 -1
  2. {remoterf-0.0.7.48 → remoterf-0.0.7.52}/setup.py +5 -5
  3. remoterf-0.0.7.48/src/remoteRF/config/config_cli.py → remoterf-0.0.7.52/src/remoteRF/config/config.py +30 -69
  4. {remoterf-0.0.7.48 → remoterf-0.0.7.52}/src/remoteRF/core/acc_login.py +1 -1
  5. {remoterf-0.0.7.48 → remoterf-0.0.7.52}/src/remoteRF/core/version.py +1 -1
  6. remoterf-0.0.7.52/src/remoteRF/remoterf_cli.py +203 -0
  7. {remoterf-0.0.7.48 → remoterf-0.0.7.52/src/remoteRF.egg-info}/PKG-INFO +1 -1
  8. {remoterf-0.0.7.48 → remoterf-0.0.7.52}/src/remoteRF.egg-info/SOURCES.txt +2 -2
  9. remoterf-0.0.7.52/src/remoteRF.egg-info/entry_points.txt +2 -0
  10. remoterf-0.0.7.48/src/remoteRF/cli.py +0 -141
  11. remoterf-0.0.7.48/src/remoteRF.egg-info/entry_points.txt +0 -5
  12. {remoterf-0.0.7.48 → remoterf-0.0.7.52}/LICENSE +0 -0
  13. {remoterf-0.0.7.48 → remoterf-0.0.7.52}/MANIFEST.in +0 -0
  14. {remoterf-0.0.7.48 → remoterf-0.0.7.52}/README.md +0 -0
  15. {remoterf-0.0.7.48 → remoterf-0.0.7.52}/setup.cfg +0 -0
  16. {remoterf-0.0.7.48 → remoterf-0.0.7.52}/src/remoteRF/__init__.py +0 -0
  17. {remoterf-0.0.7.48 → remoterf-0.0.7.52}/src/remoteRF/common/__init__.py +0 -0
  18. {remoterf-0.0.7.48 → remoterf-0.0.7.52}/src/remoteRF/common/grpc/__init__.py +0 -0
  19. {remoterf-0.0.7.48 → remoterf-0.0.7.52}/src/remoteRF/common/grpc/grpc_pb2.py +0 -0
  20. {remoterf-0.0.7.48 → remoterf-0.0.7.52}/src/remoteRF/common/grpc/grpc_pb2_grpc.py +0 -0
  21. {remoterf-0.0.7.48 → remoterf-0.0.7.52}/src/remoteRF/common/utils/__init__.py +0 -0
  22. {remoterf-0.0.7.48 → remoterf-0.0.7.52}/src/remoteRF/common/utils/ansi_codes.py +0 -0
  23. {remoterf-0.0.7.48 → remoterf-0.0.7.52}/src/remoteRF/common/utils/api_token.py +0 -0
  24. {remoterf-0.0.7.48 → remoterf-0.0.7.52}/src/remoteRF/common/utils/list_string.py +0 -0
  25. {remoterf-0.0.7.48 → remoterf-0.0.7.52}/src/remoteRF/common/utils/process_arg.py +0 -0
  26. {remoterf-0.0.7.48 → remoterf-0.0.7.52}/src/remoteRF/config/__init__.py +0 -0
  27. {remoterf-0.0.7.48 → remoterf-0.0.7.52}/src/remoteRF/config/cert_fetcher.py +0 -0
  28. {remoterf-0.0.7.48 → remoterf-0.0.7.52}/src/remoteRF/core/__init__.py +0 -0
  29. {remoterf-0.0.7.48 → remoterf-0.0.7.52}/src/remoteRF/core/app.py +0 -0
  30. {remoterf-0.0.7.48 → remoterf-0.0.7.52}/src/remoteRF/core/grpc_acc.py +0 -0
  31. {remoterf-0.0.7.48 → remoterf-0.0.7.52}/src/remoteRF/core/grpc_client.py +0 -0
  32. {remoterf-0.0.7.48 → remoterf-0.0.7.52}/src/remoteRF/drivers/__init__.py +0 -0
  33. {remoterf-0.0.7.48 → remoterf-0.0.7.52}/src/remoteRF/drivers/adalm_pluto/__init__.py +0 -0
  34. {remoterf-0.0.7.48 → remoterf-0.0.7.52}/src/remoteRF/drivers/adalm_pluto/pluto_remote.py +0 -0
  35. {remoterf-0.0.7.48 → remoterf-0.0.7.52}/src/remoteRF.egg-info/dependency_links.txt +0 -0
  36. {remoterf-0.0.7.48 → remoterf-0.0.7.52}/src/remoteRF.egg-info/requires.txt +0 -0
  37. {remoterf-0.0.7.48 → remoterf-0.0.7.52}/src/remoteRF.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: remoterf
3
- Version: 0.0.7.48
3
+ Version: 0.0.7.52
4
4
  Summary: A python API to remotely access signal centric hardware. Client-side only! Courtesy of Wireless Lab @ UCLA & Prof. Ian Roberts.
5
5
  Author: Ethan Ge
6
6
  Author-email: ethoGalaxy@gmail.com
@@ -6,7 +6,7 @@ with open("README.md", "r", encoding="utf-8") as fh:
6
6
 
7
7
  setup(
8
8
  name="remoterf",
9
- version="0.0.7.48",
9
+ version="0.0.7.52",
10
10
  author="Ethan Ge",
11
11
  author_email="ethoGalaxy@gmail.com",
12
12
  description="A python API to remotely access signal centric hardware. Client-side only! Courtesy of Wireless Lab @ UCLA & Prof. Ian Roberts.",
@@ -35,10 +35,10 @@ setup(
35
35
 
36
36
  entry_points={
37
37
  "console_scripts": [
38
- "remoterf=remoteRF.cli:main",
39
- "remoterf-login=remoteRF.core.acc_login:main",
40
- "remoterf-v=remoteRF.core.version:main",
41
- "remoterf-config=remoteRF.config.config_cli:main",
38
+ "remoterf=remoteRF.remoterf_cli:main",
39
+ # "remoterf-login=remoteRF.core.acc_login:main",
40
+ # "remoterf-v=remoteRF.core.version:main",
41
+ # "remoterf-config=remoteRF.config.config_cli:main",
42
42
  ],
43
43
  },
44
44
 
@@ -6,10 +6,13 @@ import os
6
6
  import sys
7
7
  import shutil
8
8
  from pathlib import Path
9
- from typing import Tuple
9
+ from typing import Optional, Sequence, Tuple
10
+ import argparse
10
11
 
11
12
  from .cert_fetcher import fetch_and_save_ca_cert
12
13
 
14
+
15
+
13
16
  # -----------------------------
14
17
  # Local config locations
15
18
  # -----------------------------
@@ -71,72 +74,19 @@ def _wipe_config(root: Path) -> None:
71
74
  shutil.rmtree(root)
72
75
  print(f"Wiped RemoteRF config: {root}")
73
76
 
74
- def main(argv=None) -> None:
75
- import argparse
76
-
77
- parser = argparse.ArgumentParser(
78
- prog="remoterf-config",
79
- add_help=True,
80
- formatter_class=argparse.RawTextHelpFormatter,
81
- description=(
82
- "Configure RemoteRF to talk to a server.\n"
83
- "Fetches the server CA certificate and saves the gRPC target locally."
84
- ),
85
- )
86
-
87
- parser.add_argument(
88
- "addr",
89
- nargs="?",
90
- help="Server address in host:port form. Example: 164.67.195.207:61005",
91
- )
92
-
93
- parser.add_argument(
94
- "--wipe",
95
- action="store_true",
96
- help="Delete ALL existing RemoteRF config at ~/.config/remoterf and exit.",
97
- )
98
-
99
- parser.add_argument(
100
- "--yes",
101
- action="store_true",
102
- help="Skip confirmation prompts (use with --wipe).",
103
- )
104
-
105
- args = parser.parse_args()
106
-
107
- # ----- Wipe mode -----
108
- if args.wipe:
109
- root = _config_root()
110
- if not args.yes:
111
- if not _confirm_wipe(root):
112
- print("Wipe aborted.")
113
- sys.exit(1)
114
- try:
115
- _wipe_config(root)
116
- sys.exit(0)
117
- except Exception as e:
118
- print(f"Error wiping config: {e}", file=sys.stderr)
119
- sys.exit(1)
120
-
121
- # ----- Normal configure mode -----
122
- if not args.addr:
123
- print(
124
- "\nError: missing required argument: host:port\n\n"
125
- "Usage:\n"
126
- " remoterf-config <host:port>\n"
127
- " remoterf-config --wipe [--yes]\n\n"
128
- "Example:\n"
129
- " remoterf-config 164.67.195.207:61005\n"
130
- )
131
- sys.exit(2)
77
+ def configure(host: str, port: int, cert_port: int) -> int:
78
+ # Basic validation
79
+ host = (host or "").strip()
80
+ if not host:
81
+ print("Error: host is empty", file=sys.stderr)
82
+ return 2
83
+ if port <= 0 or port > 65535:
84
+ print("Error: port out of range", file=sys.stderr)
85
+ return 2
132
86
 
133
- try:
134
- host, grpc_port = _parse_hostport(args.addr)
135
- except Exception as e:
136
- print(f"Error: invalid addr '{args.addr}': {e}", file=sys.stderr)
137
- sys.exit(2)
87
+ grpc_port = int(port)
88
+ cert_port = int(cert_port)
138
89
 
139
- cert_port = grpc_port + 1
140
90
  profile = "default"
141
91
  timeout_sec = 3.0
142
92
  overwrite = True
@@ -152,10 +102,9 @@ def main(argv=None) -> None:
152
102
  timeout_sec=timeout_sec,
153
103
  overwrite=overwrite,
154
104
  )
155
-
156
105
  if not fetched_ok:
157
106
  print(f"Failed to fetch CA cert from {host}:{cert_port}.", file=sys.stderr)
158
- sys.exit(1)
107
+ return 1
159
108
 
160
109
  env_file = _env_path()
161
110
  _write_env_kv(env_file, {
@@ -170,5 +119,17 @@ def main(argv=None) -> None:
170
119
  print(f" CA cert : {ca_out}")
171
120
  print(f" env file : {env_file}")
172
121
 
173
- if __name__ == "__main__":
174
- main()
122
+ def wipe_config(*, yes: bool = False) -> int:
123
+ """
124
+ Optional helper if you want wipe behavior without argparse.
125
+ """
126
+ root = _config_root()
127
+ if not yes and not _confirm_wipe(root):
128
+ print("Wipe aborted.")
129
+ return 1
130
+ try:
131
+ _wipe_config(root)
132
+ return 0
133
+ except Exception as e:
134
+ print(f"Error wiping config: {e}", file=sys.stderr)
135
+ return 1
@@ -1,4 +1,4 @@
1
1
  from . import app as client
2
2
 
3
- def main(argv=None):
3
+ def main():
4
4
  pass
@@ -1,6 +1,6 @@
1
1
  from importlib.metadata import version, PackageNotFoundError
2
2
 
3
- def main(argv=None):
3
+ def main():
4
4
  try:
5
5
  v = version("remoterf")
6
6
  except PackageNotFoundError:
@@ -0,0 +1,203 @@
1
+ # src/remoteRF/cli.py
2
+ from __future__ import annotations
3
+
4
+ import argparse
5
+ import sys
6
+ from typing import Optional, Sequence
7
+
8
+ import sys
9
+
10
+ from pathlib import Path
11
+
12
+ def _config_root() -> Path:
13
+ return Path.home() / ".config" / "remoterf"
14
+
15
+ def _env_path() -> Path:
16
+ return _config_root() / ".env"
17
+
18
+ def _read_dotenv_kv(path: Path) -> dict[str, str]:
19
+ """
20
+ Tiny dotenv reader (KEY=VALUE lines). Good enough for your use-case.
21
+ """
22
+ out: dict[str, str] = {}
23
+ if not path.exists():
24
+ return out
25
+
26
+ for raw in path.read_text(encoding="utf-8").splitlines():
27
+ line = raw.strip()
28
+ if not line or line.startswith("#") or "=" not in line:
29
+ continue
30
+ k, v = line.split("=", 1)
31
+ k = k.strip()
32
+ v = v.strip().strip('"').strip("'")
33
+ out[k] = v
34
+ return out
35
+
36
+ def _ensure_config_present() -> tuple[bool, str]:
37
+ env_file = _env_path()
38
+ if not env_file.exists():
39
+ return (
40
+ False,
41
+ "RemoteRF is not configured.\n"
42
+ "Run:\n"
43
+ " remoterf --config --addr <host:port>\n"
44
+ "Example:\n"
45
+ " remoterf --config --addr 123.45.654.321:12321\n",
46
+ )
47
+
48
+ kv = _read_dotenv_kv(env_file)
49
+ addr = kv.get("REMOTERF_ADDR", "").strip()
50
+ ca = kv.get("REMOTERF_CA_CERT", "").strip()
51
+
52
+ if not addr or not ca:
53
+ return (
54
+ False,
55
+ "RemoteRF config is incomplete.\n"
56
+ f"Expected REMOTERF_ADDR and REMOTERF_CA_CERT in:\n {env_file}\n"
57
+ "Fix by re-running:\n"
58
+ " remoterf --config --addr <host:port>\n",
59
+ )
60
+
61
+ ca_path = Path(ca).expanduser()
62
+ if not ca_path.exists():
63
+ return (
64
+ False,
65
+ "RemoteRF config points to a missing CA certificate.\n"
66
+ f"REMOTERF_CA_CERT={ca}\n"
67
+ "Fix by re-running:\n"
68
+ " remoterf --config --addr <host:port>\n",
69
+ )
70
+
71
+ return True, ""
72
+
73
+ def print_help() -> None:
74
+ print(
75
+ "RemoteRF CLI Help\n"
76
+ "\n"
77
+ "Usage:\n"
78
+ " remoterf Show this help\n"
79
+ " remoterf -h | --help Show this help\n"
80
+ "\n"
81
+ " remoterf -l | --login Login / register\n"
82
+ " remoterf -v | --version Print version\n"
83
+ "\n"
84
+ " remoterf -c | --config [options]\n"
85
+ " -a, --addr, -addr <host:port> Set target server \n"
86
+ " -w, --wipe, -wipe Delete all local config\n"
87
+ " -y, --yes, -yes Skip wipe confirmation\n"
88
+ "\n"
89
+ "Examples:\n"
90
+ " remoterf --login\n"
91
+ " remoterf --version\n"
92
+ " remoterf --config --addr 123.45.654.321:12321\n"
93
+ " remoterf --config --wipe\n"
94
+ " remoterf --config --wipe --yes\n"
95
+ )
96
+
97
+ def main() -> int:
98
+ argv = list(sys.argv[1:])
99
+
100
+ # ---- Debug ----
101
+ # print(f"argc={len(argv)}")
102
+ # for i, a in enumerate(argv):
103
+ # print(f"argv[{i}] = {a!r}")
104
+
105
+ if len(argv) == 0 or argv[0] in ("--help", "-help", "-h"):
106
+ print_help()
107
+ return 0
108
+
109
+ if argv[0] in ("--login", "-login", "-l"):
110
+ ok, msg = _ensure_config_present()
111
+ if not ok:
112
+ print(msg)
113
+ return 2
114
+
115
+ from remoteRF.core.acc_login import main as _
116
+ return 0
117
+
118
+ if argv[0] in ("--version", "-version", "-v"):
119
+ from remoteRF.core.version import main as version_main
120
+
121
+ print("RemoteRF version:", end=" ")
122
+ version_main()
123
+ return 0
124
+
125
+ if argv[0] in ("--config", "-config", "-c"):
126
+ from remoteRF.config.config import configure, wipe_config
127
+
128
+ addr = None
129
+ wipe = False
130
+ yes = False
131
+
132
+ i = 1
133
+ while i < len(argv):
134
+ tok = argv[i]
135
+
136
+ if tok in ("--addr", "-a", "-addr"):
137
+ if i + 1 >= len(argv):
138
+ print("ERROR: missing required argument after --addr/-a/-addr")
139
+ return 2
140
+ addr = argv[i + 1]
141
+ i += 2
142
+ continue
143
+
144
+ if tok in ("--wipe", "-w", "-wipe"):
145
+ wipe = True
146
+ i += 1
147
+ continue
148
+
149
+ if tok in ("--yes", "-y", "-yes"):
150
+ yes = True
151
+ i += 1
152
+ continue
153
+
154
+ print(f"ERROR: unknown config argument: {tok!r}")
155
+ return 2
156
+
157
+ # Mirror remoterf-config behavior:
158
+ if wipe and addr is not None:
159
+ print("ERROR: cannot use --wipe and --addr together")
160
+ return 2
161
+
162
+ if wipe:
163
+ # wipe_config returns the proper exit code
164
+ return int(wipe_config(yes=yes))
165
+
166
+ if addr is not None:
167
+ # parse host:port (minimal, strict)
168
+ s = addr.strip()
169
+ if "://" in s:
170
+ s = s.split("://", 1)[1]
171
+ if ":" not in s:
172
+ print("ERROR: addr must be in 'host:port' form")
173
+ return 2
174
+
175
+ host, port_str = s.rsplit(":", 1)
176
+ host = host.strip()
177
+ try:
178
+ port = int(port_str.strip())
179
+ except Exception:
180
+ print("ERROR: port must be an integer")
181
+ return 2
182
+
183
+ # configure returns the proper exit code
184
+ cert_port = port + 1
185
+ configure(host, port, cert_port)
186
+ return 0
187
+
188
+ # No args -> same behavior as remoterf-config missing addr (exit code 2)
189
+ print(
190
+ "\nError: missing required argument: host:port\n\n"
191
+ "Usage:\n"
192
+ " remoterf --config --addr <host:port>\n"
193
+ " remoterf -c -a <host:port>\n"
194
+ " remoterf --config --wipe [--yes]\n\n"
195
+ "Example:\n"
196
+ " remoterf --config --addr 123.45.678.901:12345\n"
197
+ )
198
+ return 2
199
+
200
+
201
+ # fallback
202
+ print(f"ERROR: unknown command: {argv[0]!r}")
203
+ return 2
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: remoterf
3
- Version: 0.0.7.48
3
+ Version: 0.0.7.52
4
4
  Summary: A python API to remotely access signal centric hardware. Client-side only! Courtesy of Wireless Lab @ UCLA & Prof. Ian Roberts.
5
5
  Author: Ethan Ge
6
6
  Author-email: ethoGalaxy@gmail.com
@@ -3,7 +3,7 @@ MANIFEST.in
3
3
  README.md
4
4
  setup.py
5
5
  src/remoteRF/__init__.py
6
- src/remoteRF/cli.py
6
+ src/remoteRF/remoterf_cli.py
7
7
  src/remoteRF.egg-info/PKG-INFO
8
8
  src/remoteRF.egg-info/SOURCES.txt
9
9
  src/remoteRF.egg-info/dependency_links.txt
@@ -21,7 +21,7 @@ src/remoteRF/common/utils/list_string.py
21
21
  src/remoteRF/common/utils/process_arg.py
22
22
  src/remoteRF/config/__init__.py
23
23
  src/remoteRF/config/cert_fetcher.py
24
- src/remoteRF/config/config_cli.py
24
+ src/remoteRF/config/config.py
25
25
  src/remoteRF/core/__init__.py
26
26
  src/remoteRF/core/acc_login.py
27
27
  src/remoteRF/core/app.py
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ remoterf = remoteRF.remoterf_cli:main
@@ -1,141 +0,0 @@
1
- # src/remoteRF/cli.py
2
- from __future__ import annotations
3
-
4
- import argparse
5
- import sys
6
- from typing import Optional, Sequence
7
-
8
- from remoteRF.core.acc_login import main as login_main
9
- from remoteRF.core.version import main as version_main
10
- from remoteRF.config.config_cli import main as config_main
11
-
12
-
13
- def build_parser() -> argparse.ArgumentParser:
14
- p = argparse.ArgumentParser(
15
- prog="remoterf",
16
- formatter_class=argparse.RawTextHelpFormatter,
17
- add_help=True,
18
- description=(
19
- "RemoteRF unified CLI\n\n"
20
- "Examples:\n"
21
- " remoterf --login\n"
22
- " remoterf -l\n"
23
- " remoterf --config --addr 164.67.195.207:61005\n"
24
- " remoterf -c -a 164.67.195.207:61005\n"
25
- " remoterf --config --wipe\n"
26
- " remoterf -v\n"
27
- ),
28
- )
29
-
30
- mode = p.add_mutually_exclusive_group()
31
-
32
- mode.add_argument("-l", "--login", action="store_true", help="Login / register (interactive).")
33
- mode.add_argument("-c", "--config", action="store_true", help="Configure server target / CA cert.")
34
- mode.add_argument("-v", "--version", action="store_true", help="Print version and exit.")
35
-
36
- # These are only meaningful with --config, but we accept them at top-level
37
- # so your UX works as requested.
38
- p.add_argument(
39
- "-a", "--addr", "-addr",
40
- dest="addr",
41
- default=None,
42
- help="Server address (host:port). Used with --config / -c.",
43
- )
44
-
45
- p.add_argument(
46
- "-w", "--wipe",
47
- action="store_true",
48
- help="Wipe local config (~/.config/remoterf). Used with --config / -c.",
49
- )
50
-
51
- p.add_argument(
52
- "--yes",
53
- action="store_true",
54
- help="Skip confirmation prompts (use with --config --wipe).",
55
- )
56
-
57
- return p
58
-
59
-
60
- def main(argv: Optional[Sequence[str]] = None) -> int:
61
- argv = list(sys.argv[1:] if argv is None else argv)
62
-
63
- parser = build_parser()
64
-
65
- # No args => help panel
66
- if len(argv) == 0:
67
- parser.print_help()
68
- return 0
69
-
70
- args, extra = parser.parse_known_args(argv)
71
-
72
- # --- Version ---
73
- if args.version:
74
- if extra:
75
- parser.error(f"Unexpected arguments for --version: {' '.join(extra)}")
76
- # If your version_main supports argv, pass [].
77
- try:
78
- version_main([])
79
- except TypeError:
80
- version_main()
81
- return 0
82
-
83
- # --- Login ---
84
- if args.login:
85
- if extra:
86
- parser.error(f"Unexpected arguments for --login: {' '.join(extra)}")
87
- try:
88
- login_main([])
89
- except TypeError:
90
- login_main()
91
- return 0
92
-
93
- # --- Config ---
94
- if args.config:
95
- cfg_argv: list[str] = []
96
-
97
- # Normalize to whatever config_cli expects.
98
- # If your config_cli supports --wipe/--yes, pass them through.
99
- if args.wipe:
100
- cfg_argv.append("--wipe")
101
- if args.yes:
102
- cfg_argv.append("--yes")
103
-
104
- # Address handling
105
- if args.addr:
106
- # If config_cli expects a positional addr, pass it positionally:
107
- cfg_argv.append(args.addr)
108
- # If your config_cli instead expects --addr, switch to:
109
- # cfg_argv += ["--addr", args.addr]
110
-
111
- # Preserve any extra args for config_cli (if you want)
112
- cfg_argv += extra
113
-
114
- # If neither addr nor wipe was supplied, show config help-like message.
115
- if not args.addr and not args.wipe and len(extra) == 0:
116
- # Call config_cli with --help if it supports it; otherwise print ours.
117
- try:
118
- config_main(["--help"])
119
- except Exception:
120
- parser.error("Config mode requires --addr <host:port> or --wipe.")
121
- return 0
122
-
123
- try:
124
- config_main(cfg_argv)
125
- except TypeError:
126
- # Fallback if config_main does not accept argv; last resort:
127
- old = sys.argv[:]
128
- try:
129
- sys.argv = ["remoterf-config", *cfg_argv]
130
- config_main()
131
- finally:
132
- sys.argv = old
133
- return 0
134
-
135
- # If user passed only -a/-w without -c/--config, show help
136
- parser.print_help()
137
- return 0
138
-
139
-
140
- if __name__ == "__main__":
141
- raise SystemExit(main())
@@ -1,5 +0,0 @@
1
- [console_scripts]
2
- remoterf = remoteRF.cli:main
3
- remoterf-config = remoteRF.config.config_cli:main
4
- remoterf-login = remoteRF.core.acc_login:main
5
- remoterf-v = remoteRF.core.version:main
File without changes
File without changes
File without changes
File without changes