linode-cli 5.52.0__tar.gz → 5.52.2__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 (54) hide show
  1. {linode_cli-5.52.0/linode_cli.egg-info → linode_cli-5.52.2}/PKG-INFO +1 -1
  2. {linode_cli-5.52.0 → linode_cli-5.52.2/linode_cli.egg-info}/PKG-INFO +1 -1
  3. {linode_cli-5.52.0 → linode_cli-5.52.2}/linodecli/configuration/config.py +4 -7
  4. {linode_cli-5.52.0 → linode_cli-5.52.2}/linodecli/configuration/helpers.py +15 -1
  5. linode_cli-5.52.2/linodecli/data-3 +0 -0
  6. {linode_cli-5.52.0 → linode_cli-5.52.2}/linodecli/help_pages.py +2 -0
  7. {linode_cli-5.52.0 → linode_cli-5.52.2}/linodecli/overrides.py +52 -1
  8. {linode_cli-5.52.0 → linode_cli-5.52.2}/linodecli/plugins/get-kubeconfig.py +27 -19
  9. {linode_cli-5.52.0 → linode_cli-5.52.2}/linodecli/version.py +1 -1
  10. linode_cli-5.52.0/linodecli/data-3 +0 -0
  11. {linode_cli-5.52.0 → linode_cli-5.52.2}/LICENSE +0 -0
  12. {linode_cli-5.52.0 → linode_cli-5.52.2}/MANIFEST.in +0 -0
  13. {linode_cli-5.52.0 → linode_cli-5.52.2}/README.md +0 -0
  14. {linode_cli-5.52.0 → linode_cli-5.52.2}/linode_cli.egg-info/SOURCES.txt +0 -0
  15. {linode_cli-5.52.0 → linode_cli-5.52.2}/linode_cli.egg-info/dependency_links.txt +0 -0
  16. {linode_cli-5.52.0 → linode_cli-5.52.2}/linode_cli.egg-info/entry_points.txt +0 -0
  17. {linode_cli-5.52.0 → linode_cli-5.52.2}/linode_cli.egg-info/requires.txt +0 -0
  18. {linode_cli-5.52.0 → linode_cli-5.52.2}/linode_cli.egg-info/top_level.txt +0 -0
  19. {linode_cli-5.52.0 → linode_cli-5.52.2}/linodecli/__init__.py +0 -0
  20. {linode_cli-5.52.0 → linode_cli-5.52.2}/linodecli/__main__.py +0 -0
  21. {linode_cli-5.52.0 → linode_cli-5.52.2}/linodecli/api_request.py +0 -0
  22. {linode_cli-5.52.0 → linode_cli-5.52.2}/linodecli/arg_helpers.py +0 -0
  23. {linode_cli-5.52.0 → linode_cli-5.52.2}/linodecli/baked/__init__.py +0 -0
  24. {linode_cli-5.52.0 → linode_cli-5.52.2}/linodecli/baked/operation.py +0 -0
  25. {linode_cli-5.52.0 → linode_cli-5.52.2}/linodecli/baked/parsing.py +0 -0
  26. {linode_cli-5.52.0 → linode_cli-5.52.2}/linodecli/baked/request.py +0 -0
  27. {linode_cli-5.52.0 → linode_cli-5.52.2}/linodecli/baked/response.py +0 -0
  28. {linode_cli-5.52.0 → linode_cli-5.52.2}/linodecli/cli.py +0 -0
  29. {linode_cli-5.52.0 → linode_cli-5.52.2}/linodecli/completion.py +0 -0
  30. {linode_cli-5.52.0 → linode_cli-5.52.2}/linodecli/configuration/__init__.py +0 -0
  31. {linode_cli-5.52.0 → linode_cli-5.52.2}/linodecli/configuration/auth.py +0 -0
  32. {linode_cli-5.52.0 → linode_cli-5.52.2}/linodecli/exit_codes.py +0 -0
  33. {linode_cli-5.52.0 → linode_cli-5.52.2}/linodecli/helpers.py +0 -0
  34. {linode_cli-5.52.0 → linode_cli-5.52.2}/linodecli/oauth-landing-page.html +0 -0
  35. {linode_cli-5.52.0 → linode_cli-5.52.2}/linodecli/output/__init__.py +0 -0
  36. {linode_cli-5.52.0 → linode_cli-5.52.2}/linodecli/output/helpers.py +0 -0
  37. {linode_cli-5.52.0 → linode_cli-5.52.2}/linodecli/output/output_handler.py +0 -0
  38. {linode_cli-5.52.0 → linode_cli-5.52.2}/linodecli/plugins/__init__.py +0 -0
  39. {linode_cli-5.52.0 → linode_cli-5.52.2}/linodecli/plugins/firewall-editor.py +0 -0
  40. {linode_cli-5.52.0 → linode_cli-5.52.2}/linodecli/plugins/image-upload.py +0 -0
  41. {linode_cli-5.52.0 → linode_cli-5.52.2}/linodecli/plugins/metadata.py +0 -0
  42. {linode_cli-5.52.0 → linode_cli-5.52.2}/linodecli/plugins/obj/__init__.py +0 -0
  43. {linode_cli-5.52.0 → linode_cli-5.52.2}/linodecli/plugins/obj/buckets.py +0 -0
  44. {linode_cli-5.52.0 → linode_cli-5.52.2}/linodecli/plugins/obj/config.py +0 -0
  45. {linode_cli-5.52.0 → linode_cli-5.52.2}/linodecli/plugins/obj/helpers.py +0 -0
  46. {linode_cli-5.52.0 → linode_cli-5.52.2}/linodecli/plugins/obj/list.py +0 -0
  47. {linode_cli-5.52.0 → linode_cli-5.52.2}/linodecli/plugins/obj/objects.py +0 -0
  48. {linode_cli-5.52.0 → linode_cli-5.52.2}/linodecli/plugins/obj/website.py +0 -0
  49. {linode_cli-5.52.0 → linode_cli-5.52.2}/linodecli/plugins/plugins.py +0 -0
  50. {linode_cli-5.52.0 → linode_cli-5.52.2}/linodecli/plugins/region-table.py +0 -0
  51. {linode_cli-5.52.0 → linode_cli-5.52.2}/linodecli/plugins/ssh.py +0 -0
  52. {linode_cli-5.52.0 → linode_cli-5.52.2}/pyproject.toml +0 -0
  53. {linode_cli-5.52.0 → linode_cli-5.52.2}/setup.cfg +0 -0
  54. {linode_cli-5.52.0 → linode_cli-5.52.2}/setup.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: linode-cli
