diff --git a/repo_reference.go b/repo_reference.go index c4d1c69d..9da086ce 100644 --- a/repo_reference.go +++ b/repo_reference.go @@ -255,7 +255,7 @@ func (r *Repository) Branches() ([]string, error) { // DeleteBranchOptions contains optional arguments for deleting a branch. // -// // Docs: https://git-scm.com/docs/git-branch +// Docs: https://git-scm.com/docs/git-branch type DeleteBranchOptions struct { // Indicates whether to force delete the branch. Force bool diff --git a/server.go b/server.go new file mode 100755 index 00000000..0c2d275e --- /dev/null +++ b/server.go @@ -0,0 +1,113 @@ +// Copyright 2023 The Gogs Authors. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. + +package git + +import ( + "time" +) + +// UpdateServerInfoOptions contains optional arguments for updating auxiliary +// info file on the server side. +// +// Docs: https://git-scm.com/docs/git-update-server-info +type UpdateServerInfoOptions struct { + // Indicates whether to overwrite the existing server info. + Force bool + // The timeout duration before giving up for each shell command execution. The + // default timeout duration will be used when not supplied. + Timeout time.Duration + // The additional options to be passed to the underlying git. + CommandOptions +} + +// UpdateServerInfo updates the auxiliary info file on the server side for the +// repository in given path. +func UpdateServerInfo(path string, opts ...UpdateServerInfoOptions) error { + var opt UpdateServerInfoOptions + if len(opts) > 0 { + opt = opts[0] + } + cmd := NewCommand("update-server-info").AddOptions(opt.CommandOptions) + if opt.Force { + cmd.AddArgs("--force") + } + _, err := cmd.RunInDirWithTimeout(opt.Timeout, path) + return err +} + +// ReceivePackOptions contains optional arguments for receiving the info pushed +// to the repository. +// +// Docs: https://git-scm.com/docs/git-receive-pack +type ReceivePackOptions struct { + // Indicates whether to suppress the log output. + Quiet bool + // Indicates whether to generate the "info/refs" used by the "git http-backend". + HTTPBackendInfoRefs bool + // The timeout duration before giving up for each shell command execution. The + // default timeout duration will be used when not supplied. + Timeout time.Duration + // The additional options to be passed to the underlying git. + CommandOptions +} + +// ReceivePack receives what is pushed into the repository in given path. +func ReceivePack(path string, opts ...ReceivePackOptions) ([]byte, error) { + var opt ReceivePackOptions + if len(opts) > 0 { + opt = opts[0] + } + cmd := NewCommand("receive-pack").AddOptions(opt.CommandOptions) + if opt.Quiet { + cmd.AddArgs("--quiet") + } + if opt.HTTPBackendInfoRefs { + cmd.AddArgs("--http-backend-info-refs") + } + cmd.AddArgs(".") + return cmd.RunInDirWithTimeout(opt.Timeout, path) +} + +// UploadPackOptions contains optional arguments for sending the packfile to the +// client. +// +// Docs: https://git-scm.com/docs/git-upload-pack +type UploadPackOptions struct { + // Indicates whether to quit after a single request/response exchange. + StatelessRPC bool + // Indicates whether to not try "/.git/" if "" is not a + // Git directory. + Strict bool + // Indicates whether to generate the "info/refs" used by the "git http-backend". + HTTPBackendInfoRefs bool + // The timeout duration before giving up for each shell command execution. The + // default timeout duration will be used when not supplied. + Timeout time.Duration + // The additional options to be passed to the underlying git. + CommandOptions +} + +// UploadPack sends the packfile to the client for the repository in given path. +func UploadPack(path string, opts ...UploadPackOptions) ([]byte, error) { + var opt UploadPackOptions + if len(opts) > 0 { + opt = opts[0] + } + cmd := NewCommand("upload-pack").AddOptions(opt.CommandOptions) + if opt.StatelessRPC { + cmd.AddArgs("--stateless-rpc") + } + if opt.Strict { + cmd.AddArgs("--strict") + } + if opt.Timeout > 0 { + cmd.AddArgs("--timeout", opt.Timeout.String()) + } + if opt.HTTPBackendInfoRefs { + cmd.AddArgs("--http-backend-info-refs") + } + cmd.AddArgs(".") + return cmd.RunInDirWithTimeout(opt.Timeout, path) +} diff --git a/server_test.go b/server_test.go new file mode 100755 index 00000000..b8d95dc2 --- /dev/null +++ b/server_test.go @@ -0,0 +1,42 @@ +// Copyright 2023 The Gogs Authors. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. + +package git + +import ( + "os" + "path/filepath" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestUpdateServerInfo(t *testing.T) { + err := os.RemoveAll(filepath.Join(repoPath, "info")) + require.NoError(t, err) + err = UpdateServerInfo(repoPath, UpdateServerInfoOptions{Force: true}) + require.NoError(t, err) + assert.True(t, isFile(filepath.Join(repoPath, "info", "refs"))) +} + +func TestReceivePack(t *testing.T) { + got, err := ReceivePack(repoPath, ReceivePackOptions{HTTPBackendInfoRefs: true}) + require.NoError(t, err) + const contains = "report-status report-status-v2 delete-refs side-band-64k quiet atomic ofs-delta object-format=sha1 agent=git/" + assert.Contains(t, string(got), contains) +} + +func TestUploadPack(t *testing.T) { + got, err := UploadPack(repoPath, + UploadPackOptions{ + StatelessRPC: true, + Strict: true, + HTTPBackendInfoRefs: true, + }, + ) + require.NoError(t, err) + 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/" + assert.Contains(t, string(got), contains) +}