You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@buildstream.apache.org by tv...@apache.org on 2021/02/05 09:46:21 UTC
[buildstream] 02/05: _remotespec.py: Adding
RemoteSpec.new_from_string()
This is an automated email from the ASF dual-hosted git repository.
tvb pushed a commit to branch tristan/remote-cli-options
in repository https://gitbox.apache.org/repos/asf/buildstream.git
commit b43b162e7cc132252ec71b50eea26ac9f16f9098
Author: Tristan van Berkom <tr...@codethink.co.uk>
AuthorDate: Fri Feb 5 16:01:27 2021 +0900
_remotespec.py: Adding RemoteSpec.new_from_string()
A class method for use by the frontend to instantiate RemoteSpec objects
from the command line.
---
src/buildstream/_remotespec.py | 128 ++++++++++++++++++++++++++++++++++++++++-
1 file changed, 125 insertions(+), 3 deletions(-)
diff --git a/src/buildstream/_remotespec.py b/src/buildstream/_remotespec.py
index e91fb55..a37698e 100644
--- a/src/buildstream/_remotespec.py
+++ b/src/buildstream/_remotespec.py
@@ -44,6 +44,20 @@ class RemoteType(FastEnum):
return ""
+# RemoteSpecPurpose():
+#
+# What a RemoteSpec is going to be used for.
+#
+# This is currently only used to control the behavior
+# of RemoteSpec.new_from_string(), after that, a RemoteSpec
+# has a `push` attribute which is either True or False.
+#
+class RemoteSpecPurpose(FastEnum):
+ ALL = 0 # Pushing and pulling
+ PUSH = 1 # Only pushing
+ PULL = 2 # Only pulling
+
+
# RemoteSpec():
#
# This data structure holds all of the details required to
@@ -252,6 +266,116 @@ class RemoteSpec:
spec_node=spec_node,
)
+ # new_from_string():
+ #
+ # Creates a RemoteSpec() from a string, used to parse CLI parameters
+ #
+ # If certificates are passed, they are interpreted as relative to the
+ # current working directory.
+ #
+ # Args:
+ # string: The user provided string
+ # purpose: The purpose this RemoteSpec is intended for (RemoteSpecPurpose)
+ #
+ # Returns:
+ # The described RemoteSpec instance.
+ #
+ # Raises:
+ # RemoteError: In case parsing the string fails
+ #
+ @classmethod
+ def new_from_string(cls, string: str, purpose: int = RemoteSpecPurpose.ALL) -> "RemoteSpec":
+ url: Optional[str] = None
+ instance_name: Optional[str] = None
+ remote_type: str = RemoteType.ALL
+ push: bool = True
+ server_cert: Optional[str] = None
+ client_key: Optional[str] = None
+ client_cert: Optional[str] = None
+
+ if purpose == RemoteSpecPurpose.PULL:
+ push = False
+
+ split = string.split(",")
+ if len(split) > 1:
+ for split_string in split:
+ subsplit = split_string.split("=")
+
+ if len(subsplit) != 2:
+ raise RemoteError(
+ "Invalid format '{}' found in remote specification: {}".format(split_string, string)
+ )
+
+ key: str = subsplit[0]
+ val: str = subsplit[1]
+
+ if key == "url":
+ url = val
+ elif key == "instance-name":
+ instance_name = val
+ elif key == "type":
+ remote_type = val
+ if remote_type not in [RemoteType.INDEX, RemoteType.STORAGE, RemoteType.ALL]:
+ raise RemoteError(
+ "Value for remote 'type' must be one of: {}".format(
+ ", ".join([RemoteType.INDEX, RemoteType.STORAGE, RemoteType.ALL])
+ )
+ )
+ elif key == "push":
+
+ # Provide a sensible error for `bst artifact push --remote url=http://pony.com,push=False ...`
+ if purpose != RemoteSpecPurpose.ALL:
+ raise RemoteError("The 'push' key is invalid and assumed to be {}".format(push))
+
+ if val in ("True", "true"):
+ push = True
+ elif val in ("False", "false"):
+ push = False
+ else:
+ raise RemoteError("Value for 'push' must be 'True' or 'False'")
+ elif key == "server-cert":
+ server_cert = cls._resolve_path(val, os.getcwd())
+ elif key == "client-key":
+ client_key = cls._resolve_path(val, os.getcwd())
+ elif key == "client-cert":
+ client_cert = cls._resolve_path(val, os.getcwd())
+ else:
+ raise RemoteError("Unexpected key '{}' encountered".format(key))
+ else:
+ # No commas, only the URL was specified
+ url = string
+
+ if not url:
+ raise RemoteError("No URL specified in remote")
+
+ return cls(
+ remote_type,
+ url,
+ push=push,
+ server_cert=server_cert,
+ client_key=client_key,
+ client_cert=client_cert,
+ instance_name=instance_name,
+ )
+
+ # _resolve_path()
+ #
+ # Resolve a path relative to the base directory
+ #
+ # Args:
+ # path: The path
+ # basedir: The base directory
+ #
+ # Returns:
+ # The resolved path
+ #
+ @classmethod
+ def _resolve_path(cls, path: str, basedir: Optional[str]) -> str:
+ path = os.path.expanduser(path)
+ if basedir:
+ path = os.path.join(basedir, path)
+ return path
+
# _parse_auth():
#
# Parse the "auth" data
@@ -276,9 +400,7 @@ class RemoteSpec:
for key in auth_keys:
value = auth_node.get_str(key, None)
if value:
- value = os.path.expanduser(value)
- if basedir:
- value = os.path.join(basedir, value)
+ value = cls._resolve_path(value, basedir)
auth_values[key] = value
server_cert = auth_values["server-cert"]