Skip to content

Commit a7329d3

Browse files
Merge pull request #2 from github/stolee/cli-1
`git-bundle-server` CLI Part 1: `init` and `update`
2 parents 444b188 + 1b1f540 commit a7329d3

File tree

12 files changed

+559
-15
lines changed

12 files changed

+559
-15
lines changed

.gitignore

Lines changed: 1 addition & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1 @@
1-
# Binaries for programs and plugins
2-
*.exe
3-
*.exe~
4-
*.dll
5-
*.so
6-
*.dylib
7-
8-
# Test binary, built with `go test -c`
9-
*.test
10-
11-
# Output of the go coverage tool, specifically when used with LiteIDE
12-
*.out
13-
14-
# Dependency directories (remove the comment below to include it)
15-
# vendor/
1+
/git-bundle-server

README.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,16 @@ By running this software, you can self-host a bundle server to work with Git's
55

66
[bundle-uris]: https://github.com/git/git/blob/next/Documentation/technical/bundle-uri.txt
77

8+
## Cloning and Building
9+
10+
Be sure to clone inside the `src` directory of your `GOROOT`.
11+
12+
Once there, you can build the `git-bundle-server` executable with
13+
14+
```ShellSession
15+
$ go build git-bundle-server/cmd/git-bundle-server
16+
```
17+
818
## Bundle Management through CLI
919

1020
The following command-line interface allows you to manage which repositories are

cmd/git-bundle-server/init.go

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
package main
2+
3+
import (
4+
"errors"
5+
"fmt"
6+
"git-bundle-server/internal/bundles"
7+
"git-bundle-server/internal/core"
8+
"git-bundle-server/internal/git"
9+
)
10+
11+
type Init struct{}
12+
13+
func (Init) subcommand() string {
14+
return "init"
15+
}
16+
17+
func (Init) run(args []string) error {
18+
if len(args) < 2 {
19+
// TODO: allow parsing <route> out of <url>
20+
return errors.New("usage: git-bundle-server init <url> <route>")
21+
}
22+
23+
url := args[0]
24+
route := args[1]
25+
26+
repo := core.GetRepository(route)
27+
28+
fmt.Printf("Cloning repository from %s\n", url)
29+
gitErr := git.GitCommand("clone", "--mirror", url, repo.RepoDir)
30+
31+
if gitErr != nil {
32+
return fmt.Errorf("failed to clone repository: %w", gitErr)
33+
}
34+
35+
bundle := bundles.CreateInitialBundle(repo)
36+
fmt.Printf("Constructing base bundle file at %s\n", bundle.Filename)
37+
38+
written, gitErr := git.CreateBundle(repo, bundle)
39+
if gitErr != nil {
40+
return fmt.Errorf("failed to create bundle: %w", gitErr)
41+
}
42+
if !written {
43+
return fmt.Errorf("refused to write empty bundle. Is the repo empty?")
44+
}
45+
46+
list := bundles.SingletonList(bundle)
47+
listErr := bundles.WriteBundleList(list, repo)
48+
if listErr != nil {
49+
return fmt.Errorf("failed to write bundle list: %w", listErr)
50+
}
51+
52+
return nil
53+
}

cmd/git-bundle-server/main.go

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
package main
2+
3+
import (
4+
"log"
5+
"os"
6+
)
7+
8+
func main() {
9+
cmds := all()
10+
11+
if len(os.Args) < 2 {
12+
log.Fatal("usage: git-bundle-server <command> [<options>]\n")
13+
return
14+
}
15+
16+
for i := 0; i < len(cmds); i++ {
17+
if cmds[i].subcommand() == os.Args[1] {
18+
err := cmds[i].run(os.Args[2:])
19+
if err != nil {
20+
log.Fatal("Failed with error: ", err)
21+
}
22+
}
23+
}
24+
}

cmd/git-bundle-server/subcommand.go

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
package main
2+
3+
type Subcommand interface {
4+
subcommand() string
5+
run(args []string) error
6+
}
7+
8+
func all() []Subcommand {
9+
return []Subcommand{
10+
Init{},
11+
Update{},
12+
}
13+
}

cmd/git-bundle-server/update.go

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
package main
2+
3+
import (
4+
"errors"
5+
"fmt"
6+
"git-bundle-server/internal/bundles"
7+
"git-bundle-server/internal/core"
8+
"git-bundle-server/internal/git"
9+
)
10+
11+
type Update struct{}
12+
13+
func (Update) subcommand() string {
14+
return "update"
15+
}
16+
17+
func (Update) run(args []string) error {
18+
if len(args) != 1 {
19+
// TODO: allow parsing <route> out of <url>
20+
return errors.New("usage: git-bundle-server update <route>")
21+
}
22+
23+
route := args[0]
24+
repo := core.GetRepository(route)
25+
26+
list, err := bundles.GetBundleList(repo)
27+
if err != nil {
28+
return fmt.Errorf("failed to load bundle list: %w", err)
29+
}
30+
31+
bundle := bundles.CreateDistinctBundle(repo, *list)
32+
33+
fmt.Printf("Constructing incremental bundle file at %s\n", bundle.Filename)
34+
35+
written, err := git.CreateIncrementalBundle(repo, bundle, *list)
36+
if err != nil {
37+
return fmt.Errorf("failed to create incremental bundle: %w", err)
38+
}
39+
40+
// Nothing to update
41+
if !written {
42+
return nil
43+
}
44+
45+
list.Bundles[bundle.CreationToken] = bundle
46+
47+
fmt.Printf("Writing updated bundle list\n")
48+
listErr := bundles.WriteBundleList(*list, repo)
49+
if listErr != nil {
50+
return fmt.Errorf("failed to write bundle list: %w", listErr)
51+
}
52+
53+
return nil
54+
}

go.mod

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
module git-bundle-server
2+
3+
go 1.18

0 commit comments

Comments
 (0)