2015-05-04 05:36:34 +00:00
|
|
|
package commands
|
|
|
|
|
|
|
|
import (
|
|
|
|
"crypto/sha256"
|
|
|
|
"encoding/hex"
|
|
|
|
"io"
|
|
|
|
"os"
|
|
|
|
"path/filepath"
|
|
|
|
|
|
|
|
"github.com/github/git-lfs/git"
|
|
|
|
"github.com/github/git-lfs/lfs"
|
|
|
|
"github.com/github/git-lfs/vendor/_nuts/github.com/spf13/cobra"
|
|
|
|
)
|
|
|
|
|
|
|
|
var (
|
|
|
|
fsckCmd = &cobra.Command{
|
|
|
|
Use: "fsck",
|
|
|
|
Short: "Verifies validity of Git LFS files",
|
|
|
|
Run: fsckCommand,
|
|
|
|
}
|
|
|
|
)
|
|
|
|
|
2015-05-08 16:20:02 +00:00
|
|
|
func doFsck(localGitDir string) (bool, error) {
|
2015-05-04 05:36:34 +00:00
|
|
|
ref, err := git.CurrentRef()
|
|
|
|
if err != nil {
|
2015-05-08 16:20:02 +00:00
|
|
|
return false, err
|
2015-05-04 05:36:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
pointers, err := lfs.ScanRefs(ref, "")
|
|
|
|
if err != nil {
|
2015-05-08 16:20:02 +00:00
|
|
|
return false, err
|
2015-05-04 05:36:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// TODO(zeroshirts): do we want to look for LFS stuff in past commits?
|
|
|
|
p2, err := lfs.ScanIndex()
|
|
|
|
if err != nil {
|
2015-05-08 16:20:02 +00:00
|
|
|
return false, err
|
2015-05-04 05:36:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// zeroshirts: assuming no duplicates...
|
|
|
|
pointers = append(pointers, p2...)
|
|
|
|
|
2015-05-08 16:20:02 +00:00
|
|
|
ok := true
|
|
|
|
|
2015-05-04 05:36:34 +00:00
|
|
|
for _, p := range pointers {
|
|
|
|
path := filepath.Join(localGitDir, "lfs", "objects", p.Pointer.Oid[0:2], p.Pointer.Oid[2:4], p.Pointer.Oid)
|
|
|
|
|
|
|
|
Debug("Examining %v (%v)", p.Name, path)
|
|
|
|
|
|
|
|
f, err := os.Open(path)
|
|
|
|
if err != nil {
|
2015-05-08 16:20:02 +00:00
|
|
|
return false, err
|
2015-05-04 05:36:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
oidHash := sha256.New()
|
|
|
|
_, err = io.Copy(oidHash, f)
|
|
|
|
f.Close()
|
|
|
|
if err != nil {
|
2015-05-08 16:20:02 +00:00
|
|
|
return false, err
|
2015-05-04 05:36:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
recalculatedOid := hex.EncodeToString(oidHash.Sum(nil))
|
|
|
|
if recalculatedOid != p.Pointer.Oid {
|
2015-05-08 16:20:02 +00:00
|
|
|
ok = false
|
|
|
|
Print("Object %s (%s) is corrupt", p.Name, p.Oid)
|
2015-05-08 16:29:16 +00:00
|
|
|
os.RemoveAll(path)
|
2015-05-04 05:36:34 +00:00
|
|
|
}
|
|
|
|
}
|
2015-05-08 16:20:02 +00:00
|
|
|
return ok, nil
|
2015-05-04 05:36:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// TODO(zeroshirts): 'git fsck' reports status (percentage, current#/total) as
|
|
|
|
// it checks... we should do the same, as we are rehashing potentially gigs and
|
|
|
|
// gigs of content.
|
|
|
|
//
|
|
|
|
// NOTE(zeroshirts): Ideally git would have hooks for fsck such that we could
|
|
|
|
// chain a lfs-fsck, but I don't think it does.
|
|
|
|
func fsckCommand(cmd *cobra.Command, args []string) {
|
|
|
|
lfs.InstallHooks(false)
|
|
|
|
|
2015-05-08 16:20:02 +00:00
|
|
|
ok, err := doFsck(lfs.LocalGitDir)
|
2015-05-04 05:36:34 +00:00
|
|
|
if err != nil {
|
2015-05-08 16:20:02 +00:00
|
|
|
Panic(err, "Error checking Git LFS files")
|
|
|
|
}
|
|
|
|
|
|
|
|
if ok {
|
|
|
|
Print("Git LFS fsck OK")
|
2015-05-04 05:36:34 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func init() {
|
|
|
|
RootCmd.AddCommand(fsckCmd)
|
|
|
|
}
|