Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 6 additions & 4 deletions glide.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion glide.yaml
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
package: github.com/opencontainers/image-spec
import:
- package: github.com/pkg/errors
version: ">=0.7.0"
version: '>=0.7.0'
- package: github.com/xeipuuv/gojsonschema
version: d5336c75940ef31c9ceeb0ae64cf92944bccb4ee
- package: github.com/russross/blackfriday
version: ~v1.4
- package: github.com/shurcooL/sanitized_anchor_name
version: 10ef21a441db47d8b13ebcc5fd2310f636973c77
- package: github.com/opencontainers/go-digest
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you add a version, please?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you add a version, please?

We still need to cut one (opencontainers/go-digest#23), as @stevvooe mentions at in his earlier comment.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Look at the immediately prior dependency. Version can be a hash.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That is in the glide.lock file. Only specify a version here if it matters when updating.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, it's here in glide.yaml - every other package has an associated version. Can we just keep it consistent for now? IMO glide-update should ideally be idempotent unless someone intentionally requests otherwise.

67 changes: 67 additions & 0 deletions identity/chainid.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
// Copyright 2016 The Linux Foundation
//
// 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.

// Package identity provides implementations of subtle calculations pertaining
// to image and layer identity. The primary item present here is the ChainID
// calculation used in identifying the result of subsequent layer applications.
//
// Helpers are also provided here to ease transition to the
// github.com/opencontainers/go-digest package, but that package may be used
// directly.
package identity

import "github.com/opencontainers/go-digest"

// ChainID takes a slice of digests and returns the ChainID corresponding to
// the last entry. Typically, these are a list of layer DiffIDs, with the
// result providing the ChainID identifying the result of sequential
// application of the preceding layers.
func ChainID(dgsts []digest.Digest) digest.Digest {
chainIDs := make([]digest.Digest, len(dgsts))
copy(chainIDs, dgsts)
ChainIDs(chainIDs)

if len(chainIDs) == 0 {
return ""
}
return chainIDs[len(chainIDs)-1]
}

// ChainIDs calculates the recursively applied chain id for each identifier in
// the slice. The result is written direcly back into the slice such that the
// ChainID for each item will be in the respective position.
//
// By definition of ChainID, the zeroth element will always be the same before
// and after the call.
//
// As an example, given the chain of ids `[A, B, C]`, the result `[A,
// ChainID(A|B), ChainID(A|B|C)]` will be written back to the slice.
//
// The input is provided as a return value for convenience.
//
// Typically, these are a list of layer DiffIDs, with the
// result providing the ChainID for each the result of each layer application
// sequentially.
func ChainIDs(dgsts []digest.Digest) []digest.Digest {
if len(dgsts) < 2 {
return dgsts
}

parent := digest.FromBytes([]byte(dgsts[0] + " " + dgsts[1]))
next := dgsts[1:]
next[0] = parent
ChainIDs(next)

return dgsts
}
95 changes: 95 additions & 0 deletions identity/chainid_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
// Copyright 2016 The Linux Foundation
//
// 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.

package identity

import (
_ "crypto/sha256" // required to install sha256 digest support
"reflect"
"testing"

"github.com/opencontainers/go-digest"
)

func TestChainID(t *testing.T) {
// To provide a good testing base, we define the individual links in a
// chain recursively, illustrating the calculations for each chain.
//
// Note that we use invalid digests for the unmodified identifiers here to
// make the computation more readable.
chainDigestAB := digest.FromString("sha256:a" + " " + "sha256:b") // chain for A|B
chainDigestABC := digest.FromString(chainDigestAB.String() + " " + "sha256:c") // chain for A|B|C

for _, testcase := range []struct {
Name string
Digests []digest.Digest
Expected []digest.Digest
}{
{
Name: "nil",
},
{
Name: "empty",
Digests: []digest.Digest{},
Expected: []digest.Digest{},
},
{
Name: "identity",
Digests: []digest.Digest{"sha256:a"},
Expected: []digest.Digest{"sha256:a"},
},
{
Name: "two",
Digests: []digest.Digest{"sha256:a", "sha256:b"},
Expected: []digest.Digest{"sha256:a", chainDigestAB},
},
{
Name: "three",
Digests: []digest.Digest{"sha256:a", "sha256:b", "sha256:c"},
Expected: []digest.Digest{"sha256:a", chainDigestAB, chainDigestABC},
},
} {
t.Run(testcase.Name, func(t *testing.T) {
t.Log("before", testcase.Digests)

var ids []digest.Digest

if testcase.Digests != nil {
ids = make([]digest.Digest, len(testcase.Digests))
copy(ids, testcase.Digests)
}

ids = ChainIDs(ids)
t.Log("after", ids)
if !reflect.DeepEqual(ids, testcase.Expected) {
t.Errorf("unexpected chain: %v != %v", ids, testcase.Expected)
}

if len(testcase.Digests) == 0 {
return
}

// Make sure parent stays stable
if ids[0] != testcase.Digests[0] {
t.Errorf("parent changed: %v != %v", ids[0], testcase.Digests[0])
}

// make sure that the ChainID function takes the last element
id := ChainID(testcase.Digests)
if id != ids[len(ids)-1] {
t.Errorf("incorrect chain id returned from ChainID: %v != %v", id, ids[len(ids)-1])
}
})
}
}
40 changes: 40 additions & 0 deletions identity/helpers.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
// Copyright 2016 The Linux Foundation
//
// 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.

package identity

import (
_ "crypto/sha256" // side-effect to install impls, sha256
_ "crypto/sha512" // side-effect to install impls, sha384/sh512

"io"

digest "github.com/opencontainers/go-digest"
)

// FromReader consumes the content of rd until io.EOF, returning canonical
// digest.
func FromReader(rd io.Reader) (digest.Digest, error) {
return digest.Canonical.FromReader(rd)
}

// FromBytes digests the input and returns a Digest.
func FromBytes(p []byte) digest.Digest {
return digest.Canonical.FromBytes(p)
}

// FromString digests the input and returns a Digest.
func FromString(s string) digest.Digest {
return digest.Canonical.FromString(s)
}
Loading