1 // Copyright 2016 The Linux Foundation 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 // Package identity provides implementations of subtle calculations pertaining 16 // to image and layer identity. The primary item present here is the ChainID 17 // calculation used in identifying the result of subsequent layer applications. 18 // 19 // Helpers are also provided here to ease transition to the 20 // github.com/opencontainers/go-digest package, but that package may be used 21 // directly. 22 package identity 23 24 import "github.com/opencontainers/go-digest" 25 26 // ChainID takes a slice of digests and returns the ChainID corresponding to 27 // the last entry. Typically, these are a list of layer DiffIDs, with the 28 // result providing the ChainID identifying the result of sequential 29 // application of the preceding layers. 30 func ChainID(dgsts []digest.Digest) digest.Digest { 31 chainIDs := make([]digest.Digest, len(dgsts)) 32 copy(chainIDs, dgsts) 33 ChainIDs(chainIDs) 34 35 if len(chainIDs) == 0 { 36 return "" 37 } 38 return chainIDs[len(chainIDs)-1] 39 } 40 41 // ChainIDs calculates the recursively applied chain id for each identifier in 42 // the slice. The result is written direcly back into the slice such that the 43 // ChainID for each item will be in the respective position. 44 // 45 // By definition of ChainID, the zeroth element will always be the same before 46 // and after the call. 47 // 48 // As an example, given the chain of ids `[A, B, C]`, the result `[A, 49 // ChainID(A|B), ChainID(A|B|C)]` will be written back to the slice. 50 // 51 // The input is provided as a return value for convenience. 52 // 53 // Typically, these are a list of layer DiffIDs, with the 54 // result providing the ChainID for each the result of each layer application 55 // sequentially. 56 func ChainIDs(dgsts []digest.Digest) []digest.Digest { 57 if len(dgsts) < 2 { 58 return dgsts 59 } 60 61 parent := digest.FromBytes([]byte(dgsts[0] + " " + dgsts[1])) 62 next := dgsts[1:] 63 next[0] = parent 64 ChainIDs(next) 65 66 return dgsts 67 } 68