@@ -23,68 +23,79 @@ func ParseTreeEntries(data []byte) ([]*TreeEntry, error) {
2323
2424var sepSpace = []byte {' ' }
2525
26- func parseTreeEntries (data []byte , ptree * Tree ) ([]* TreeEntry , error ) {
26+ func parseLsTreeLine (line []byte ) (* TreeEntry , error ) {
27+ // expect line to be of the form:
28+ // <mode> <type> <sha> <space-padded-size>\t<filename>
29+ // <mode> <type> <sha>\t<filename>
30+
2731 var err error
32+ posTab := bytes .IndexByte (line , '\t' )
33+ if posTab == - 1 {
34+ return nil , fmt .Errorf ("invalid ls-tree output (no tab): %q" , line )
35+ }
36+
37+ entry := new (TreeEntry )
38+
39+ entryAttrs := line [:posTab ]
40+ entryName := line [posTab + 1 :]
41+
42+ entryMode , entryAttrs , _ := bytes .Cut (entryAttrs , sepSpace )
43+ _ /* entryType */ , entryAttrs , _ = bytes .Cut (entryAttrs , sepSpace ) // the type is not used, the mode is enough to determine the type
44+ entryObjectID , entryAttrs , _ := bytes .Cut (entryAttrs , sepSpace )
45+ if len (entryAttrs ) > 0 {
46+ entrySize := entryAttrs // the last field is the space-padded-size
47+ entry .size , _ = strconv .ParseInt (strings .TrimSpace (string (entrySize )), 10 , 64 )
48+ entry .sized = true
49+ }
50+
51+ switch string (entryMode ) {
52+ case "100644" :
53+ entry .entryMode = EntryModeBlob
54+ case "100755" :
55+ entry .entryMode = EntryModeExec
56+ case "120000" :
57+ entry .entryMode = EntryModeSymlink
58+ case "160000" :
59+ entry .entryMode = EntryModeCommit
60+ case "040000" , "040755" : // git uses 040000 for tree object, but some users may get 040755 for unknown reasons
61+ entry .entryMode = EntryModeTree
62+ default :
63+ return nil , fmt .Errorf ("unknown type: %v" , string (entryMode ))
64+ }
65+
66+ entry .ID , err = NewIDFromString (string (entryObjectID ))
67+ if err != nil {
68+ return nil , fmt .Errorf ("invalid ls-tree output (invalid object id): %q, err: %w" , line , err )
69+ }
70+
71+ if len (entryName ) > 0 && entryName [0 ] == '"' {
72+ entry .name , err = strconv .Unquote (string (entryName ))
73+ if err != nil {
74+ return nil , fmt .Errorf ("invalid ls-tree output (invalid name): %q, err: %w" , line , err )
75+ }
76+ } else {
77+ entry .name = string (entryName )
78+ }
79+ return entry , nil
80+ }
81+
82+ // parseTreeEntries FIXME this function's design is not right, it should make the caller read all data into memory
83+ func parseTreeEntries (data []byte , ptree * Tree ) ([]* TreeEntry , error ) {
2884 entries := make ([]* TreeEntry , 0 , bytes .Count (data , []byte {'\n' })+ 1 )
2985 for pos := 0 ; pos < len (data ); {
30- // expect line to be of the form:
31- // <mode> <type> <sha> <space-padded-size>\t<filename>
32- // <mode> <type> <sha>\t<filename>
3386 posEnd := bytes .IndexByte (data [pos :], '\n' )
3487 if posEnd == - 1 {
3588 posEnd = len (data )
3689 } else {
3790 posEnd += pos
3891 }
39- line := data [pos :posEnd ]
40- posTab := bytes .IndexByte (line , '\t' )
41- if posTab == - 1 {
42- return nil , fmt .Errorf ("invalid ls-tree output (no tab): %q" , line )
43- }
44-
45- entry := new (TreeEntry )
46- entry .ptree = ptree
4792
48- entryAttrs := line [:posTab ]
49- entryName := line [posTab + 1 :]
50-
51- entryMode , entryAttrs , _ := bytes .Cut (entryAttrs , sepSpace )
52- _ /* entryType */ , entryAttrs , _ = bytes .Cut (entryAttrs , sepSpace ) // the type is not used, the mode is enough to determine the type
53- entryObjectID , entryAttrs , _ := bytes .Cut (entryAttrs , sepSpace )
54- if len (entryAttrs ) > 0 {
55- entrySize := entryAttrs // the last field is the space-padded-size
56- entry .size , _ = strconv .ParseInt (strings .TrimSpace (string (entrySize )), 10 , 64 )
57- entry .sized = true
58- }
59-
60- switch string (entryMode ) {
61- case "100644" :
62- entry .entryMode = EntryModeBlob
63- case "100755" :
64- entry .entryMode = EntryModeExec
65- case "120000" :
66- entry .entryMode = EntryModeSymlink
67- case "160000" :
68- entry .entryMode = EntryModeCommit
69- case "040000" , "040755" : // git uses 040000 for tree object, but some users may get 040755 for unknown reasons
70- entry .entryMode = EntryModeTree
71- default :
72- return nil , fmt .Errorf ("unknown type: %v" , string (entryMode ))
73- }
74-
75- entry .ID , err = NewIDFromString (string (entryObjectID ))
93+ line := data [pos :posEnd ]
94+ entry , err := parseLsTreeLine (line )
7695 if err != nil {
77- return nil , fmt .Errorf ("invalid ls-tree output (invalid object id): %q, err: %w" , line , err )
78- }
79-
80- if len (entryName ) > 0 && entryName [0 ] == '"' {
81- entry .name , err = strconv .Unquote (string (entryName ))
82- if err != nil {
83- return nil , fmt .Errorf ("invalid ls-tree output (invalid name): %q, err: %w" , line , err )
84- }
85- } else {
86- entry .name = string (entryName )
96+ return nil , err
8797 }
98+ entry .ptree = ptree
8899
89100 pos = posEnd + 1
90101 entries = append (entries , entry )
@@ -100,7 +111,7 @@ func catBatchParseTreeEntries(objectFormat ObjectFormat, ptree *Tree, rd *bufio.
100111
101112loop:
102113 for sz > 0 {
103- mode , fname , sha , count , err := ParseTreeLine (objectFormat , rd , modeBuf , fnameBuf , shaBuf )
114+ mode , fname , sha , count , err := ParseCatFileTreeLine (objectFormat , rd , modeBuf , fnameBuf , shaBuf )
104115 if err != nil {
105116 if err == io .EOF {
106117 break loop
0 commit comments