1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109
|
package main
import (
"fmt"
"io"
"os"
"path/filepath"
"strings"
"time"
"github.com/charmbracelet/git-lfs-transfer/internal/local"
"github.com/charmbracelet/git-lfs-transfer/transfer"
"github.com/rubyist/tracerx"
)
func ensureDirs(path string) error {
for _, dir := range []string{
"objects", "incomplete", "tmp", "locks",
} {
if err := os.MkdirAll(filepath.Join(path, dir), os.ModePerm); err != nil {
return err
}
}
return nil
}
// Run runs the git-lfs-transfer command against the given I/O and arguments.
func Run(r io.Reader, w io.Writer, args ...string) error {
if len(args) != 2 {
return fmt.Errorf("expected 2 arguments, got %d", len(args))
}
path := args[0]
op := args[1]
_, err := os.Stat(path)
if err != nil {
return err
}
gitdir := path
if !strings.HasSuffix(path, ".git") {
gitdir = filepath.Join(path, ".git")
}
lfsPath := filepath.Join(gitdir, "lfs")
if err := ensureDirs(lfsPath); err != nil {
return err
}
umask := setPermissions(gitdir)
handler := transfer.NewPktline(r, w, logger)
for _, cap := range transfer.Capabilities {
if err := handler.WritePacketText(cap); err != nil {
logger.Log("error sending capability", "cap", cap, "err", err)
}
}
if err := handler.WriteFlush(); err != nil {
logger.Log("error flushing capabilities", "err", err)
}
now := time.Now()
logger.Log("umask", "umask", umask)
backend := local.New(lfsPath, umask, &now)
p := transfer.NewProcessor(handler, backend, logger)
defer logger.Log("done processing commands")
switch op {
case "upload":
return p.ProcessCommands(transfer.UploadOperation)
case "download":
return p.ProcessCommands(transfer.DownloadOperation)
default:
return fmt.Errorf("unknown operation %q", op)
}
}
// Usage returns the command usage.
func Usage() string {
return `Git LFS SSH transfer agent
Usage:
git-lfs-transfer PATH OPERATION
`
}
func init() {
tracerx.DefaultKey = "GIT"
tracerx.Prefix = "trace git-lfs-transfer: "
}
// Command is the main git-lfs-transfer entry.
func Command(stdin io.Reader, stdout io.Writer, stderr io.Writer, args ...string) error {
done := make(chan os.Signal, 1)
errc := make(chan error, 1)
setup(done)
logger.Log("git-lfs-transfer", "version", "v1")
defer logger.Log("git-lfs-transfer completed")
go func() {
errc <- Run(stdin, stdout, args...)
}()
select {
case s := <-done:
logger.Log("signal received", "signal", s)
case err := <-errc:
logger.Log("done running")
fmt.Fprintln(stderr, Usage())
fmt.Fprintln(stderr, err)
if err != nil {
return err
}
}
return nil
}
|