git-lfs/commands/command_track.go

175 lines
3.6 KiB
Go
Raw Normal View History

2015-03-22 18:50:06 +00:00
package commands
import (
"bufio"
"fmt"
"io"
"os"
"path/filepath"
"strings"
2015-05-13 19:43:41 +00:00
"github.com/github/git-lfs/lfs"
2015-05-25 18:20:50 +00:00
"github.com/github/git-lfs/vendor/_nuts/github.com/spf13/cobra"
2015-03-22 18:50:06 +00:00
)
var (
trackCmd = &cobra.Command{
Use: "track",
Short: "Manipulate .gitattributes",
Run: trackCommand,
}
)
func trackCommand(cmd *cobra.Command, args []string) {
if lfs.LocalGitDir == "" {
Print("Not a git repository.")
os.Exit(128)
}
if lfs.LocalWorkingDir == "" {
Print("This operation must be run in a work tree.")
os.Exit(128)
}
2015-03-22 18:50:06 +00:00
lfs.InstallHooks(false)
knownPaths := findPaths()
2015-03-22 18:50:06 +00:00
if len(args) == 0 {
Print("Listing tracked paths")
for _, t := range knownPaths {
Print(" %s (%s)", t.Path, t.Source)
}
return
}
addTrailingLinebreak := needsTrailingLinebreak(".gitattributes")
attributesFile, err := os.OpenFile(".gitattributes", os.O_RDWR|os.O_APPEND|os.O_CREATE, 0660)
if err != nil {
Print("Error opening .gitattributes file")
return
}
defer attributesFile.Close()
2015-03-22 18:50:06 +00:00
if addTrailingLinebreak {
if _, err := attributesFile.WriteString("\n"); err != nil {
Print("Error writing to .gitattributes")
}
}
2015-06-01 10:48:06 +00:00
wd, _ := os.Getwd()
ArgsLoop:
2015-03-22 18:50:06 +00:00
for _, t := range args {
absT, relT := absRelPath(t, wd)
2015-06-01 12:15:12 +00:00
if !filepath.HasPrefix(absT, lfs.LocalWorkingDir) {
Print("%s is outside repository", t)
os.Exit(128)
2015-03-22 18:50:06 +00:00
}
for _, k := range knownPaths {
2015-06-01 10:48:06 +00:00
absK, _ := absRelPath(k.Path, filepath.Join(wd, filepath.Dir(k.Source)))
if absT == absK {
Print("%s already supported", t)
continue ArgsLoop
2015-03-22 18:50:06 +00:00
}
}
encodedArg := strings.Replace(relT, " ", "[[:space:]]", -1)
2015-07-09 16:01:50 +00:00
_, err := attributesFile.WriteString(fmt.Sprintf("%s filter=lfs diff=lfs merge=lfs -text\n", encodedArg))
2015-03-22 18:50:06 +00:00
if err != nil {
Print("Error adding path %s", t)
continue
}
Print("Tracking %s", t)
}
}
type mediaPath struct {
Path string
Source string
}
func findPaths() []mediaPath {
paths := make([]mediaPath, 0)
wd, _ := os.Getwd()
for _, path := range findAttributeFiles() {
attributes, err := os.Open(path)
if err != nil {
continue
2015-03-22 18:50:06 +00:00
}
scanner := bufio.NewScanner(attributes)
for scanner.Scan() {
line := scanner.Text()
if strings.Contains(line, "filter=lfs") {
fields := strings.Fields(line)
relPath, _ := filepath.Rel(wd, path)
paths = append(paths, mediaPath{Path: fields[0], Source: relPath})
}
}
}
return paths
}
2015-05-31 21:31:23 +00:00
func findAttributeFiles() []string {
paths := make([]string, 0)
repoAttributes := filepath.Join(lfs.LocalGitDir, "info", "attributes")
if info, err := os.Stat(repoAttributes); err == nil && !info.IsDir() {
2015-05-31 21:31:23 +00:00
paths = append(paths, repoAttributes)
}
filepath.Walk(lfs.LocalWorkingDir, func(path string, info os.FileInfo, err error) error {
if err != nil {
return err
}
if !info.IsDir() && (filepath.Base(path) == ".gitattributes") {
paths = append(paths, path)
}
return nil
})
return paths
}
2015-03-22 18:50:06 +00:00
func needsTrailingLinebreak(filename string) bool {
file, err := os.Open(filename)
if err != nil {
return false
}
defer file.Close()
2015-03-22 18:50:06 +00:00
buf := make([]byte, 16384)
bytesRead := 0
for {
n, err := file.Read(buf)
if err == io.EOF {
break
} else if err != nil {
return false
}
bytesRead = n
}
return !strings.HasSuffix(string(buf[0:bytesRead]), "\n")
}
2015-06-01 10:48:06 +00:00
// absRelPath takes a path and a working directory and
// returns an absolute and a relative representation of path based on the working directory
func absRelPath(path, wd string) (string, string) {
if filepath.IsAbs(path) {
relPath, _ := filepath.Rel(wd, path)
return path, relPath
}
absPath := filepath.Join(wd, path)
return absPath, path
}
2015-03-22 18:50:06 +00:00
func init() {
RootCmd.AddCommand(trackCmd)
}