File: //snap/google-cloud-cli/current/lib/surface/compute/images/packages/diff.py
# -*- coding: utf-8 -*- #
# Copyright 2018 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.
"""Command for diffing image packages."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
from googlecloudsdk.api_lib.compute import base_classes
from googlecloudsdk.api_lib.containeranalysis import util as containeranalysis_util
from googlecloudsdk.calliope import base
from googlecloudsdk.command_lib.compute.images.packages import exceptions
from googlecloudsdk.command_lib.compute.images.packages import filter_utils
from googlecloudsdk.command_lib.compute.images.packages import flags as package_flags
class Diff(base.ListCommand):
""" Displays the version differences of packages between two images."""
@staticmethod
def Args(parser):
parser.display_info.AddFormat("""\
table(
name:label=PACKAGE,
version_base:label=VERSION_BASE,
revision_base:label=REVISION_BASE,
version_diff:label=VERSION_DIFF,
revision_diff:label=REVISION_DIFF
)""")
# Add resource flags.
package_flags.AddResourceArgs(parser)
# Add filter flags.
package_flags.AddShowAddedPackagesFlag(parser)
package_flags.AddShowRemovedPackagesFlag(parser)
package_flags.AddShowUpdatedPackagesFlag(parser)
Diff._parser = parser
def _GetVersions(self, image_packages, image_name):
package_versions = {}
for occurrence in image_packages:
package_name = occurrence.installation.name
versions = []
for location in occurrence.installation.location:
versions.append((location.version.name, location.version.revision))
package_versions[package_name] = versions
if not package_versions:
raise exceptions.ImagePackagesInfoUnavailableException(image_name)
return package_versions
def _GetDiff(self, args, package_versions_base, package_versions_diff):
all_package_names = set(package_versions_base.keys()).union(
set(package_versions_diff.keys()))
show_all_diff_packages = True
if (args.show_added_packages or args.show_removed_packages or
args.show_updated_packages):
show_all_diff_packages = False
diff = []
empty = ('-', '-')
for package_name in all_package_names:
versions_base = package_versions_base.get(package_name, [])
versions_diff = package_versions_diff.get(package_name, [])
if set(versions_base) != set(versions_diff):
len_base = len(versions_base)
len_diff = len(versions_diff)
if (show_all_diff_packages or
(args.show_added_packages and len_base == 0 and len_diff != 0) or
(args.show_removed_packages and len_base != 0 and len_diff == 0) or
(args.show_updated_packages and len_base != 0 and len_diff != 0)):
for idx in range(max(len_base, len_diff)):
version_base, revision_base = versions_base[idx] if (
idx < len_base) else empty
version_diff, revision_diff = versions_diff[idx] if (
idx < len_diff) else empty
package_diff = {
'name': package_name,
'version_base': version_base,
'revision_base': revision_base,
'version_diff': version_diff,
'revision_diff': revision_diff
}
diff.append(package_diff)
return sorted(diff, key=lambda package_diff: package_diff['name'])
def Run(self, args):
"""Yields the differences of packages between two images."""
# If not specified, both base project and diff project are the user project.
base_image_ref = args.CONCEPTS.base_image.Parse()
diff_image_ref = args.CONCEPTS.diff_image.Parse()
# Use GA to construct the compute API holder since the containeranalysis
# API always call compute v1 API to refer the compute resources.
holder = base_classes.ComputeApiHolder(base.ReleaseTrack.GA)
resource_filter_base = filter_utils.GetFilter(base_image_ref, holder)
resource_filter_diff = filter_utils.GetFilter(diff_image_ref, holder)
image_packages_base = containeranalysis_util.MakeOccurrenceRequest(
project_id=base_image_ref.project, resource_filter=resource_filter_base,
occurrence_filter=None, resource_urls=None)
image_packages_diff = containeranalysis_util.MakeOccurrenceRequest(
project_id=diff_image_ref.project, resource_filter=resource_filter_diff,
occurrence_filter=None, resource_urls=None)
package_versions_base = self._GetVersions(image_packages_base,
args.base_image)
package_versions_diff = self._GetVersions(image_packages_diff,
args.diff_image)
return self._GetDiff(args, package_versions_base, package_versions_diff)