1+ const PathInfo = Union{String, Int64, Symbol}
2+
3+ struct GitLeaf
4+ mode:: String
5+ hash:: String
6+ end
7+
8+ struct GitTree
9+ children:: Dict{String, Union{GitTree, GitLeaf}}
10+ end
11+ GitTree () = GitTree (Dict {String, Union{GitTree, GitLeaf}} ())
12+
113function iterate_headers (
214 callback:: Function ,
315 tar:: IO ;
168180
169181# resolve symlink target or nothing if not valid
170182function link_target (
171- paths:: Dict{String} ,
183+ paths:: Dict{String, PathInfo } ,
172184 path:: AbstractString ,
173185 link:: AbstractString ,
174186)
@@ -214,21 +226,21 @@ function git_tree_hash(
214226 buf:: Vector{UInt8} = Vector {UInt8} (undef, DEFAULT_BUFFER_SIZE),
215227) where HashType <: SHA.SHA_CTX
216228 # build tree with leaves for files and symlinks
217- tree = Dict {String,Any} ()
229+ tree = GitTree ()
218230 read_tarball (predicate, tar; buf= buf) do hdr, parts
219231 isempty (parts) && return
220232 name = pop! (parts)
221233 node = tree
222234 for part in parts
223- node′ = get (node, part, nothing )
224- if ! (node′ isa Dict )
225- node′ = node[part] = Dict {String,Any} ()
235+ child = get (node. children , part, nothing )
236+ if ! (child isa GitTree )
237+ child = node. children [part] = GitTree ()
226238 end
227- node = node′
239+ node = child
228240 end
229241 if hdr. type == :directory
230- if ! (get (node, name, nothing ) isa Dict )
231- node[name] = Dict {String,Any} ()
242+ if ! (get (node. children , name, nothing ) isa GitTree )
243+ node. children [name] = GitTree ()
232244 end
233245 return
234246 elseif hdr. type == :symlink
@@ -238,47 +250,51 @@ function git_tree_hash(
238250 end
239251 elseif hdr. type == :hardlink
240252 mode = iszero (hdr. mode & 0o100 ) ? " 100644" : " 100755"
241- node′ = tree
253+ linked = tree
242254 for part in split (hdr. link, ' /' )
243- node′ = node′ [part]
255+ linked = linked . children [part]
244256 end
245- hash = node′[ 2 ] # hash of linked file
257+ hash = ( linked:: GitLeaf ) . hash
246258 elseif hdr. type == :file
247259 mode = iszero (hdr. mode & 0o100 ) ? " 100644" : " 100755"
248260 hash = git_file_hash (tar, hdr. size, HashType, buf= buf)
249261 else
250262 error (" unsupported type for git tree hashing: $(hdr. type) " )
251263 end
252- node[name] = (mode, hash)
264+ node. children [name] = GitLeaf (mode, hash)
253265 end
254266
255267 # prune directories that don't contain any files
256268 if skip_empty
257- prune_empty! (node:: Tuple ) = true
258- function prune_empty! (node:: Dict )
259- filter! (node) do (name, child)
260- prune_empty! (child)
261- end
262- return ! isempty (node)
263- end
264269 prune_empty! (tree)
265270 end
266271
267272 # reduce the tree to a single hash value
268- hash_tree (node:: Tuple ) = node
269- function hash_tree (node:: Dict )
270- by ((name, child)) = child isa Dict ? " $name /" : name
271- hash = git_object_hash (" tree" , HashType) do io
272- for (name, child) in sort! (collect (node), by= by)
273- mode, hash = hash_tree (child)
274- print (io, mode, ' ' , name, ' \0 ' )
275- write (io, hex2bytes (hash))
276- end
277- end
278- return " 40000" , hash
273+ return hash_git_tree (tree, HashType)[end ]
274+ end
275+
276+ prune_empty! (node:: GitLeaf ) = true
277+ function prune_empty! (node:: GitTree )
278+ filter! (node. children) do (name, child)
279+ prune_empty! (child)
279280 end
281+ return ! isempty (node. children)
282+ end
280283
281- return hash_tree (tree)[end ]
284+ function hash_git_tree (node:: GitLeaf , :: Type{HashType} ) where HashType <: SHA.SHA_CTX
285+ return (node. mode, node. hash)
286+ end
287+
288+ function hash_git_tree (node:: GitTree , :: Type{HashType} ) where HashType <: SHA.SHA_CTX
289+ by ((name, child)) = child isa GitTree ? " $name /" : name
290+ hash = git_object_hash (" tree" , HashType) do io
291+ for (name, child) in sort! (collect (node. children), by= by)
292+ mode, hash = hash_git_tree (child, HashType)
293+ print (io, mode, ' ' , name, ' \0 ' )
294+ write (io, hex2bytes (hash))
295+ end
296+ end
297+ return (" 40000" , hash)
282298end
283299
284300function git_object_hash (
@@ -350,7 +366,7 @@ function read_tarball(
350366)
351367 write_skeleton_header (skeleton, buf= buf)
352368 # symbols for path types except symlinks store the link
353- paths = Dict {String,Any } ()
369+ paths = Dict {String, PathInfo } ()
354370 globals = Dict {String,String} ()
355371 while ! eof (tar)
356372 hdr = read_header (tar, globals= globals, buf= buf, tee= skeleton)
0 commit comments