Skip to content

Commit 323efc1

Browse files
feat: add server-side git commands (#96)
Co-authored-by: Joe Chen <[email protected]>
1 parent bd58efd commit 323efc1

File tree

3 files changed

+156
-1
lines changed

3 files changed

+156
-1
lines changed

repo_reference.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -255,7 +255,7 @@ func (r *Repository) Branches() ([]string, error) {
255255

256256
// DeleteBranchOptions contains optional arguments for deleting a branch.
257257
//
258-
// // Docs: https://git-scm.com/docs/git-branch
258+
// Docs: https://git-scm.com/docs/git-branch
259259
type DeleteBranchOptions struct {
260260
// Indicates whether to force delete the branch.
261261
Force bool

server.go

+113
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
// Copyright 2023 The Gogs Authors. All rights reserved.
2+
// Use of this source code is governed by a MIT-style
3+
// license that can be found in the LICENSE file.
4+
5+
package git
6+
7+
import (
8+
"time"
9+
)
10+
11+
// UpdateServerInfoOptions contains optional arguments for updating auxiliary
12+
// info file on the server side.
13+
//
14+
// Docs: https://git-scm.com/docs/git-update-server-info
15+
type UpdateServerInfoOptions struct {
16+
// Indicates whether to overwrite the existing server info.
17+
Force bool
18+
// The timeout duration before giving up for each shell command execution. The
19+
// default timeout duration will be used when not supplied.
20+
Timeout time.Duration
21+
// The additional options to be passed to the underlying git.
22+
CommandOptions
23+
}
24+
25+
// UpdateServerInfo updates the auxiliary info file on the server side for the
26+
// repository in given path.
27+
func UpdateServerInfo(path string, opts ...UpdateServerInfoOptions) error {
28+
var opt UpdateServerInfoOptions
29+
if len(opts) > 0 {
30+
opt = opts[0]
31+
}
32+
cmd := NewCommand("update-server-info").AddOptions(opt.CommandOptions)
33+
if opt.Force {
34+
cmd.AddArgs("--force")
35+
}
36+
_, err := cmd.RunInDirWithTimeout(opt.Timeout, path)
37+
return err
38+
}
39+
40+
// ReceivePackOptions contains optional arguments for receiving the info pushed
41+
// to the repository.
42+
//
43+
// Docs: https://git-scm.com/docs/git-receive-pack
44+
type ReceivePackOptions struct {
45+
// Indicates whether to suppress the log output.
46+
Quiet bool
47+
// Indicates whether to generate the "info/refs" used by the "git http-backend".
48+
HTTPBackendInfoRefs bool
49+
// The timeout duration before giving up for each shell command execution. The
50+
// default timeout duration will be used when not supplied.
51+
Timeout time.Duration
52+
// The additional options to be passed to the underlying git.
53+
CommandOptions
54+
}
55+
56+
// ReceivePack receives what is pushed into the repository in given path.
57+
func ReceivePack(path string, opts ...ReceivePackOptions) ([]byte, error) {
58+
var opt ReceivePackOptions
59+
if len(opts) > 0 {
60+
opt = opts[0]
61+
}
62+
cmd := NewCommand("receive-pack").AddOptions(opt.CommandOptions)
63+
if opt.Quiet {
64+
cmd.AddArgs("--quiet")
65+
}
66+
if opt.HTTPBackendInfoRefs {
67+
cmd.AddArgs("--http-backend-info-refs")
68+
}
69+
cmd.AddArgs(".")
70+
return cmd.RunInDirWithTimeout(opt.Timeout, path)
71+
}
72+
73+
// UploadPackOptions contains optional arguments for sending the packfile to the
74+
// client.
75+
//
76+
// Docs: https://git-scm.com/docs/git-upload-pack
77+
type UploadPackOptions struct {
78+
// Indicates whether to quit after a single request/response exchange.
79+
StatelessRPC bool
80+
// Indicates whether to not try "<directory>/.git/" if "<directory>" is not a
81+
// Git directory.
82+
Strict bool
83+
// Indicates whether to generate the "info/refs" used by the "git http-backend".
84+
HTTPBackendInfoRefs bool
85+
// The timeout duration before giving up for each shell command execution. The
86+
// default timeout duration will be used when not supplied.
87+
Timeout time.Duration
88+
// The additional options to be passed to the underlying git.
89+
CommandOptions
90+
}
91+
92+
// UploadPack sends the packfile to the client for the repository in given path.
93+
func UploadPack(path string, opts ...UploadPackOptions) ([]byte, error) {
94+
var opt UploadPackOptions
95+
if len(opts) > 0 {
96+
opt = opts[0]
97+
}
98+
cmd := NewCommand("upload-pack").AddOptions(opt.CommandOptions)
99+
if opt.StatelessRPC {
100+
cmd.AddArgs("--stateless-rpc")
101+
}
102+
if opt.Strict {
103+
cmd.AddArgs("--strict")
104+
}
105+
if opt.Timeout > 0 {
106+
cmd.AddArgs("--timeout", opt.Timeout.String())
107+
}
108+
if opt.HTTPBackendInfoRefs {
109+
cmd.AddArgs("--http-backend-info-refs")
110+
}
111+
cmd.AddArgs(".")
112+
return cmd.RunInDirWithTimeout(opt.Timeout, path)
113+
}

server_test.go

+42
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
// Copyright 2023 The Gogs Authors. All rights reserved.
2+
// Use of this source code is governed by a MIT-style
3+
// license that can be found in the LICENSE file.
4+
5+
package git
6+
7+
import (
8+
"os"
9+
"path/filepath"
10+
"testing"
11+
12+
"github.com/stretchr/testify/assert"
13+
"github.com/stretchr/testify/require"
14+
)
15+
16+
func TestUpdateServerInfo(t *testing.T) {
17+
err := os.RemoveAll(filepath.Join(repoPath, "info"))
18+
require.NoError(t, err)
19+
err = UpdateServerInfo(repoPath, UpdateServerInfoOptions{Force: true})
20+
require.NoError(t, err)
21+
assert.True(t, isFile(filepath.Join(repoPath, "info", "refs")))
22+
}
23+
24+
func TestReceivePack(t *testing.T) {
25+
got, err := ReceivePack(repoPath, ReceivePackOptions{HTTPBackendInfoRefs: true})
26+
require.NoError(t, err)
27+
const contains = "report-status report-status-v2 delete-refs side-band-64k quiet atomic ofs-delta object-format=sha1 agent=git/"
28+
assert.Contains(t, string(got), contains)
29+
}
30+
31+
func TestUploadPack(t *testing.T) {
32+
got, err := UploadPack(repoPath,
33+
UploadPackOptions{
34+
StatelessRPC: true,
35+
Strict: true,
36+
HTTPBackendInfoRefs: true,
37+
},
38+
)
39+
require.NoError(t, err)
40+
const contains = "multi_ack thin-pack side-band side-band-64k ofs-delta shallow deepen-since deepen-not deepen-relative no-progress include-tag multi_ack_detailed no-done symref=HEAD:refs/heads/master object-format=sha1 agent=git/"
41+
assert.Contains(t, string(got), contains)
42+
}

0 commit comments

Comments
 (0)