3
- Version: 5.52.0
3
+ Version: 5.52.2
4
4
  Summary: The official command-line interface for interacting with the Linode API.
5
5
  Author-email: "Akamai Technologies Inc." <developers@linode.com>
6
6
  License: BSD-3-Clause
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: linode-cli
3
- Version: 5.52.0
3
+ Version: 5.52.2
4
4
  Summary: The official command-line interface for interacting with the Linode API.
5
5
  Author-email: "Akamai Technologies Inc." <developers@linode.com>
6
6
  License: BSD-3-Clause
@@ -290,7 +290,10 @@ class CLIConfig:
290
290
  ):
291
291
  print(f"User {username} is not configured.")
292
292
  sys.exit(ExitCodes.USERNAME_ERROR)
293
- if not self.config.has_section(username) or allowed_defaults is None:
293
+ if (
294
+ not self.config.has_section(username)
295
+ and self.config.default_section is None
296
+ ) or allowed_defaults is None:
294
297
  return namespace
295
298
 
296
299
  warn_dict = {}
@@ -335,12 +338,6 @@ class CLIConfig:
335
338
  to save values they've set, and is used internally to update the config
336
339
  on disk when a new user if configured.
337
340
  """
338
-
339
- # Create the config path isf necessary
340
- config_path = f"{os.path.expanduser('~')}/.config"
341
- if not os.path.exists(config_path):
342
- os.makedirs(config_path)
343
-
344
341
  with open(_get_config_path(), "w", encoding="utf-8") as f:
345
342
  self.config.write(f)
346
343
 
@@ -15,6 +15,8 @@ CONFIG_DIR = os.environ.get(
15
15
  "XDG_CONFIG_HOME", f"{os.path.expanduser('~')}/.config"
16
16
  )
17
17
 
18
+ ENV_CONFIG_FILE_PATH = "LINODE_CLI_CONFIG"
19
+
18
20
  # this is a list of browser that _should_ work for web-based auth. This is mostly
19
21
  # intended to exclude lynx and other terminal browsers which could be opened, but
20
22
  # won't work.
@@ -38,11 +40,23 @@ def _get_config_path() -> str:
38
40
  :returns: The path to the local config file.
39
41
  :rtype: str
40
42
  """
