Skip to content

Commit

Permalink
Fix #115: Speed up the link command.
Browse files Browse the repository at this point in the history
 - Don't store intermediate `paths` variable; use pipes.
 - Use process substitution to speed up loops.
 - Minor clean-up & fix a few shellcheck warnings.

1 test re: Fail on newline in filename does *NOT* pass.
Is this behavior we need to keep?
  • Loading branch information
dougborg committed Oct 12, 2014
1 parent ecfaa2a commit f577ea5
Showing 1 changed file with 52 additions and 28 deletions.
80 changes: 52 additions & 28 deletions lib/commands/link.sh
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,14 @@ function symlink {
fi
oldIFS=$IFS
IFS=$'\n'
for filename in $(get_repo_files $repo/home); do
remote="$repo/home/$filename"
for filename in $(get_repo_files "$repo/home"); do
IFS=$oldIFS
remote="$repo/home/$filename"
local=$HOME/$filename

if [[ -e $local || -L $local ]]; then
# $local exists (but may be a dead symlink)
if [[ -L $local && $(readlink "$local") == $remote ]]; then
if [[ -L $local && $(readlink "$local") == "$remote" ]]; then
# $local symlinks to $remote.
if [[ -d $remote && ! -L $remote ]]; then
# If $remote is a directory -> legacy handling.
Expand Down Expand Up @@ -64,6 +64,37 @@ function symlink {
return $EX_SUCCESS
}

function get_repo_dirs {
# Loop through the files tracked by git and compute
# a list of their parent directories.
# The root of repo we are looking at, will not change.
local root=$1
# Check if this is the root invocation.
if [[ -n $2 ]]; then
# The path to the current repo we are looking at:
repo_dir="$root/$2"
# The relative path to the submodule:
relpath="$2/"
else
# First invocation, the repo_dir is just the root.
local repo_dir=$root
local relpath=''
fi
(
local path
while read path; do
printf "%s\n" "$relpath$path"
# Get all directory paths up to the root.
# We won't ever hit '/' here since ls-files
# always shows paths relative to the repo root.
while [[ $path =~ '/' ]]; do
path=$(dirname "$path")
printf "%s\n" "$relpath$path"
done
done < <(cd "$repo_dir" && git ls-files | xargs -I{} dirname "{}" | sort | uniq)
) | sort | uniq
}

function get_repo_files {
# This function descends recursively through all submodules
# of a repository and makes the paths returned by `git ls-files`
Expand All @@ -72,38 +103,31 @@ function get_repo_files {

# The root of repo we are looking at, will not change.
local root=$1
# Check if this is the root invocation
# Check if this is the root invocation.
if [[ -n $2 ]]; then
# The path to the current repo we are looking at
# The path to the current repo we are looking at:
repo_dir="$root/$2"
# The relative path to the submodule
# The relative path to the submodule:
relpath="$2/"
else
# First invocation, the repo dir is just the root
# First invocation, the repo_dir is just the root.
local repo_dir=$root
local relpath=''
fi
local paths=""
# Loop through the files tracked by git and compute
# a list of their parent directories.
for path in $(cd $repo_dir && git ls-files); do
# Don't add a newline to the beginning of the list
[[ -n $paths ]] && paths="$paths\n"
paths="$paths$relpath$path"
# Get all directory paths up to the root.
# We won't ever hit '/' here since ls-files
# always shows paths relative to the repo root.
while [[ $path =~ '/' ]]; do
path=$(dirname $path)
paths="$relpath$path\n$paths"
done
done
(
# Get files (+ submodule path prefix).
local path
while read path; do
printf "%s\n" "$relpath$path"
done < <(cd "$repo_dir" && git ls-files)

# Loop through all submodule children (not descendants, i.e. immediate children)
# and invoke the function again, passing the relative path to the submodule as the 2nd arg
for submodule in $(cd $repo_dir; git submodule --quiet foreach 'printf "%s\n" "$path"'); do
paths="$(get_repo_files $root $relpath$submodule)\n$paths"
done
# Get all directories (+ submodule path prefix).
get_repo_files "$repo_dir" "$submodule"

printf "$paths" | sort | uniq
# Recurse on all submodule children (not descendants, i.e. immediate
# children), passing the relative path to the submodule as the 2nd arg.
for submodule in $(cd "$root"; git submodule --quiet foreach 'printf "%s\n" "$path"'); do
get_repo_files "$repo_dir" "$submodule"
done
) | sort | uniq
}

0 comments on commit f577ea5

Please sign in to comment.