Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

changeset: Look in packed-refs if ref file not found. #2425

Merged
merged 1 commit into from
Feb 17, 2022
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
67 changes: 65 additions & 2 deletions changeset/commit.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ limitations under the License.
package changeset

import (
"bufio"
"fmt"
"io/ioutil"
"os"
Expand All @@ -28,6 +29,10 @@ import (
const (
commitIDFile = "HEAD"
koDataPathEnvName = "KO_DATA_PATH"
// packedRefsFile is a file containing a list of refs, used to compact the
// list of refs instead of storing them on the filesystem directly.
// See https://git-scm.com/docs/git-pack-refs
packedRefsFile = "packed-refs"
)

var commitIDRE = regexp.MustCompile(`^[a-f0-9]{40}$`)
Expand All @@ -41,9 +46,27 @@ func Get() (string, error) {
}
commitID := strings.TrimSpace(string(data))
if rID := strings.TrimPrefix(commitID, "ref: "); rID != commitID {
// First try to read from the direct ref file - e.g. refs/heads/main
data, err := readFileFromKoData(rID)
if err != nil {
return "", err
if !os.IsNotExist(err) {
return "", err
}

// Ref file didn't exist - it might be contained in the packed-refs
// file.
var pferr error
data, pferr = findPackedRef(rID)
// Only return the sub-error if the packed-refs file exists, otherwise
// just let the original error return (e.g. treat it as if we didn't
// even attempt the operation). This is primarily to keep the error
// messages clean.
if pferr != nil {
if os.IsNotExist(pferr) {
return "", err
}
return "", pferr
}
}
commitID = strings.TrimSpace(string(data))
}
Expand All @@ -58,9 +81,49 @@ func Get() (string, error) {
// to be wrapped into the container from /kodata by ko. If it fails, returns
// the error it gets.
func readFileFromKoData(filename string) ([]byte, error) {
f, err := koDataFile(filename)
if err != nil {
return nil, err
}
defer f.Close()
return ioutil.ReadAll(f)
}

// readFileFromKoData tries to open the file with given name under KO_DATA_PATH.
// The file is expected to be wrapped into the container from /kodata by ko.
// If it fails, returns the error it gets.
func koDataFile(filename string) (*os.File, error) {
koDataPath := os.Getenv(koDataPathEnvName)
if koDataPath == "" {
return nil, fmt.Errorf("%q does not exist or is empty", koDataPathEnvName)
}
return ioutil.ReadFile(filepath.Join(koDataPath, filename))
return os.Open(filepath.Join(koDataPath, filename))
}

// findPackedRef searches the packed-ref file for ref values.
// This can happen if the # of refs in a repo grows too much - git will try
// and condense them into a file.
// See https://git-scm.com/docs/git-pack-refs
func findPackedRef(ref string) ([]byte, error) {
f, err := koDataFile(packedRefsFile)
if err != nil {
return nil, err
}
defer f.Close()

scanner := bufio.NewScanner(f)
for scanner.Scan() {
// We only care about lines with `<commit> <ref>` pairs.
// Why this might happen:
// 1. Lines starting with ^ refer to unpeeled tag SHAs
// (e.g. the commits pointed to by annotated tags)
s := strings.Split(scanner.Text(), " ")
if len(s) != 2 {
continue
}
if ref == s[1] {
return []byte(s[0]), nil
}
}
return nil, fmt.Errorf("%q ref not found in packed-refs", ref)
}
9 changes: 9 additions & 0 deletions changeset/commit_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,15 @@ func TestReadFile(t *testing.T) {
koDataPath: "testdata/nonexisting",
wantErr: true,
err: errors.New("open testdata/nonexisting/HEAD: no such file or directory"),
}, {
name: "packed-ref",
koDataPath: "testdata/packed-refs",
want: testCommitID,
}, {
name: "no refs with packed-ref",
koDataPath: "testdata/noncommited-packed-refs",
wantErr: true,
err: fmt.Errorf("%q ref not found in packed-refs", nonCommittedHeadRef),
}}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
Expand Down
1 change: 1 addition & 0 deletions changeset/testdata/noncommited-packed-refs/HEAD
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
ref: refs/heads/non_committed_branch
Empty file.
1 change: 1 addition & 0 deletions changeset/testdata/packed-refs/HEAD
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
ref: refs/heads/foo
4 changes: 4 additions & 0 deletions changeset/testdata/packed-refs/packed-refs
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
a2d1bdfe929516d7da141aef68631a7ee6941b2d refs/tags/bar
^51be315ed160e68627a3bc51a244ec77e470c667
a2d1bdfe929516d7da141aef68631a7ee6941b2d refs/tags/baz
a2d1bdfe929516d7da141aef68631a7ee6941b2d refs/heads/foo