129 lines
5.3 KiB
Python
129 lines
5.3 KiB
Python
# -*- 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)
|