8311: Add git_tree mount type.
[arvados.git] / services / crunch-run / git_mount.go
1 package main
2
3 import (
4         "fmt"
5         "net/url"
6
7         "git.curoverse.com/arvados.git/sdk/go/arvados"
8         "git.curoverse.com/arvados.git/sdk/go/arvadostest"
9         "gopkg.in/src-d/go-billy.v3/osfs"
10         git "gopkg.in/src-d/go-git.v4"
11         git_config "gopkg.in/src-d/go-git.v4/config"
12         git_plumbing "gopkg.in/src-d/go-git.v4/plumbing"
13         git_http "gopkg.in/src-d/go-git.v4/plumbing/transport/http"
14         "gopkg.in/src-d/go-git.v4/storage/memory"
15 )
16
17 type gitMount arvados.Mount
18
19 func (gm gitMount) validate() error {
20         if gm.Path != "/" {
21                 return fmt.Errorf("cannot mount git_tree path %q -- only \"/\" is supported", gm.Path)
22         }
23         return nil
24 }
25
26 // ExtractTree extracts the specified tree into dir, which is an
27 // existing empty local directory.
28 func (gm gitMount) extractTree(ac IArvadosClient, dir string) error {
29         err := gm.validate()
30         if err != nil {
31                 return err
32         }
33         baseURL, err := ac.Discovery("gitUrl")
34         if err != nil {
35                 return fmt.Errorf("discover gitUrl from API: %s", err)
36         }
37         u, err := url.Parse(baseURL.(string))
38         if err != nil {
39                 return fmt.Errorf("parse gitUrl %q: %s", baseURL, err)
40         }
41         u, err = u.Parse("/" + gm.UUID + ".git")
42         if err != nil {
43                 return fmt.Errorf("build git url from %q, %q: %s", baseURL, gm.UUID, err)
44         }
45         store := memory.NewStorage()
46         repo, err := git.Init(store, osfs.New(dir))
47         if err != nil {
48                 return fmt.Errorf("init repo: %s", err)
49         }
50         _, err = repo.CreateRemote(&git_config.RemoteConfig{
51                 Name: "origin",
52                 URLs: []string{u.String()},
53         })
54         if err != nil {
55                 return fmt.Errorf("create remote %q: %s", u.String(), err)
56         }
57         err = repo.Fetch(&git.FetchOptions{
58                 RemoteName: "origin",
59                 Auth:       git_http.NewBasicAuth("none", arvadostest.ActiveToken),
60         })
61         if err != nil {
62                 return fmt.Errorf("git fetch %q: %s", u.String(), err)
63         }
64         wt, err := repo.Worktree()
65         if err != nil {
66                 return fmt.Errorf("worktree failed: %s", err)
67         }
68         err = wt.Checkout(&git.CheckoutOptions{
69                 Hash: git_plumbing.NewHash(gm.Commit),
70         })
71         if err != nil {
72                 return fmt.Errorf("checkout failed: %s", err)
73         }
74         return nil
75 }