git-lfs/commands/command_fsck.go

99 lines
2.0 KiB
Go
Raw Normal View History

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,
}
)
func doFsck(localGitDir string) (bool, error) {
2015-05-04 05:36:34 +00:00
ref, err := git.CurrentRef()
if err != nil {
return false, err
2015-05-04 05:36:34 +00:00
}
pointers, err := lfs.ScanRefs(ref, "")
if err != nil {
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 {
return false, err
2015-05-04 05:36:34 +00:00
}
// zeroshirts: assuming no duplicates...
pointers = append(pointers, p2...)
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 pErr, pOk := err.(*os.PathError); pOk {
Print("Object %s (%s) could not be checked: %s", name, oid, pErr.Err)
ok = false
continue
}
2015-05-04 05:36:34 +00:00
if err != nil {
return false, err
2015-05-04 05:36:34 +00:00
}
oidHash := sha256.New()
_, err = io.Copy(oidHash, f)
f.Close()
if err != nil {
return false, err
2015-05-04 05:36:34 +00:00
}
recalculatedOid := hex.EncodeToString(oidHash.Sum(nil))
if recalculatedOid != p.Pointer.Oid {
ok = false
Print("Object %s (%s) is corrupt", p.Name, p.Oid)
os.RemoveAll(path)
2015-05-04 05:36:34 +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)
ok, err := doFsck(lfs.LocalGitDir)
2015-05-04 05:36:34 +00:00
if err != nil {
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)
}