f1b8d88d6b
* Improving mattermost auth implementation * Making mattermost-auth based on shared database access * Reverting unneeded changes in the config.json file * Fixing tiny problems * Removing the need of using the mattermost session token * Fixing some bugs and allowing to not-bind the server to any port * Small fix to correctly get the templates * Adding the mattermost-plugin code inside focalboard repo * Adding a not working code part of the cluster websocket communication * Updating the mattermost version * Adding the cluster messages for the websockets * Updating to the new node version * Making it compatible with S3 * Addressing some tiny problems * Fixing server tests * Adds support for MySQL migrations and initialization Co-authored-by: Miguel de la Cruz <miguel@mcrx.me>
111 lines
2.6 KiB
Go
111 lines
2.6 KiB
Go
package git
|
|
|
|
import (
|
|
"crypto/sha1" //nolint
|
|
"encoding/hex"
|
|
"fmt"
|
|
"io"
|
|
"os"
|
|
"path/filepath"
|
|
|
|
git "github.com/go-git/go-git/v5"
|
|
"github.com/go-git/go-git/v5/plumbing"
|
|
"github.com/go-git/go-git/v5/plumbing/object"
|
|
"github.com/pkg/errors"
|
|
)
|
|
|
|
// ErrNotFound signifies the file was not found.
|
|
var ErrNotFound = fmt.Errorf("not found")
|
|
|
|
// FileHistory will trace all the versions of a file in the git repository
|
|
// and return a list of sha1 hashes of that file.
|
|
func FileHistory(path string, repo *git.Repository) ([]string, error) {
|
|
logOpts := git.LogOptions{
|
|
FileName: &path,
|
|
All: true,
|
|
}
|
|
commits, err := repo.Log(&logOpts)
|
|
if errors.Is(err, plumbing.ErrReferenceNotFound) {
|
|
return nil, ErrNotFound
|
|
}
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to get commits for path %q: %v", path, err)
|
|
}
|
|
defer commits.Close()
|
|
hashHistory := []string{}
|
|
cerr := commits.ForEach(func(c *object.Commit) error {
|
|
root, err := repo.TreeObject(c.TreeHash)
|
|
if err != nil {
|
|
return fmt.Errorf("failed to get commit tree: %v", err)
|
|
}
|
|
f, err := traverseTree(root, path)
|
|
if err == object.ErrFileNotFound || err == object.ErrDirectoryNotFound {
|
|
// Ignoring file not found errors.
|
|
return nil
|
|
} else if err != nil {
|
|
return err
|
|
}
|
|
sum, err := getReaderHash(f)
|
|
f.Close()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
hashHistory = append(hashHistory, sum)
|
|
return nil
|
|
})
|
|
if cerr != nil && cerr != io.EOF {
|
|
return nil, cerr
|
|
}
|
|
if len(hashHistory) == 0 {
|
|
return nil, ErrNotFound
|
|
}
|
|
return hashHistory, nil
|
|
}
|
|
|
|
func traverseTree(root *object.Tree, path string) (io.ReadCloser, error) {
|
|
dirName, fileName := filepath.Split(path)
|
|
var err error
|
|
t := root
|
|
if dirName != "" {
|
|
t, err = root.Tree(filepath.Clean(dirName))
|
|
if err == object.ErrDirectoryNotFound {
|
|
return nil, err
|
|
} else if err != nil {
|
|
return nil, fmt.Errorf("failed to traverse tree to %q: %v", dirName, err)
|
|
}
|
|
}
|
|
f, err := t.File(fileName)
|
|
if err == object.ErrFileNotFound {
|
|
return nil, err
|
|
} else if err != nil {
|
|
return nil, fmt.Errorf("failed to lookup file %q: %v", fileName, err)
|
|
}
|
|
reader, err := f.Reader()
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to open %q: %v", path, err)
|
|
}
|
|
return reader, nil
|
|
}
|
|
|
|
func getReaderHash(r io.Reader) (string, error) {
|
|
h := sha1.New() // nolint
|
|
_, err := io.Copy(h, r)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
return hex.EncodeToString(h.Sum(nil)), nil
|
|
}
|
|
|
|
// GetFileHash calculates the sha1 hash sum of the file.
|
|
func GetFileHash(path string) (string, error) {
|
|
f, err := os.Open(path)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
defer f.Close()
|
|
sum, err := getReaderHash(f)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
return sum, nil
|
|
}
|