pax_global_header00006660000000000000000000000064142307357530014523gustar00rootroot0000000000000052 comment=e841cdc2852af2835a916d9e753188b95e1c4d82 gitmap-1.3.0/000077500000000000000000000000001423073575300130055ustar00rootroot00000000000000gitmap-1.3.0/.gitignore000066400000000000000000000004511423073575300147750ustar00rootroot00000000000000# Compiled Object files, Static and Dynamic libs (Shared Objects) *.o *.a *.so # Folders _obj _test # Architecture specific extensions/prefixes *.[568vq] [568vq].out *.cgo1.go *.cgo2.c _cgo_defun.c _cgo_gotypes.go _cgo_export.* _testmain.go *.exe *.test *.prof cover.out bench.txt bench2.txt gitmap-1.3.0/.travis.yml000066400000000000000000000003371423073575300151210ustar00rootroot00000000000000language: go sudo: false go: - 1.12.x - tip os: - linux - osx script: - go test -coverprofile=coverage.txt -covermode=atomic install: - go get -v ./... after_success: - bash <(curl -s https://codecov.io/bash) gitmap-1.3.0/LICENSE000066400000000000000000000020771423073575300140200ustar00rootroot00000000000000The MIT License (MIT) Copyright (c) 2016 Bjørn Erik Pedersen Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. gitmap-1.3.0/README.md000066400000000000000000000017201423073575300142640ustar00rootroot00000000000000# GitMap [![GoDoc](https://godoc.org/github.com/bep/gitmap?status.svg)](https://godoc.org/github.com/bep/gitmap) [![Build Status](https://travis-ci.org/bep/gitmap.svg)](https://travis-ci.org/bep/gitmap) [![Build status](https://ci.appveyor.com/api/projects/status/c8tu1wdoa4j7q81g?svg=true)](https://ci.appveyor.com/project/bjornerik/gitmap) [![Go Report Card](https://goreportcard.com/badge/github.com/bep/gitmap)](https://goreportcard.com/report/github.com/bep/gitmap) [![codecov](https://codecov.io/gh/bep/gitmap/branch/master/graph/badge.svg)](https://codecov.io/gh/bep/gitmap) A fairly fast way to create a map from all the filenames to info objects for a given revision of a Git repo. This library uses `os/exec` to talk to Git. There are faster ways to do this by using some Go Git-lib or C bindings, but that adds dependencies I really don't want or need. If some `git log kung fu master` out there have suggestions for improvements, please open an issue or a PR. gitmap-1.3.0/gitmap.go000066400000000000000000000076011423073575300146210ustar00rootroot00000000000000// Copyright © 2016-present Bjørn Erik Pedersen . // // Use of this source code is governed by an MIT-style // license that can be found in the LICENSE file. package gitmap import ( "bytes" "errors" "fmt" "os/exec" "path/filepath" "strings" "time" ) var ( // will be modified during tests gitExec string GitNotFound = errors.New("Git executable not found in $PATH") ) type GitRepo struct { // TopLevelAbsPath contains the absolute path of the top-level directory. // This is similar to the answer from "git rev-parse --show-toplevel" // except symbolic link is not followed on non-Windows platforms. // Note that this follows Git's way of handling paths, so expect to get forward slashes, // even on Windows. TopLevelAbsPath string // The files in this Git repository. Files GitMap } // GitMap maps filenames to Git revision information. type GitMap map[string]*GitInfo // GitInfo holds information about a Git commit. type GitInfo struct { Hash string `json:"hash"` // Commit hash AbbreviatedHash string `json:"abbreviatedHash"` // Abbreviated commit hash Subject string `json:"subject"` // The commit message's subject/title line AuthorName string `json:"authorName"` // The author name, respecting .mailmap AuthorEmail string `json:"authorEmail"` // The author email address, respecting .mailmap AuthorDate time.Time `json:"authorDate"` // The author date CommitDate time.Time `json:"commitDate"` // The commit date } // Map creates a GitRepo with a file map from the given repository path and revision. // Use blank or HEAD as revision for the currently active revision. func Map(repository, revision string) (*GitRepo, error) { m := make(GitMap) // First get the top level repo path absRepoPath, err := filepath.Abs(repository) if err != nil { return nil, err } out, err := git("-C", repository, "rev-parse", "--show-cdup") if err != nil { return nil, err } cdUp := strings.TrimSpace(string(out)) topLevelPath := filepath.ToSlash(filepath.Join(absRepoPath, cdUp)) gitLogArgs := strings.Fields(fmt.Sprintf( `--name-only --no-merges --format=format:%%x1e%%H%%x1f%%h%%x1f%%s%%x1f%%aN%%x1f%%aE%%x1f%%ai%%x1f%%ci %s`, revision, )) gitLogArgs = append([]string{"-c", "diff.renames=0", "-c", "log.showSignature=0", "-C", repository, "log"}, gitLogArgs...) out, err = git(gitLogArgs...) if err != nil { return nil, err } entriesStr := string(out) entriesStr = strings.Trim(entriesStr, "\n\x1e'") entries := strings.Split(entriesStr, "\x1e") for _, e := range entries { lines := strings.Split(e, "\n") gitInfo, err := toGitInfo(lines[0]) if err != nil { return nil, err } for _, filename := range lines[1:] { filename := strings.TrimSpace(filename) if filename == "" { continue } if _, ok := m[filename]; !ok { m[filename] = gitInfo } } } return &GitRepo{Files: m, TopLevelAbsPath: topLevelPath}, nil } func git(args ...string) ([]byte, error) { out, err := exec.Command(gitExec, args...).CombinedOutput() if err != nil { if ee, ok := err.(*exec.Error); ok { if ee.Err == exec.ErrNotFound { return nil, GitNotFound } } return nil, errors.New(string(bytes.TrimSpace(out))) } return out, nil } func toGitInfo(entry string) (*GitInfo, error) { items := strings.Split(entry, "\x1f") authorDate, err := time.Parse("2006-01-02 15:04:05 -0700", items[5]) if err != nil { return nil, err } commitDate, err := time.Parse("2006-01-02 15:04:05 -0700", items[6]) if err != nil { return nil, err } return &GitInfo{ Hash: items[0], AbbreviatedHash: items[1], Subject: items[2], AuthorName: items[3], AuthorEmail: items[4], AuthorDate: authorDate, CommitDate: commitDate, }, nil } func init() { initDefaults() } func initDefaults() { gitExec = "git" } gitmap-1.3.0/gitmap_test.go000066400000000000000000000110151423073575300156520ustar00rootroot00000000000000// Copyright © 2016-present Bjørn Erik Pedersen . // // Use of this source code is governed by an MIT-style // license that can be found in the LICENSE file. package gitmap import ( "encoding/json" "os" "strings" "testing" ) var ( revision = "7d46b653c9674510d808815c4c92c7dc10bedc16" repository string ) func init() { var err error if repository, err = os.Getwd(); err != nil { panic(err) } } func TestMap(t *testing.T) { var ( gm GitMap gr *GitRepo err error ) if gr, err = Map(repository, revision); err != nil { t.Fatal(err) } gm = gr.Files if len(gm) != 11 { t.Fatalf("Wrong number of files, got %d, expected %d", len(gm), 9) } assertFile(t, gm, "testfiles/d1/d1.txt", "39120eb", "39120eb28a2f8a0312f9b45f91b6abb687b7fd3c", "2016-07-20", "2016-07-20", ) assertFile(t, gm, "testfiles/d2/d2.txt", "39120eb", "39120eb28a2f8a0312f9b45f91b6abb687b7fd3c", "2016-07-20", "2016-07-20", ) assertFile(t, gm, "testfiles/amended.txt", "7d46b65", "7d46b653c9674510d808815c4c92c7dc10bedc16", "2019-05-23", "2019-05-25", ) assertFile(t, gm, "README.md", "0b830e4", "0b830e458446fdb774b1688af9b402acf388d6ab", "2016-07-22", "2016-07-22", ) } func assertFile( t *testing.T, gm GitMap, filename, expectedAbbreviatedHash, expectedHash, expectedAuthorDate, expectedCommitDate string) { var ( gi *GitInfo ok bool ) if gi, ok = gm[filename]; !ok { t.Fatal(filename) } if gi.AbbreviatedHash != expectedAbbreviatedHash || gi.Hash != expectedHash { t.Error("Invalid tree hash, file", filename, "abbreviated:", gi.AbbreviatedHash, "full:", gi.Hash, gi.Subject) } if gi.AuthorName != "Bjørn Erik Pedersen" && gi.AuthorName != "Michael Stapelberg" { t.Error("These commits are mine! Got", gi.AuthorName, "and", gi.AuthorEmail) } if gi.AuthorEmail != "bjorn.erik.pedersen@gmail.com" && gi.AuthorEmail != "stapelberg@google.com" { t.Error("These commits are mine! Got", gi.AuthorName, "and", gi.AuthorEmail) } if got, want := gi.AuthorDate.Format("2006-01-02"), expectedAuthorDate; got != want { t.Errorf("%s: unexpected author date: got %v, want %v", filename, got, want) } if got, want := gi.CommitDate.Format("2006-01-02"), expectedCommitDate; got != want { t.Errorf("%s: unexpected commit date: got %v, want %v", filename, got, want) } } func TestActiveRevision(t *testing.T) { var ( gm GitMap gr *GitRepo err error ) if gr, err = Map(repository, "HEAD"); err != nil { t.Fatal(err) } gm = gr.Files if len(gm) < 10 { t.Fatalf("Wrong number of files, got %d, expected at least %d", len(gm), 10) } if len(gm) < 10 { t.Fatalf("Wrong number of files, got %d, expected at least %d", len(gm), 10) } } func TestGitExecutableNotFound(t *testing.T) { defer initDefaults() gitExec = "thisShouldHopefullyNotExistOnPath" gi, err := Map(repository, revision) if err != GitNotFound || gi != nil { t.Fatal("Invalid error handling") } } func TestEncodeJSON(t *testing.T) { var ( gm GitMap gr *GitRepo gi *GitInfo err error ok bool filename = "README.md" ) if gr, err = Map(repository, revision); err != nil { t.Fatal(err) } gm = gr.Files if gi, ok = gm[filename]; !ok { t.Fatal(filename) } b, err := json.Marshal(&gi) if err != nil { t.Fatal(err) } s := string(b) if s != `{"hash":"0b830e458446fdb774b1688af9b402acf388d6ab","abbreviatedHash":"0b830e4","subject":"Add some more to README","authorName":"Bjørn Erik Pedersen","authorEmail":"bjorn.erik.pedersen@gmail.com","authorDate":"2016-07-22T21:40:27+02:00","commitDate":"2016-07-22T21:40:27+02:00"}` { t.Errorf("JSON marshal error: \n%s", s) } } func TestGitRevisionNotFound(t *testing.T) { gi, err := Map(repository, "adfasdfasdf") // TODO(bep) improve error handling. if err == nil || gi != nil { t.Fatal("Invalid error handling", err) } } func TestGitRepoNotFound(t *testing.T) { gi, err := Map("adfasdfasdf", revision) // TODO(bep) improve error handling. if err == nil || gi != nil { t.Fatal("Invalid error handling", err) } } func TestTopLevelAbsPath(t *testing.T) { var ( gr *GitRepo err error ) if gr, err = Map(repository, revision); err != nil { t.Fatal(err) } expected := "/bep/gitmap" if !strings.HasSuffix(gr.TopLevelAbsPath, expected) { t.Fatalf("Expected to end with %q got %q", expected, gr.TopLevelAbsPath) } } func BenchmarkMap(b *testing.B) { for i := 0; i < b.N; i++ { _, err := Map(repository, revision) if err != nil { b.Fatalf("Got error: %s", err) } } } gitmap-1.3.0/go.mod000066400000000000000000000000461423073575300141130ustar00rootroot00000000000000module github.com/bep/gitmap go 1.18 gitmap-1.3.0/testfiles/000077500000000000000000000000001423073575300150075ustar00rootroot00000000000000gitmap-1.3.0/testfiles/amended.txt000066400000000000000000000000351423073575300171430ustar00rootroot00000000000000different author/commit date gitmap-1.3.0/testfiles/d1/000077500000000000000000000000001423073575300153135ustar00rootroot00000000000000gitmap-1.3.0/testfiles/d1/d1.txt000066400000000000000000000000141423073575300163530ustar00rootroot00000000000000d1-changed2 gitmap-1.3.0/testfiles/d2/000077500000000000000000000000001423073575300153145ustar00rootroot00000000000000gitmap-1.3.0/testfiles/d2/d2.txt000066400000000000000000000000131423073575300163540ustar00rootroot00000000000000d2-changed gitmap-1.3.0/testfiles/r1.txt000066400000000000000000000000061423073575300160660ustar00rootroot00000000000000test1 gitmap-1.3.0/testfiles/r2.txt000066400000000000000000000000031423073575300160640ustar00rootroot00000000000000r2