Use a _get_real_element() method in workspace commands

The _get_real_element() method is used in case some elements decide that
workspace commands should be redirected to another element.
diff --git a/buildstream/_frontend/cli.py b/buildstream/_frontend/cli.py
index c0bf741..6003b30 100644
--- a/buildstream/_frontend/cli.py
+++ b/buildstream/_frontend/cli.py
@@ -618,7 +618,7 @@
 def workspace_open(app, no_checkout, force, track_, element, directory):
     """Open a workspace for manual source modification"""
 
-    app.initialize((element,), rewritable=track_, track_elements=[element] if track_ else None)
+    app.initialize((element,), rewritable=track_)
     try:
         app.pipeline.open_workspace(app.scheduler, directory, no_checkout, track_, force)
         click.echo("", err=True)
@@ -641,7 +641,10 @@
 
     app.initialize((element,))
 
-    if app.pipeline.project._get_workspace(app.pipeline.targets[0].name) is None:
+    target = app.pipeline.targets[0]
+    target = target._get_real_element()
+
+    if app.pipeline.project._get_workspace(target.name) is None:
         click.echo("ERROR: Workspace '{}' does not exist".format(element), err=True)
         sys.exit(-1)
 
diff --git a/buildstream/_pipeline.py b/buildstream/_pipeline.py
index d4f65b4..18bef5c 100644
--- a/buildstream/_pipeline.py
+++ b/buildstream/_pipeline.py
@@ -616,6 +616,15 @@
     def open_workspace(self, scheduler, directory, no_checkout, track_first, force):
         # When working on workspaces we only have one target
         target = self.targets[0]
+
+        # Some elements act as proxies for other elements
+        target = target._get_real_element()
+
+        # Ordinarily, this would be done by pipeline initialization, but we need the
+        # elements initialized before we know which ones to track.
+        if track_first:
+            self.resolve_cache_keys([target.name])
+
         workdir = os.path.abspath(directory)
 
         if not list(target.sources()):
@@ -698,6 +707,9 @@
         # When working on workspaces we only have one target
         target = self.targets[0]
 
+        # Some elements act as proxies for other elements
+        target = target._get_real_element()
+
         # Remove workspace directory if prompted
         if remove_dir:
             path = self.project._get_workspace(target.name)
@@ -738,6 +750,10 @@
     def reset_workspace(self, scheduler, track, no_checkout):
         # When working on workspaces we only have one target
         target = self.targets[0]
+
+        # Some elements act as proxies for other elements
+        target = target._get_real_element()
+
         workspace_dir = self.project._get_workspace(target.name)
 
         if workspace_dir is None:
diff --git a/buildstream/element.py b/buildstream/element.py
index b62945f..f1f34b3 100644
--- a/buildstream/element.py
+++ b/buildstream/element.py
@@ -1958,6 +1958,9 @@
     def _subst_string(self, value):
         return self.__variables.subst(value)
 
+    def _get_real_element(self):
+        return self
+
 
 def _overlap_error_detail(f, forbidden_overlap_elements, elements):
     if forbidden_overlap_elements: