1package fakegit // import "github.com/docker/docker/testutil/fakegit"
2
3import (
4	"fmt"
5	"io/ioutil"
6	"net/http"
7	"net/http/httptest"
8	"os"
9	"os/exec"
10	"path/filepath"
11	"testing"
12
13	"github.com/docker/docker/testutil/fakecontext"
14	"github.com/docker/docker/testutil/fakestorage"
15)
16
17type gitServer interface {
18	URL() string
19	Close() error
20}
21
22type localGitServer struct {
23	*httptest.Server
24}
25
26func (r *localGitServer) Close() error {
27	r.Server.Close()
28	return nil
29}
30
31func (r *localGitServer) URL() string {
32	return r.Server.URL
33}
34
35// FakeGit is a fake git server
36type FakeGit struct {
37	root    string
38	server  gitServer
39	RepoURL string
40}
41
42// Close closes the server, implements Closer interface
43func (g *FakeGit) Close() {
44	g.server.Close()
45	os.RemoveAll(g.root)
46}
47
48// New create a fake git server that can be used for git related tests
49func New(c testing.TB, name string, files map[string]string, enforceLocalServer bool) *FakeGit {
50	c.Helper()
51	ctx := fakecontext.New(c, "", fakecontext.WithFiles(files))
52	defer ctx.Close()
53	curdir, err := os.Getwd()
54	if err != nil {
55		c.Fatal(err)
56	}
57	defer os.Chdir(curdir)
58
59	if output, err := exec.Command("git", "init", ctx.Dir).CombinedOutput(); err != nil {
60		c.Fatalf("error trying to init repo: %s (%s)", err, output)
61	}
62	err = os.Chdir(ctx.Dir)
63	if err != nil {
64		c.Fatal(err)
65	}
66	if output, err := exec.Command("git", "config", "user.name", "Fake User").CombinedOutput(); err != nil {
67		c.Fatalf("error trying to set 'user.name': %s (%s)", err, output)
68	}
69	if output, err := exec.Command("git", "config", "user.email", "fake.user@example.com").CombinedOutput(); err != nil {
70		c.Fatalf("error trying to set 'user.email': %s (%s)", err, output)
71	}
72	if output, err := exec.Command("git", "add", "*").CombinedOutput(); err != nil {
73		c.Fatalf("error trying to add files to repo: %s (%s)", err, output)
74	}
75	if output, err := exec.Command("git", "commit", "-a", "-m", "Initial commit").CombinedOutput(); err != nil {
76		c.Fatalf("error trying to commit to repo: %s (%s)", err, output)
77	}
78
79	root, err := ioutil.TempDir("", "docker-test-git-repo")
80	if err != nil {
81		c.Fatal(err)
82	}
83	repoPath := filepath.Join(root, name+".git")
84	if output, err := exec.Command("git", "clone", "--bare", ctx.Dir, repoPath).CombinedOutput(); err != nil {
85		os.RemoveAll(root)
86		c.Fatalf("error trying to clone --bare: %s (%s)", err, output)
87	}
88	err = os.Chdir(repoPath)
89	if err != nil {
90		os.RemoveAll(root)
91		c.Fatal(err)
92	}
93	if output, err := exec.Command("git", "update-server-info").CombinedOutput(); err != nil {
94		os.RemoveAll(root)
95		c.Fatalf("error trying to git update-server-info: %s (%s)", err, output)
96	}
97	err = os.Chdir(curdir)
98	if err != nil {
99		os.RemoveAll(root)
100		c.Fatal(err)
101	}
102
103	var server gitServer
104	if !enforceLocalServer {
105		// use fakeStorage server, which might be local or remote (at test daemon)
106		server = fakestorage.New(c, root)
107	} else {
108		// always start a local http server on CLI test machine
109		httpServer := httptest.NewServer(http.FileServer(http.Dir(root)))
110		server = &localGitServer{httpServer}
111	}
112	return &FakeGit{
113		root:    root,
114		server:  server,
115		RepoURL: fmt.Sprintf("%s/%s.git", server.URL(), name),
116	}
117}
118