code.gitea.io/gitea@v1.19.3/modules/git/tree_nogogit.go (about)

     1  // Copyright 2020 The Gitea Authors. All rights reserved.
     2  // SPDX-License-Identifier: MIT
     3  
     4  //go:build !gogit
     5  
     6  package git
     7  
     8  import (
     9  	"io"
    10  	"math"
    11  	"strings"
    12  )
    13  
    14  // Tree represents a flat directory listing.
    15  type Tree struct {
    16  	ID         SHA1
    17  	ResolvedID SHA1
    18  	repo       *Repository
    19  
    20  	// parent tree
    21  	ptree *Tree
    22  
    23  	entries       Entries
    24  	entriesParsed bool
    25  
    26  	entriesRecursive       Entries
    27  	entriesRecursiveParsed bool
    28  }
    29  
    30  // ListEntries returns all entries of current tree.
    31  func (t *Tree) ListEntries() (Entries, error) {
    32  	if t.entriesParsed {
    33  		return t.entries, nil
    34  	}
    35  
    36  	if t.repo != nil {
    37  		wr, rd, cancel := t.repo.CatFileBatch(t.repo.Ctx)
    38  		defer cancel()
    39  
    40  		_, _ = wr.Write([]byte(t.ID.String() + "\n"))
    41  		_, typ, sz, err := ReadBatchLine(rd)
    42  		if err != nil {
    43  			return nil, err
    44  		}
    45  		if typ == "commit" {
    46  			treeID, err := ReadTreeID(rd, sz)
    47  			if err != nil && err != io.EOF {
    48  				return nil, err
    49  			}
    50  			_, _ = wr.Write([]byte(treeID + "\n"))
    51  			_, typ, sz, err = ReadBatchLine(rd)
    52  			if err != nil {
    53  				return nil, err
    54  			}
    55  		}
    56  		if typ == "tree" {
    57  			t.entries, err = catBatchParseTreeEntries(t, rd, sz)
    58  			if err != nil {
    59  				return nil, err
    60  			}
    61  			t.entriesParsed = true
    62  			return t.entries, nil
    63  		}
    64  
    65  		// Not a tree just use ls-tree instead
    66  		for sz > math.MaxInt32 {
    67  			discarded, err := rd.Discard(math.MaxInt32)
    68  			sz -= int64(discarded)
    69  			if err != nil {
    70  				return nil, err
    71  			}
    72  		}
    73  		for sz > 0 {
    74  			discarded, err := rd.Discard(int(sz))
    75  			sz -= int64(discarded)
    76  			if err != nil {
    77  				return nil, err
    78  			}
    79  		}
    80  	}
    81  
    82  	stdout, _, runErr := NewCommand(t.repo.Ctx, "ls-tree", "-l").AddDynamicArguments(t.ID.String()).RunStdBytes(&RunOpts{Dir: t.repo.Path})
    83  	if runErr != nil {
    84  		if strings.Contains(runErr.Error(), "fatal: Not a valid object name") || strings.Contains(runErr.Error(), "fatal: not a tree object") {
    85  			return nil, ErrNotExist{
    86  				ID: t.ID.String(),
    87  			}
    88  		}
    89  		return nil, runErr
    90  	}
    91  
    92  	var err error
    93  	t.entries, err = parseTreeEntries(stdout, t)
    94  	if err == nil {
    95  		t.entriesParsed = true
    96  	}
    97  
    98  	return t.entries, err
    99  }
   100  
   101  // listEntriesRecursive returns all entries of current tree recursively including all subtrees
   102  // extraArgs could be "-l" to get the size, which is slower
   103  func (t *Tree) listEntriesRecursive(extraArgs TrustedCmdArgs) (Entries, error) {
   104  	if t.entriesRecursiveParsed {
   105  		return t.entriesRecursive, nil
   106  	}
   107  
   108  	stdout, _, runErr := NewCommand(t.repo.Ctx, "ls-tree", "-t", "-r").
   109  		AddArguments(extraArgs...).
   110  		AddDynamicArguments(t.ID.String()).
   111  		RunStdBytes(&RunOpts{Dir: t.repo.Path})
   112  	if runErr != nil {
   113  		return nil, runErr
   114  	}
   115  
   116  	var err error
   117  	t.entriesRecursive, err = parseTreeEntries(stdout, t)
   118  	if err == nil {
   119  		t.entriesRecursiveParsed = true
   120  	}
   121  
   122  	return t.entriesRecursive, err
   123  }
   124  
   125  // ListEntriesRecursiveFast returns all entries of current tree recursively including all subtrees, no size
   126  func (t *Tree) ListEntriesRecursiveFast() (Entries, error) {
   127  	return t.listEntriesRecursive(nil)
   128  }
   129  
   130  // ListEntriesRecursiveWithSize returns all entries of current tree recursively including all subtrees, with size
   131  func (t *Tree) ListEntriesRecursiveWithSize() (Entries, error) {
   132  	return t.listEntriesRecursive(TrustedCmdArgs{"--long"})
   133  }