2018-02-10 21:19:26 +03:00
// Copyright 2018 The Gitea Authors. All rights reserved.
2022-11-27 21:20:29 +03:00
// SPDX-License-Identifier: MIT
2018-02-10 21:19:26 +03:00
2021-08-24 19:47:09 +03:00
//go:build gogit
2020-12-17 17:00:47 +03:00
2018-02-10 21:19:26 +03:00
package git
import (
"bytes"
"fmt"
"strconv"
2021-02-18 00:32:25 +03:00
"strings"
2019-04-19 15:17:27 +03:00
2023-12-14 00:02:00 +03:00
"github.com/go-git/go-git/v5/plumbing"
2020-03-17 19:19:58 +03:00
"github.com/go-git/go-git/v5/plumbing/filemode"
2023-12-14 00:02:00 +03:00
"github.com/go-git/go-git/v5/plumbing/hash"
2020-03-17 19:19:58 +03:00
"github.com/go-git/go-git/v5/plumbing/object"
2018-02-10 21:19:26 +03:00
)
2021-02-18 00:32:25 +03:00
// ParseTreeEntries parses the output of a `git ls-tree -l` command.
2023-12-14 00:02:00 +03:00
func ParseTreeEntries ( h ObjectFormat , data [ ] byte ) ( [ ] * TreeEntry , error ) {
2018-02-10 21:19:26 +03:00
return parseTreeEntries ( data , nil )
}
func parseTreeEntries ( data [ ] byte , ptree * Tree ) ( [ ] * TreeEntry , error ) {
entries := make ( [ ] * TreeEntry , 0 , 10 )
for pos := 0 ; pos < len ( data ) ; {
2021-02-18 00:32:25 +03:00
// expect line to be of the form "<mode> <type> <sha> <space-padded-size>\t<filename>"
2018-02-10 21:19:26 +03:00
entry := new ( TreeEntry )
2019-04-19 15:17:27 +03:00
entry . gogitTreeEntry = & object . TreeEntry { }
2018-02-10 21:19:26 +03:00
entry . ptree = ptree
if pos + 6 > len ( data ) {
return nil , fmt . Errorf ( "Invalid ls-tree output: %s" , string ( data ) )
}
switch string ( data [ pos : pos + 6 ] ) {
case "100644" :
2019-04-19 15:17:27 +03:00
entry . gogitTreeEntry . Mode = filemode . Regular
2018-02-10 21:19:26 +03:00
pos += 12 // skip over "100644 blob "
case "100755" :
2019-04-19 15:17:27 +03:00
entry . gogitTreeEntry . Mode = filemode . Executable
2018-02-10 21:19:26 +03:00
pos += 12 // skip over "100755 blob "
case "120000" :
2019-04-19 15:17:27 +03:00
entry . gogitTreeEntry . Mode = filemode . Symlink
2018-02-10 21:19:26 +03:00
pos += 12 // skip over "120000 blob "
case "160000" :
2019-04-19 15:17:27 +03:00
entry . gogitTreeEntry . Mode = filemode . Submodule
2018-02-10 21:19:26 +03:00
pos += 14 // skip over "160000 object "
case "040000" :
2019-04-19 15:17:27 +03:00
entry . gogitTreeEntry . Mode = filemode . Dir
2018-02-10 21:19:26 +03:00
pos += 12 // skip over "040000 tree "
default :
return nil , fmt . Errorf ( "unknown type: %v" , string ( data [ pos : pos + 6 ] ) )
}
2023-12-14 00:02:00 +03:00
// in hex format, not byte format ....
if pos + hash . Size * 2 > len ( data ) {
2018-02-10 21:19:26 +03:00
return nil , fmt . Errorf ( "Invalid ls-tree output: %s" , string ( data ) )
}
2023-12-14 00:02:00 +03:00
var err error
2023-12-19 10:20:47 +03:00
entry . ID , err = NewIDFromString ( string ( data [ pos : pos + hash . Size * 2 ] ) )
2018-02-10 21:19:26 +03:00
if err != nil {
2023-12-14 00:02:00 +03:00
return nil , fmt . Errorf ( "invalid ls-tree output: %w" , err )
2018-02-10 21:19:26 +03:00
}
2023-12-14 00:02:00 +03:00
entry . gogitTreeEntry . Hash = plumbing . Hash ( entry . ID . RawValue ( ) )
2018-02-10 21:19:26 +03:00
pos += 41 // skip over sha and trailing space
2021-02-18 00:32:25 +03:00
end := pos + bytes . IndexByte ( data [ pos : ] , '\t' )
if end < pos {
return nil , fmt . Errorf ( "Invalid ls-tree -l output: %s" , string ( data ) )
}
entry . size , _ = strconv . ParseInt ( strings . TrimSpace ( string ( data [ pos : end ] ) ) , 10 , 64 )
entry . sized = true
pos = end + 1
end = pos + bytes . IndexByte ( data [ pos : ] , '\n' )
2018-02-10 21:19:26 +03:00
if end < pos {
return nil , fmt . Errorf ( "Invalid ls-tree output: %s" , string ( data ) )
}
// In case entry name is surrounded by double quotes(it happens only in git-shell).
if data [ pos ] == '"' {
2023-12-14 00:02:00 +03:00
var err error
2019-04-19 15:17:27 +03:00
entry . gogitTreeEntry . Name , err = strconv . Unquote ( string ( data [ pos : end ] ) )
2018-02-10 21:19:26 +03:00
if err != nil {
2022-10-24 22:29:17 +03:00
return nil , fmt . Errorf ( "Invalid ls-tree output: %w" , err )
2018-02-10 21:19:26 +03:00
}
} else {
2019-04-19 15:17:27 +03:00
entry . gogitTreeEntry . Name = string ( data [ pos : end ] )
2018-02-10 21:19:26 +03:00
}
pos = end + 1
entries = append ( entries , entry )
}
return entries , nil
}