43
+ custom_path = os.getenv(ENV_CONFIG_FILE_PATH, None)
44
+
45
+ if custom_path is not None:
46
+ custom_path = os.path.expanduser(custom_path)
47
+ if not os.path.exists(custom_path):
48
+ os.makedirs(os.path.dirname(custom_path), exist_ok=True)
49
+ return custom_path
50
+
41
51
  path = f"{LEGACY_CONFIG_DIR}/{LEGACY_CONFIG_NAME}"
42
52
  if os.path.exists(path):
43
53
  return path
44
54
 
45
- return f"{CONFIG_DIR}/{CONFIG_NAME}"
55
+ path = f"{CONFIG_DIR}/{CONFIG_NAME}"
56
+ if not os.path.exists(path):
57
+ os.makedirs(CONFIG_DIR, exist_ok=True)
58
+
59
+ return path
46
60
 
47
61
 
48
62
  def _get_config(load: bool = True):
Binary file
@@ -30,6 +30,8 @@ HELP_ENV_VARS = {
30
30
  "(e.g. 'v4beta')",
31
31
  "LINODE_CLI_API_SCHEME": "Overrides the target scheme used for API requests. "
32
32
  "(e.g. 'https')",
33
+ "LINODE_CLI_CONFIG": "Overrides the default configuration file path. "
34
+ "(e.g '~/.linode/my-cli-config')",
33
35
  }
34
36
 
