-
Notifications
You must be signed in to change notification settings - Fork 18
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
use a copy of GitTools with isexecutable fix
- Loading branch information
1 parent
8c42f53
commit a47bbd0
Showing
3 changed files
with
133 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,130 @@ | ||
# copied from Pkg.jl/src/GitTools.jl | ||
|
||
module GitTools | ||
|
||
using SHA | ||
import Base: SHA1 | ||
|
||
@enum GitMode mode_dir=0o040000 mode_normal=0o100644 mode_executable=0o100755 mode_symlink=0o120000 mode_submodule=0o160000 | ||
Base.string(mode::GitMode) = string(UInt32(mode); base=8) | ||
Base.print(io::IO, mode::GitMode) = print(io, string(mode)) | ||
|
||
function gitmode(path::AbstractString) | ||
if islink(path) | ||
return mode_symlink | ||
elseif isdir(path) | ||
return mode_dir | ||
elseif Sys.isexecutable(path) | ||
return mode_executable | ||
else | ||
return mode_normal | ||
end | ||
end | ||
|
||
""" | ||
blob_hash(HashType::Type, path::AbstractString) | ||
Calculate the git blob hash of a given path. | ||
""" | ||
function blob_hash(::Type{HashType}, path::AbstractString) where HashType | ||
ctx = HashType() | ||
if islink(path) | ||
datalen = length(readlink(path)) | ||
else | ||
datalen = filesize(path) | ||
end | ||
|
||
# First, the header | ||
SHA.update!(ctx, Vector{UInt8}("blob $(datalen)\0")) | ||
|
||
# Next, read data in in chunks of 4KB | ||
buff = Vector{UInt8}(undef, 4*1024) | ||
|
||
try | ||
if islink(path) | ||
update!(ctx, Vector{UInt8}(readlink(path))) | ||
else | ||
open(path, "r") do io | ||
while !eof(io) | ||
num_read = readbytes!(io, buff) | ||
update!(ctx, buff, num_read) | ||
end | ||
end | ||
end | ||
catch e | ||
if isa(e, InterruptException) | ||
rethrow(e) | ||
end | ||
@warn("Unable to open $(path) for hashing; git-tree-sha1 likely suspect") | ||
end | ||
|
||
# Finish it off and return the digest! | ||
return SHA.digest!(ctx) | ||
end | ||
blob_hash(path::AbstractString) = blob_hash(SHA1_CTX, path) | ||
|
||
""" | ||
contains_files(root::AbstractString) | ||
Helper function to determine whether a directory contains files; e.g. it is a | ||
direct parent of a file or it contains some other directory that itself is a | ||
direct parent of a file. This is used to exclude directories from tree hashing. | ||
""" | ||
function contains_files(path::AbstractString) | ||
st = lstat(path) | ||
ispath(st) || throw(ArgumentError("non-existent path: $(repr(path))")) | ||
isdir(st) || return true | ||
for p in readdir(path) | ||
contains_files(joinpath(path, p)) && return true | ||
end | ||
return false | ||
end | ||
|
||
|
||
""" | ||
tree_hash(HashType::Type, root::AbstractString) | ||
Calculate the git tree hash of a given path. | ||
""" | ||
function tree_hash(::Type{HashType}, root::AbstractString) where HashType | ||
entries = Tuple{String, Vector{UInt8}, GitMode}[] | ||
for f in readdir(root) | ||
# Skip `.git` directories | ||
if f == ".git" | ||
continue | ||
end | ||
|
||
filepath = abspath(root, f) | ||
mode = gitmode(filepath) | ||
if mode == mode_dir | ||
# If this directory contains no files, then skip it | ||
contains_files(filepath) || continue | ||
|
||
# Otherwise, hash it up! | ||
hash = tree_hash(HashType, filepath) | ||
else | ||
hash = blob_hash(HashType, filepath) | ||
end | ||
push!(entries, (f, hash, mode)) | ||
end | ||
|
||
# Sort entries by name (with trailing slashes for directories) | ||
sort!(entries, by = ((name, hash, mode),) -> mode == mode_dir ? name*"/" : name) | ||
|
||
content_size = 0 | ||
for (n, h, m) in entries | ||
content_size += ndigits(UInt32(m); base=8) + 1 + sizeof(n) + 1 + sizeof(h) | ||
end | ||
|
||
# Return the hash of these entries | ||
ctx = HashType() | ||
SHA.update!(ctx, Vector{UInt8}("tree $(content_size)\0")) | ||
for (name, hash, mode) in entries | ||
SHA.update!(ctx, Vector{UInt8}("$(mode) $(name)\0")) | ||
SHA.update!(ctx, hash) | ||
end | ||
return SHA.digest!(ctx) | ||
end | ||
tree_hash(root::AbstractString) = tree_hash(SHA.SHA1_CTX, root) | ||
|
||
end # module |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters