File: //snap/google-cloud-cli/396/lib/googlecloudsdk/calliope/command_release_tracks.py
# -*- coding: utf-8 -*- #
# Copyright 2019 Google LLC. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""Helpers to separate release tracks in declarative commands."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
import copy
from googlecloudsdk.calliope import base
ALL_TRACKS = [t.id for t in base.ReleaseTrack.AllValues()]
RELEASE_TRACKS = 'release_tracks'
GROUP = 'group'
class DoesNotExistForTrackError(Exception):
pass
# This function should be kept in sync with function in
# cloud/sdk/surface_specs/release_tracks.py
def _SetValuesForTrack(obj, track):
"""Recursively modify an object to have only values for the provided track.
Args:
obj: The object to modify.
track: The track to extract the values for.
Returns:
The modified object
Raises:
DoesNotExistForTrackError: if the object does not exist for the track.
"""
if isinstance(obj, dict):
is_group = GROUP in obj
# Check if it exists for this track, and raise an Exception if it doesn't.
if RELEASE_TRACKS in obj:
if track not in obj[RELEASE_TRACKS]:
raise DoesNotExistForTrackError()
del obj[RELEASE_TRACKS]
# Copy tracked properties for this track to the object itself.
if track in obj:
for key, value in obj[track].items():
obj[key] = value
# Remove all tracked properties
for track_key in ALL_TRACKS:
if track_key in obj:
del obj[track_key]
# Recursively update all children.
# Remove them if they don't exist for the track.
for key, child in list(obj.items()):
try:
_SetValuesForTrack(child, track)
except DoesNotExistForTrackError:
del obj[key]
if is_group and not obj:
# All of the children have been omitted for an arg group nested under the
# `group` key.
raise DoesNotExistForTrackError()
elif isinstance(obj, list):
# Recursively update all children.
# Remove them if they don't exist for the track.
children = list(obj)
obj[:] = []
for child in children:
try:
obj.append(_SetValuesForTrack(child, track))
except DoesNotExistForTrackError:
pass
return obj
def SeparateDeclarativeCommandTracks(command_impls):
"""Separate combined track definitions.
If a file does not specify tracks, the same implementation may be used for
all track implementations the command is present in.
Args:
command_impls: A single or list of declarative command implementation(s).
Yields:
One implementation for each distinct track implmentation in a file.
"""
if not isinstance(command_impls, list):
command_impls = [command_impls]
for impl in command_impls:
release_tracks = impl.get(RELEASE_TRACKS)
if not release_tracks:
release_tracks = ['ALPHA', 'BETA', 'GA']
for track in release_tracks:
track_impl = copy.deepcopy(impl)
try:
_SetValuesForTrack(track_impl, track)
except DoesNotExistForTrackError:
# The implementation doesn't have any keys left.
# continue
pass
track_impl[RELEASE_TRACKS] = [track]
yield track_impl