zotregistry.dev/zot@v1.4.4-0.20240314164342-eec277e14d20/pkg/meta/convert/convert.go (about)

     1  package convert
     2  
     3  import (
     4  	"time"
     5  
     6  	godigest "github.com/opencontainers/go-digest"
     7  	"github.com/opencontainers/image-spec/specs-go"
     8  	ispec "github.com/opencontainers/image-spec/specs-go/v1"
     9  	"google.golang.org/protobuf/types/known/timestamppb"
    10  
    11  	"zotregistry.dev/zot/pkg/common"
    12  	proto_go "zotregistry.dev/zot/pkg/meta/proto/gen"
    13  	mTypes "zotregistry.dev/zot/pkg/meta/types"
    14  )
    15  
    16  func GetHistory(history []*proto_go.History) []ispec.History {
    17  	if history == nil {
    18  		return nil
    19  	}
    20  
    21  	results := make([]ispec.History, 0, len(history))
    22  
    23  	for _, his := range history {
    24  		results = append(results, ispec.History{
    25  			Created:    ref(his.Created.AsTime()),
    26  			CreatedBy:  deref(his.CreatedBy, ""),
    27  			Author:     deref(his.Author, ""),
    28  			Comment:    deref(his.Comment, ""),
    29  			EmptyLayer: deref(his.EmptyLayer, false),
    30  		})
    31  	}
    32  
    33  	return results
    34  }
    35  
    36  func GetImageArtifactType(imageMeta *proto_go.ImageMeta) string {
    37  	switch imageMeta.MediaType {
    38  	case ispec.MediaTypeImageManifest:
    39  		manifestArtifactType := deref(imageMeta.Manifests[0].Manifest.ArtifactType, "")
    40  		if manifestArtifactType != "" {
    41  			return manifestArtifactType
    42  		}
    43  
    44  		return imageMeta.Manifests[0].Manifest.Config.MediaType
    45  	case ispec.MediaTypeImageIndex:
    46  		return deref(imageMeta.Index.Index.ArtifactType, "")
    47  	default:
    48  		return ""
    49  	}
    50  }
    51  
    52  func GetImageManifestSize(imageMeta *proto_go.ImageMeta) int64 {
    53  	switch imageMeta.MediaType {
    54  	case ispec.MediaTypeImageManifest:
    55  		return imageMeta.Manifests[0].Size
    56  	case ispec.MediaTypeImageIndex:
    57  		return imageMeta.Index.Size
    58  	default:
    59  		return 0
    60  	}
    61  }
    62  
    63  func GetImageDigest(imageMeta *proto_go.ImageMeta) godigest.Digest {
    64  	switch imageMeta.MediaType {
    65  	case ispec.MediaTypeImageManifest:
    66  		return godigest.Digest(imageMeta.Manifests[0].Digest)
    67  	case ispec.MediaTypeImageIndex:
    68  		return godigest.Digest(imageMeta.Index.Digest)
    69  	default:
    70  		return ""
    71  	}
    72  }
    73  
    74  func GetImageDigestStr(imageMeta *proto_go.ImageMeta) string {
    75  	switch imageMeta.MediaType {
    76  	case ispec.MediaTypeImageManifest:
    77  		return imageMeta.Manifests[0].Digest
    78  	case ispec.MediaTypeImageIndex:
    79  		return imageMeta.Index.Digest
    80  	default:
    81  		return ""
    82  	}
    83  }
    84  
    85  func GetImageAnnotations(imageMeta *proto_go.ImageMeta) map[string]string {
    86  	switch imageMeta.MediaType {
    87  	case ispec.MediaTypeImageManifest:
    88  		return imageMeta.Manifests[0].Manifest.Annotations
    89  	case ispec.MediaTypeImageIndex:
    90  		return imageMeta.Index.Index.Annotations
    91  	default:
    92  		return map[string]string{}
    93  	}
    94  }
    95  
    96  func GetImageSubject(imageMeta *proto_go.ImageMeta) *ispec.Descriptor {
    97  	switch imageMeta.MediaType {
    98  	case ispec.MediaTypeImageManifest:
    99  		if imageMeta.Manifests[0].Manifest.Subject == nil {
   100  			return nil
   101  		}
   102  
   103  		return GetDescriptorRef(imageMeta.Manifests[0].Manifest.Subject)
   104  	case ispec.MediaTypeImageIndex:
   105  		if imageMeta.Index.Index.Subject == nil {
   106  			return nil
   107  		}
   108  
   109  		return GetDescriptorRef(imageMeta.Index.Index.Subject)
   110  	default:
   111  		return nil
   112  	}
   113  }
   114  
   115  func GetDescriptorRef(descriptor *proto_go.Descriptor) *ispec.Descriptor {
   116  	if descriptor == nil {
   117  		return nil
   118  	}
   119  
   120  	platform := GetPlatformRef(descriptor.Platform)
   121  
   122  	return &ispec.Descriptor{
   123  		MediaType:    descriptor.MediaType,
   124  		Digest:       godigest.Digest(descriptor.Digest),
   125  		Size:         descriptor.Size,
   126  		URLs:         descriptor.URLs,
   127  		Data:         descriptor.Data,
   128  		Platform:     platform,
   129  		ArtifactType: deref(descriptor.ArtifactType, ""),
   130  		Annotations:  descriptor.Annotations,
   131  	}
   132  }
   133  
   134  func GetPlatform(platform *proto_go.Platform) ispec.Platform {
   135  	if platform == nil {
   136  		return ispec.Platform{}
   137  	}
   138  
   139  	return ispec.Platform{
   140  		Architecture: platform.Architecture,
   141  		OS:           platform.OS,
   142  		OSVersion:    deref(platform.OSVersion, ""),
   143  		OSFeatures:   platform.OSFeatures,
   144  		Variant:      deref(platform.Variant, ""),
   145  	}
   146  }
   147  
   148  func GetPlatformRef(platform *proto_go.Platform) *ispec.Platform {
   149  	if platform == nil {
   150  		return nil
   151  	}
   152  
   153  	return &ispec.Platform{
   154  		Architecture: platform.Architecture,
   155  		OS:           platform.OS,
   156  		OSVersion:    deref(platform.OSVersion, ""),
   157  		OSFeatures:   platform.OSFeatures,
   158  		Variant:      deref(platform.Variant, ""),
   159  	}
   160  }
   161  
   162  func GetLayers(descriptors []*proto_go.Descriptor) []ispec.Descriptor {
   163  	results := make([]ispec.Descriptor, 0, len(descriptors))
   164  
   165  	for _, desc := range descriptors {
   166  		results = append(results, ispec.Descriptor{
   167  			MediaType: desc.MediaType,
   168  			Digest:    godigest.Digest(desc.Digest),
   169  			Size:      desc.Size,
   170  		})
   171  	}
   172  
   173  	return results
   174  }
   175  
   176  func GetSubject(subj *proto_go.Descriptor) *ispec.Descriptor {
   177  	if subj == nil {
   178  		return nil
   179  	}
   180  
   181  	return &ispec.Descriptor{
   182  		MediaType: subj.MediaType,
   183  		Digest:    godigest.Digest(subj.Digest),
   184  		Size:      subj.Size,
   185  	}
   186  }
   187  
   188  func GetReferrers(refs map[string]*proto_go.ReferrersInfo) map[string][]mTypes.ReferrerInfo {
   189  	results := map[string][]mTypes.ReferrerInfo{}
   190  
   191  	for digest, ref := range refs {
   192  		referrers := []mTypes.ReferrerInfo{}
   193  
   194  		for _, dbRef := range ref.List {
   195  			referrers = append(referrers, mTypes.ReferrerInfo{
   196  				Digest:       dbRef.Digest,
   197  				MediaType:    dbRef.MediaType,
   198  				ArtifactType: dbRef.ArtifactType,
   199  				Size:         int(dbRef.Size),
   200  				Annotations:  dbRef.Annotations,
   201  			})
   202  		}
   203  
   204  		results[digest] = referrers
   205  	}
   206  
   207  	return results
   208  }
   209  
   210  func GetImageReferrers(refs *proto_go.ReferrersInfo) []mTypes.ReferrerInfo {
   211  	if refs == nil {
   212  		return []mTypes.ReferrerInfo{}
   213  	}
   214  
   215  	results := []mTypes.ReferrerInfo{}
   216  
   217  	for _, dbRef := range refs.List {
   218  		results = append(results, mTypes.ReferrerInfo{
   219  			Digest:       dbRef.Digest,
   220  			MediaType:    dbRef.MediaType,
   221  			ArtifactType: dbRef.ArtifactType,
   222  			Size:         int(dbRef.Size),
   223  			Annotations:  dbRef.Annotations,
   224  		})
   225  	}
   226  
   227  	return results
   228  }
   229  
   230  func GetSignatures(sigs map[string]*proto_go.ManifestSignatures) map[string]mTypes.ManifestSignatures {
   231  	results := map[string]mTypes.ManifestSignatures{}
   232  
   233  	for digest, dbSignatures := range sigs {
   234  		imageSignatures := mTypes.ManifestSignatures{}
   235  
   236  		for signatureName, signatureInfo := range dbSignatures.Map {
   237  			imageSignatures[signatureName] = GetSignaturesInfo(signatureInfo.List)
   238  		}
   239  
   240  		results[digest] = imageSignatures
   241  	}
   242  
   243  	return results
   244  }
   245  
   246  func GetImageSignatures(sigs *proto_go.ManifestSignatures) mTypes.ManifestSignatures {
   247  	if sigs == nil {
   248  		return mTypes.ManifestSignatures{}
   249  	}
   250  
   251  	results := mTypes.ManifestSignatures{}
   252  
   253  	for signatureName, signatureInfo := range sigs.Map {
   254  		results[signatureName] = GetSignaturesInfo(signatureInfo.List)
   255  	}
   256  
   257  	return results
   258  }
   259  
   260  func GetSignaturesInfo(sigsInfo []*proto_go.SignatureInfo) []mTypes.SignatureInfo {
   261  	results := []mTypes.SignatureInfo{}
   262  
   263  	for _, siginfo := range sigsInfo {
   264  		results = append(results, mTypes.SignatureInfo{
   265  			SignatureManifestDigest: siginfo.SignatureManifestDigest,
   266  			LayersInfo:              GetLayersInfo(siginfo.LayersInfo),
   267  		})
   268  	}
   269  
   270  	return results
   271  }
   272  
   273  func GetLayersInfo(layersInfo []*proto_go.LayersInfo) []mTypes.LayerInfo {
   274  	results := []mTypes.LayerInfo{}
   275  
   276  	for _, layerInfo := range layersInfo {
   277  		date := time.Time{}
   278  
   279  		if layerInfo.Date != nil {
   280  			date = layerInfo.Date.AsTime()
   281  		}
   282  
   283  		results = append(results, mTypes.LayerInfo{
   284  			LayerDigest:  layerInfo.LayerDigest,
   285  			LayerContent: layerInfo.LayerContent,
   286  			SignatureKey: layerInfo.SignatureKey,
   287  			Signer:       layerInfo.Signer,
   288  			Date:         date,
   289  		})
   290  	}
   291  
   292  	return results
   293  }
   294  
   295  func GetStatisticsMap(stats map[mTypes.ImageDigest]*proto_go.DescriptorStatistics,
   296  ) map[mTypes.ImageDigest]mTypes.DescriptorStatistics {
   297  	results := map[mTypes.ImageDigest]mTypes.DescriptorStatistics{}
   298  
   299  	for digest, stat := range stats {
   300  		results[digest] = mTypes.DescriptorStatistics{
   301  			DownloadCount:     int(stat.DownloadCount),
   302  			LastPullTimestamp: stat.LastPullTimestamp.AsTime(),
   303  			PushTimestamp:     stat.PushTimestamp.AsTime(),
   304  			PushedBy:          stat.PushedBy,
   305  		}
   306  	}
   307  
   308  	return results
   309  }
   310  
   311  func GetImageStatistics(stats *proto_go.DescriptorStatistics) mTypes.DescriptorStatistics {
   312  	if stats == nil {
   313  		return mTypes.DescriptorStatistics{}
   314  	}
   315  
   316  	return mTypes.DescriptorStatistics{
   317  		DownloadCount:     int(stats.DownloadCount),
   318  		LastPullTimestamp: stats.LastPullTimestamp.AsTime(),
   319  		PushTimestamp:     stats.PushTimestamp.AsTime(),
   320  		PushedBy:          stats.PushedBy,
   321  	}
   322  }
   323  
   324  func GetImageManifestMeta(manifestContent ispec.Manifest, configContent ispec.Image, size int64,
   325  	digest godigest.Digest,
   326  ) mTypes.ImageMeta {
   327  	return mTypes.ImageMeta{
   328  		MediaType: ispec.MediaTypeImageManifest,
   329  		Digest:    digest,
   330  		Size:      size,
   331  		Manifests: []mTypes.ManifestMeta{
   332  			{
   333  				Digest:   digest,
   334  				Size:     size,
   335  				Config:   configContent,
   336  				Manifest: manifestContent,
   337  			},
   338  		},
   339  	}
   340  }
   341  
   342  func GetImageIndexMeta(indexContent ispec.Index, size int64, digest godigest.Digest) mTypes.ImageMeta {
   343  	return mTypes.ImageMeta{
   344  		MediaType: ispec.MediaTypeImageIndex,
   345  		Index:     &indexContent,
   346  		Manifests: GetManifests(indexContent.Manifests),
   347  		Size:      size,
   348  		Digest:    digest,
   349  	}
   350  }
   351  
   352  func GetTags(tags map[mTypes.Tag]*proto_go.TagDescriptor) map[mTypes.Tag]mTypes.Descriptor {
   353  	resultMap := map[mTypes.Tag]mTypes.Descriptor{}
   354  
   355  	for tag, tagDescriptor := range tags {
   356  		resultMap[tag] = mTypes.Descriptor{
   357  			Digest:    tagDescriptor.Digest,
   358  			MediaType: tagDescriptor.MediaType,
   359  		}
   360  	}
   361  
   362  	return resultMap
   363  }
   364  
   365  func GetManifests(descriptors []ispec.Descriptor) []mTypes.ManifestMeta {
   366  	manifestList := []mTypes.ManifestMeta{}
   367  
   368  	for _, manifest := range descriptors {
   369  		manifestList = append(manifestList, mTypes.ManifestMeta{
   370  			Digest: manifest.Digest,
   371  			Size:   manifest.Size,
   372  		})
   373  	}
   374  
   375  	return manifestList
   376  }
   377  
   378  func GetTime(time *timestamppb.Timestamp) *time.Time {
   379  	if time == nil {
   380  		return nil
   381  	}
   382  
   383  	return ref(time.AsTime())
   384  }
   385  
   386  func GetFullImageMetaFromProto(tag string, protoRepoMeta *proto_go.RepoMeta, protoImageMeta *proto_go.ImageMeta,
   387  ) mTypes.FullImageMeta {
   388  	if protoRepoMeta == nil {
   389  		return mTypes.FullImageMeta{}
   390  	}
   391  
   392  	imageMeta := GetImageMeta(protoImageMeta)
   393  	imageDigest := imageMeta.Digest.String()
   394  
   395  	return mTypes.FullImageMeta{
   396  		Repo:         protoRepoMeta.Name,
   397  		Tag:          tag,
   398  		MediaType:    imageMeta.MediaType,
   399  		Digest:       imageMeta.Digest,
   400  		Size:         imageMeta.Size,
   401  		Index:        imageMeta.Index,
   402  		Manifests:    GetFullManifestData(protoRepoMeta, imageMeta.Manifests),
   403  		IsStarred:    protoRepoMeta.IsStarred,
   404  		IsBookmarked: protoRepoMeta.IsBookmarked,
   405  
   406  		Referrers:  GetImageReferrers(protoRepoMeta.Referrers[imageDigest]),
   407  		Statistics: GetImageStatistics(protoRepoMeta.Statistics[imageDigest]),
   408  		Signatures: GetImageSignatures(protoRepoMeta.Signatures[imageDigest]),
   409  	}
   410  }
   411  
   412  func GetFullManifestData(protoRepoMeta *proto_go.RepoMeta, manifestData []mTypes.ManifestMeta,
   413  ) []mTypes.FullManifestMeta {
   414  	if protoRepoMeta == nil {
   415  		return []mTypes.FullManifestMeta{}
   416  	}
   417  
   418  	results := []mTypes.FullManifestMeta{}
   419  
   420  	for i := range manifestData {
   421  		results = append(results, mTypes.FullManifestMeta{
   422  			ManifestMeta: manifestData[i],
   423  			Referrers:    GetImageReferrers(protoRepoMeta.Referrers[manifestData[i].Digest.String()]),
   424  			Statistics:   GetImageStatistics(protoRepoMeta.Statistics[manifestData[i].Digest.String()]),
   425  			Signatures:   GetImageSignatures(protoRepoMeta.Signatures[manifestData[i].Digest.String()]),
   426  		})
   427  	}
   428  
   429  	return results
   430  }
   431  
   432  func GetRepoMeta(protoRepoMeta *proto_go.RepoMeta) mTypes.RepoMeta {
   433  	if protoRepoMeta == nil {
   434  		return mTypes.RepoMeta{}
   435  	}
   436  
   437  	repoDownloads := int32(0)
   438  
   439  	for _, descriptor := range protoRepoMeta.Tags {
   440  		if statistic := protoRepoMeta.Statistics[descriptor.Digest]; statistic != nil {
   441  			repoDownloads += statistic.DownloadCount
   442  		}
   443  	}
   444  
   445  	return mTypes.RepoMeta{
   446  		Name:             protoRepoMeta.Name,
   447  		Tags:             GetTags(protoRepoMeta.Tags),
   448  		Rank:             int(protoRepoMeta.Rank),
   449  		Size:             protoRepoMeta.Size,
   450  		Platforms:        GetPlatforms(protoRepoMeta.Platforms),
   451  		Vendors:          protoRepoMeta.Vendors,
   452  		IsStarred:        protoRepoMeta.IsStarred,
   453  		IsBookmarked:     protoRepoMeta.IsBookmarked,
   454  		StarCount:        int(protoRepoMeta.Stars),
   455  		DownloadCount:    int(repoDownloads),
   456  		LastUpdatedImage: GetLastUpdatedImage(protoRepoMeta.LastUpdatedImage),
   457  		Statistics:       GetStatisticsMap(protoRepoMeta.Statistics),
   458  		Signatures:       GetSignatures(protoRepoMeta.Signatures),
   459  		Referrers:        GetReferrers(protoRepoMeta.Referrers),
   460  	}
   461  }
   462  
   463  func GetPlatforms(platforms []*proto_go.Platform) []ispec.Platform {
   464  	result := []ispec.Platform{}
   465  
   466  	for i := range platforms {
   467  		result = append(result, GetPlatform(platforms[i]))
   468  	}
   469  
   470  	return result
   471  }
   472  
   473  func AddProtoPlatforms(platforms []*proto_go.Platform, newPlatforms []*proto_go.Platform) []*proto_go.Platform {
   474  	for _, newPlatform := range newPlatforms {
   475  		if !ContainsProtoPlatform(platforms, newPlatform) {
   476  			platforms = append(platforms, newPlatform)
   477  		}
   478  	}
   479  
   480  	return platforms
   481  }
   482  
   483  func ContainsProtoPlatform(platforms []*proto_go.Platform, platform *proto_go.Platform) bool {
   484  	for i := range platforms {
   485  		if platforms[i].OS == platform.OS && platforms[i].Architecture == platform.Architecture {
   486  			return true
   487  		}
   488  	}
   489  
   490  	return false
   491  }
   492  
   493  func AddVendors(vendors []string, newVendors []string) []string {
   494  	for _, newVendor := range newVendors {
   495  		if !common.Contains(vendors, newVendor) {
   496  			vendors = append(vendors, newVendor)
   497  		}
   498  	}
   499  
   500  	return vendors
   501  }
   502  
   503  func GetLastUpdatedImage(protoLastUpdated *proto_go.RepoLastUpdatedImage) *mTypes.LastUpdatedImage {
   504  	if protoLastUpdated == nil {
   505  		return nil
   506  	}
   507  
   508  	return &mTypes.LastUpdatedImage{
   509  		Descriptor: mTypes.Descriptor{
   510  			Digest:    protoLastUpdated.Digest,
   511  			MediaType: protoLastUpdated.MediaType,
   512  		},
   513  		Tag:         protoLastUpdated.Tag,
   514  		LastUpdated: GetTime(protoLastUpdated.LastUpdated),
   515  	}
   516  }
   517  
   518  func GetImageMeta(dbImageMeta *proto_go.ImageMeta) mTypes.ImageMeta {
   519  	if dbImageMeta == nil {
   520  		return mTypes.ImageMeta{}
   521  	}
   522  
   523  	imageMeta := mTypes.ImageMeta{
   524  		MediaType: dbImageMeta.MediaType,
   525  		Size:      GetImageManifestSize(dbImageMeta),
   526  		Digest:    GetImageDigest(dbImageMeta),
   527  	}
   528  
   529  	if dbImageMeta.MediaType == ispec.MediaTypeImageIndex {
   530  		manifests := make([]ispec.Descriptor, 0, len(dbImageMeta.Manifests))
   531  
   532  		for _, manifest := range deref(dbImageMeta.Index, proto_go.IndexMeta{}).Index.Manifests {
   533  			manifests = append(manifests, ispec.Descriptor{
   534  				MediaType: manifest.MediaType,
   535  				Digest:    godigest.Digest(manifest.Digest),
   536  				Size:      manifest.Size,
   537  			})
   538  		}
   539  
   540  		imageMeta.Index = &ispec.Index{
   541  			Versioned:    specs.Versioned{SchemaVersion: int(dbImageMeta.Index.Index.Versioned.GetSchemaVersion())},
   542  			MediaType:    ispec.MediaTypeImageIndex,
   543  			Manifests:    manifests,
   544  			Subject:      GetImageSubject(dbImageMeta),
   545  			ArtifactType: GetImageArtifactType(dbImageMeta),
   546  			Annotations:  GetImageAnnotations(dbImageMeta),
   547  		}
   548  	}
   549  
   550  	manifestDataList := make([]mTypes.ManifestMeta, 0, len(dbImageMeta.Manifests))
   551  
   552  	for _, manifest := range dbImageMeta.Manifests {
   553  		manifestDataList = append(manifestDataList, mTypes.ManifestMeta{
   554  			Size:   manifest.Size,
   555  			Digest: godigest.Digest(manifest.Digest),
   556  			Manifest: ispec.Manifest{
   557  				Versioned:    specs.Versioned{SchemaVersion: int(manifest.Manifest.Versioned.GetSchemaVersion())},
   558  				MediaType:    deref(manifest.Manifest.MediaType, ""),
   559  				ArtifactType: deref(manifest.Manifest.ArtifactType, ""),
   560  				Config: ispec.Descriptor{
   561  					MediaType: manifest.Manifest.Config.MediaType,
   562  					Size:      manifest.Manifest.Config.Size,
   563  					Digest:    godigest.Digest(manifest.Manifest.Config.Digest),
   564  				},
   565  				Layers:      GetLayers(manifest.Manifest.Layers),
   566  				Subject:     GetSubject(manifest.Manifest.Subject),
   567  				Annotations: manifest.Manifest.Annotations,
   568  			},
   569  			Config: ispec.Image{
   570  				Created:  GetTime(manifest.Config.Created),
   571  				Author:   deref(manifest.Config.Author, ""),
   572  				Platform: GetPlatform(manifest.Config.Platform),
   573  				Config: ispec.ImageConfig{
   574  					User:         manifest.Config.Config.User,
   575  					ExposedPorts: GetExposedPorts(manifest.Config.Config.ExposedPorts),
   576  					Env:          manifest.Config.Config.Env,
   577  					Entrypoint:   manifest.Config.Config.Entrypoint,
   578  					Cmd:          manifest.Config.Config.Cmd,
   579  					Volumes:      GetConfigVolumes(manifest.Config.Config.Volumes),
   580  					WorkingDir:   deref(manifest.Config.Config.WorkingDir, ""),
   581  					Labels:       manifest.Config.Config.Labels,
   582  					StopSignal:   deref(manifest.Config.Config.StopSignal, ""),
   583  				},
   584  				RootFS: ispec.RootFS{
   585  					Type:    manifest.Config.RootFS.Type,
   586  					DiffIDs: GetDiffIDs(manifest.Config.RootFS.DiffIDs),
   587  				},
   588  				History: GetHistory(manifest.Config.History),
   589  			},
   590  		})
   591  	}
   592  
   593  	imageMeta.Manifests = manifestDataList
   594  
   595  	return imageMeta
   596  }
   597  
   598  func GetExposedPorts(exposedPorts map[string]*proto_go.EmptyMessage) map[string]struct{} {
   599  	if exposedPorts == nil {
   600  		return nil
   601  	}
   602  
   603  	result := map[string]struct{}{}
   604  
   605  	for key := range exposedPorts {
   606  		result[key] = struct{}{}
   607  	}
   608  
   609  	return result
   610  }
   611  
   612  func GetConfigVolumes(configVolumes map[string]*proto_go.EmptyMessage) map[string]struct{} {
   613  	if configVolumes == nil {
   614  		return nil
   615  	}
   616  
   617  	result := map[string]struct{}{}
   618  
   619  	for key := range configVolumes {
   620  		result[key] = struct{}{}
   621  	}
   622  
   623  	return result
   624  }
   625  
   626  func GetDiffIDs(diffIDs []string) []godigest.Digest {
   627  	result := make([]godigest.Digest, 0, len(diffIDs))
   628  
   629  	for i := range diffIDs {
   630  		result = append(result, godigest.Digest(diffIDs[i]))
   631  	}
   632  
   633  	return result
   634  }