drone/git/adapter/tree.go
2023-12-07 10:24:58 +00:00

161 lines
4.2 KiB
Go

// Copyright 2023 Harness, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package adapter
import (
"bytes"
"context"
"fmt"
"io"
"path"
"path/filepath"
"strings"
"github.com/harness/gitness/git/types"
gitea "code.gitea.io/gitea/modules/git"
)
func cleanTreePath(treePath string) string {
return strings.Trim(path.Clean("/"+treePath), "/")
}
// GetTreeNode returns the tree node at the given path as found for the provided reference.
// Note: ref can be Branch / Tag / CommitSHA.
func (a Adapter) GetTreeNode(
ctx context.Context,
repoPath string,
ref string,
treePath string,
) (*types.TreeNode, error) {
treePath = cleanTreePath(treePath)
giteaRepo, err := gitea.OpenRepository(ctx, repoPath)
if err != nil {
return nil, processGiteaErrorf(err, "failed to open repository")
}
defer giteaRepo.Close()
// Get the giteaCommit object for the ref
giteaCommit, err := giteaRepo.GetCommit(ref)
if err != nil {
return nil, processGiteaErrorf(err, "error getting commit for ref '%s'", ref)
}
// TODO: handle ErrNotExist :)
giteaTreeEntry, err := giteaCommit.GetTreeEntryByPath(treePath)
if err != nil {
return nil, processGiteaErrorf(err, "failed to get tree entry for commit '%s' at path '%s'",
giteaCommit.ID.String(), treePath)
}
nodeType, mode, err := mapGiteaNodeToTreeNodeModeAndType(giteaTreeEntry.Mode())
if err != nil {
return nil, err
}
return &types.TreeNode{
Mode: mode,
NodeType: nodeType,
Sha: giteaTreeEntry.ID.String(),
Name: giteaTreeEntry.Name(),
Path: treePath,
}, nil
}
// ListTreeNodes lists the child nodes of a tree reachable from ref via the specified path
// and includes the latest commit for all nodes if requested.
// Note: ref can be Branch / Tag / CommitSHA.
func (a Adapter) ListTreeNodes(
ctx context.Context,
repoPath string,
ref string,
treePath string,
) ([]types.TreeNode, error) {
treePath = cleanTreePath(treePath)
giteaRepo, err := gitea.OpenRepository(ctx, repoPath)
if err != nil {
return nil, processGiteaErrorf(err, "failed to open repository")
}
defer giteaRepo.Close()
// Get the giteaCommit object for the ref
giteaCommit, err := giteaRepo.GetCommit(ref)
if err != nil {
return nil, processGiteaErrorf(err, "error getting commit for ref '%s'", ref)
}
// Get the giteaTree object for the ref
giteaTree, err := giteaCommit.SubTree(treePath)
if err != nil {
return nil, processGiteaErrorf(err, "error getting tree for '%s'", treePath)
}
giteaEntries, err := giteaTree.ListEntries()
if err != nil {
return nil, processGiteaErrorf(err, "failed to list entries for tree '%s'", treePath)
}
nodes := make([]types.TreeNode, len(giteaEntries))
for i := range giteaEntries {
giteaEntry := giteaEntries[i]
var nodeType types.TreeNodeType
var mode types.TreeNodeMode
nodeType, mode, err = mapGiteaNodeToTreeNodeModeAndType(giteaEntry.Mode())
if err != nil {
return nil, err
}
// giteaNode.Name() returns the path of the node relative to the tree.
relPath := giteaEntry.Name()
name := filepath.Base(relPath)
nodes[i] = types.TreeNode{
NodeType: nodeType,
Mode: mode,
Sha: giteaEntry.ID.String(),
Name: name,
Path: filepath.Join(treePath, relPath),
}
}
return nodes, nil
}
func (a Adapter) ReadTree(
ctx context.Context,
repoPath string,
ref string,
w io.Writer,
args ...string,
) error {
if repoPath == "" {
return ErrRepositoryPathEmpty
}
errbuf := bytes.Buffer{}
if err := gitea.NewCommand(ctx, append([]string{"read-tree", ref}, args...)...).
Run(&gitea.RunOpts{
Dir: repoPath,
Stdout: w,
Stderr: &errbuf,
}); err != nil {
return fmt.Errorf("unable to read %s in to the index: %w\n%s",
ref, err, errbuf.String())
}
return nil
}