// Copyright 2020 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT //go:build !gogit package git import ( "context" "io" "gitea.dev/modules/git/gitcmd" ) // Tree represents a flat directory listing. type Tree struct { TreeCommon entries Entries entriesParsed bool } // ListEntries returns all entries of current tree. func (t *Tree) ListEntries(ctx context.Context, gitRepo *Repository) (Entries, error) { if t.entriesParsed { return t.entries, nil } batch, cancel, err := gitRepo.CatFileBatch(ctx) if err != nil { return nil, err } defer cancel() info, rd, err := batch.QueryContent(t.ID.String()) if err != nil { return nil, err } if info.Type == "commit" { treeID, err := ReadTreeID(rd, info.Size) if err != nil && err != io.EOF { return nil, err } info, rd, err = batch.QueryContent(treeID) if err != nil { return nil, err } } if info.Type == "tree" { t.entries, err = catBatchParseTreeEntries(t.ID.Type(), t, rd, info.Size) if err != nil { return nil, err } t.entriesParsed = true return t.entries, nil } // Not a tree just use ls-tree instead if err := DiscardFull(rd, info.Size+1); err != nil { return nil, err } stdout, _, runErr := gitcmd.NewCommand("ls-tree", "-l").AddDynamicArguments(t.ID.String()).WithDir(gitRepo.Path).RunStdBytes(ctx) if runErr != nil { if gitcmd.IsStderr(runErr, gitcmd.StderrNotValidObjectName) || gitcmd.IsStderr(runErr, gitcmd.StderrNotTreeObject) { return nil, ErrNotExist{ ID: t.ID.String(), } } return nil, runErr } t.entries, err = parseTreeEntries(stdout, t) if err == nil { t.entriesParsed = true } return t.entries, err } // listEntriesRecursive returns all entries of current tree recursively including all subtrees // extraArgs could be "-l" to get the size, which is slower func (t *Tree) listEntriesRecursive(ctx context.Context, gitRepo *Repository, extraArgs gitcmd.TrustedCmdArgs) (Entries, error) { stdout, _, runErr := gitcmd.NewCommand("ls-tree", "-t", "-r"). AddArguments(extraArgs...). AddDynamicArguments(t.ID.String()). WithDir(gitRepo.Path). RunStdBytes(ctx) if runErr != nil { return nil, runErr } // FIXME: the "name" field is abused, here it is a full path // FIXME: this ptree is not right, fortunately it isn't really used return parseTreeEntries(stdout, t) } // ListEntriesRecursiveFast returns all entries of current tree recursively including all subtrees, no size func (t *Tree) ListEntriesRecursiveFast(ctx context.Context, gitRepo *Repository) (Entries, error) { return t.listEntriesRecursive(ctx, gitRepo, nil) } // ListEntriesRecursiveWithSize returns all entries of current tree recursively including all subtrees, with size func (t *Tree) ListEntriesRecursiveWithSize(ctx context.Context, gitRepo *Repository) (Entries, error) { return t.listEntriesRecursive(ctx, gitRepo, gitcmd.TrustedCmdArgs{"--long"}) }