35
37
  HELP_TOPICS = {
@@ -4,7 +4,7 @@ This allows us to easily alter per-command outputs, etc. without making
4
4
  large changes to the OpenAPI spec.
5
5
  """
6
6
 
7
- from typing import Dict
7
+ from typing import Dict, List
8
8
 
9
9
  from rich import box
10
10
  from rich import print as rprint
@@ -57,6 +57,15 @@ def handle_types_region_prices_list(
57
57
  return linode_types_with_region_prices(operation, output_handler, json_data)
58
58
 
59
59
 
60
+ @output_override("images", "replicate", OutputMode.table)
61
+ def handle_image_replicate(operation, output_handler, json_data) -> bool:
62
+ # pylint: disable=unused-argument
63
+ """
64
+ Override the output of 'linode-cli images replicate'.
65
+ """
66
+ return image_replicate_output(json_data)
67
+
68
+
60
69
  def linode_types_with_region_prices(
61
70
  operation, output_handler, json_data
62
71
  ) -> bool:
@@ -137,3 +146,45 @@ def format_region_prices(data: Dict[str, any]) -> any:
137
146
  sub_table.add_row(*region_price_row)
138
147
 
139
148
  return sub_table
149
+
150
+
151
+ def build_replicas_output(replicas: List) -> Table:
152
+ """
153
+ Format nested replicas list to a sub-table.
154
+ """
155
+ replicas_output = Table(show_header=False, box=None)
156
+ replicas_headers = replicas[0].keys()
157
+ for replica in replicas:
158
+ row = []
159
+ for h in replicas_headers:
160
+ row.append(Align(str(replica[h]), align="left"))
161
+ replicas_output.add_row(*row)
162
+
163
+ return replicas_output
164
+
165
+
166
+ def image_replicate_output(json_data) -> bool:
167
+ """
168
+ Parse and format the image replicate output table.
169
+ """
170
+ output = Table(
171
+ header_style="bold",
172
+ show_lines=True,
173
+ )
174
+
175
+ row = []
176
+ for header in json_data.keys():
177
+ if header == "regions" and len(json_data[header]) > 0:
178
+ # leverage `replicas` in output for readability
179
+ output.add_column("replicas", justify="center")
180
+ row.append(build_replicas_output(json_data[header]))
181
+ elif json_data[header] is not None:
182
+ output.add_column(header, justify="center")
183
+ row.append(Align(str(json_data[header]), align="left"))
184
+
185
+ output.add_row(*row)
186
+
187
+ console = Console()
188
+ console.print(output)
189
+
190
+ return False
@@ -90,7 +90,7 @@ def call(args, context):
90
90
  else cluster_config
91
91
  )
92
92
  if parsed.dry_run:
93
- print(cluster_config)
93
+ print(yaml.dump(cluster_config))
94
94
  else:
95
95
  _dump_config(kubeconfig_path, cluster_config)
96
96
 
@@ -146,27 +146,35 @@ def _dump_config(filepath, data):
146
146
  yaml.dump(data, file_descriptor)
147
147
 
148
148
 
149
- # Merges the lists in the provided dicts. If non-list properties of the two
150
- # dicts differ, uses the value from the first dict.
151
149
  def _merge_dict(dict_1, dict_2):
150
+ """
151
+ Merges two dicts:
152
+ * Lists that are present in both dicts are merged together by their "name" key
153
+ (preferring duplicate values in the first dict)
154
+ * `None` or missing keys in the first dict are set to the second dict's value
155
+ * Other values are preferred from the first dict
156
+ """
152
157
  # Return a new dict to prevent any accidental mutations
153
158
  result = {}
154
159
 
155
- for key in dict_1:
156
- if not isinstance(dict_1[key], list):
157
- result[key] = dict_1[key]
158
- continue
159
-
160
- merge_map = {sub["name"]: sub for sub in dict_1[key]}
161
-
162
- for sub in dict_2[key]:
163
- # If the name is already in the merge map, skip
164
- if sub["name"] in merge_map:
165
- continue
166
-
167
- merge_map[sub["name"]] = sub
168
-
169
- # Convert back to a list
170
- result[key] = list(merge_map.values())
160
+ for key, dict_1_value in dict_1.items():
161
+ if dict_1_value is None and (dict_2_value := dict_2.get(key)):
162
+ # Replace null value in previous config
163
+ result[key] = dict_2_value
164
+ elif isinstance(dict_1_value, list) and (
165
+ dict_2_value := dict_2.get(key)
166
+ ):
167
+ merge_map = {sub["name"]: sub for sub in dict_1_value}
168
+ for list_2_item in dict_2_value:
169
+ if (list_2_name := list_2_item["name"]) not in merge_map:
170
+ merge_map[list_2_name] = list_2_item
171
+ # Convert back to a list
172
+ result[key] = list(merge_map.values())
173
+ else:
174
+ result[key] = dict_1_value
175
+
176
+ # Process keys missing in dict_1
177
+ for key in set(dict_2.keys()).difference(dict_1.keys()):
178
+ result[key] = dict_2[key]
171
179
 
172
180
  return result
@@ -2,4 +2,4 @@
2
2
  The version of the Linode CLI.
3
3
  """
4
4
 
5
- __version__ = "v5.52.0"
5
+ __version__ = "v5.52.2"
Binary file
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes