Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Remove broken symlinks when updating deps #2842

Merged
merged 9 commits into from
Jan 14, 2019
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions hack/update-deps.sh
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,26 @@ set -o pipefail

source $(dirname $0)/../vendor/github.com/knative/test-infra/scripts/library.sh

# Remove symlinks in /vendor that are broken or lead outside the repo.
function remove_broken_symlinks() {
for link in $(find ./vendor -type l); do
local target="$(ls -l ${link})"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd suggest using readlink for this:

local target="$(readlink ${link})"
...

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, it doesn't work on Macs. That was the major reason for this PR taking so long to be finished.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think vanilla readlink without -f works on Macs. At least one test on Dan's laptop suggested this was installed in /bin, which is pretty likely to be a core utility.

target="${target##* -> }"
# Remove broken symlinks
if [[ ! -e ${link} ]]; then
erain marked this conversation as resolved.
Show resolved Hide resolved
unlink ${link}
continue
fi
# Get canonical path to target, remove if outside the repo
[[ ${target} == /* ]] || target="./${target}"
Copy link
Member

@evankanderson evankanderson Jan 11, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't understand what's going on here, and why this is needed to find a canonical path.

I'd have this follow the links recursively. I understand we want this to work with MacOS X/BSD, so we only have a simple readlink and no realpath (which we can emulate with $(cd $(dirname $FOO); pwd)):

function remove_external_links() {  # Removes a chain of links pointing out of tree
  if ! [[ -e $1 ]]; then
    return 1  # This link doesn't point anywhere.
  fi
  if ! [[ -L $1 ]]; then
    return 0  # This is a real file/directory which is not a link.
  fi
  # This determines if it points outside the tree, either absolutely, or outside vendor.
  target="$(readlink "$1")"
  if [[ $target == /* ]] || [[ "$(cd $(dirname "$target"; pwd)/" == ${PWD}/vendor/* ]]; then
    rm "$1"  # Remove the errant link, but not its target (which is outside our tree)
    return 1
  fi
  if ! remove_external_links "$target"; then
    rm "$1"  # Recursive examination found a bad target, remove this link, too.
    return 1
  fi
}

remove_external_links "${link}"

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FWIW, I tested this as a set of one-liners, so you may want to re-test if you decide to use it.

Note that the current script does not handle any of the following:

  • chained links (ln -s b c; ln -s a b)
  • Intermediate links that point outside the current directory (ln -s go/src/github.com/knative/serving/vendor/foo a; ln -s ~/a go/src/github.com/knative/serving/vendor/bar)
  • Link paths which exit and re-enter the working directory. (ln -s ../../../../../../go/src/github.com/knative/serving/vendor/foo bar, which assumes GOPATH=~/go or the like. I didn't fix this one, either.)

Unfortuantely, for the third item, I think you have to process each segment of the $target independently and do a check as to whether it is under PWD at each step.

Copy link
Contributor

@adrcunha adrcunha Jan 12, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

a) readlink is not available on Mac, so this solution can't be used.
b) You don't need to check the beyond the first target. If it leads outside the repo tree, it'll be removed. If it leads to some other link inside the tree, the target link will be checked at some point.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For b)

If you don't check beyond the first target, there may still be dangling symlinks after running N passes of this, depending on the order of directory entries returned by the OS. Consider the following:

$ cd /tmp/x
$ ls -l

b -> ../a
c -> b
d -> c

$ for x in $(find . -type l ); do [[ -L $x ]] || continue; t=$(readlink $x); [[ $t == /* ]] || t="./$t"; t2="$(cd $(dirname $x) && cd ${t%/*} && echo $PWD/${t##*/})"; echo $x $t $t2; if [[ ${t2}/ != $PWD/* ]]; then echo remove $x; continue; fi; done

./d ./c /tmp/x/c
./c ./b /tmp/x/b
./b ./../a /tmp/a
remove ./b

At the end of this, d and c will still be present and dangling (pointing at b, which was removed from the directory).

Unfortunately, I just discovered a different problem with my solution, which is that a symlink loop will cause it to recurse until stack space is exhausted. 🤷‍♂️

I'm okay with this solution, but wanted to point out that it might miss symlink chains where the last element in the chain points outside the tree (and that order will depend on the order that directory entries are added and returned, which is OS-dependent).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually "following the symlink all the way by simple readlink was implemented" in a previous commit:
1adb644

And that approach can solve the problem you mentioned, since each symlink will be solved to the canonical path of a final target (and be deleted if it is outside of the source tree).

Let me know if you want me to revert to that approach, or do the minor improvement (as your first comment) on this approach.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The version in 1adb644 doesn't check that the intermediate symlinks are inside the tree, allowing for e.g.

vendor/foo --> /home/evan/foo --> /home/evan/go/src/github.com/knative/serving/vendor/bar

With that said, I'm happy with a simpler solution for now and then having dep do the right thing.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(And I've approved, so if people want this version, they can just /hold cancel.)

target="$(cd `dirname ${link}` && cd ${target%/*} && echo $PWD/${target##*/})"
if [[ ${target} != *github.com/knative/* ]]; then
unlink ${link}
continue
fi
done
}

cd ${REPO_ROOT_DIR}

# Ensure we have everything we need under vendor/
Expand All @@ -35,3 +55,6 @@ update_licenses third_party/VENDOR-LICENSE "./cmd/*"
# cherrypick of #66078. Remove this once that reaches a client version
# we have pulled in.
git apply ${REPO_ROOT_DIR}/hack/66078.patch

# Remove all invalid symlinks under ./vendor
remove_broken_symlinks

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

1 change: 0 additions & 1 deletion vendor/github.com/docker/docker/project/CONTRIBUTORS.md

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

1 change: 0 additions & 1 deletion vendor/github.com/knative/build/config/300-imagecache.yaml

This file was deleted.

This file was deleted.

This file was deleted.

1 change: 0 additions & 1 deletion vendor/github.com/prometheus/procfs/fixtures/26231/exe

This file was deleted.

1 change: 0 additions & 1 deletion vendor/github.com/prometheus/procfs/fixtures/26231/fd/0

This file was deleted.

1 change: 0 additions & 1 deletion vendor/github.com/prometheus/procfs/fixtures/26231/fd/1

This file was deleted.

1 change: 0 additions & 1 deletion vendor/github.com/prometheus/procfs/fixtures/26231/fd/10

This file was deleted.

1 change: 0 additions & 1 deletion vendor/github.com/prometheus/procfs/fixtures/26231/fd/2

This file was deleted.

1 change: 0 additions & 1 deletion vendor/github.com/prometheus/procfs/fixtures/26231/fd/3

This file was deleted.

1 change: 0 additions & 1 deletion vendor/github.com/prometheus/procfs/fixtures/26231/ns/mnt

This file was deleted.

1 change: 0 additions & 1 deletion vendor/github.com/prometheus/procfs/fixtures/26231/ns/net

This file was deleted.

1 change: 0 additions & 1 deletion vendor/github.com/prometheus/procfs/fixtures/26232/fd/0

This file was deleted.

1 change: 0 additions & 1 deletion vendor/github.com/prometheus/procfs/fixtures/26232/fd/1

This file was deleted.

1 change: 0 additions & 1 deletion vendor/github.com/prometheus/procfs/fixtures/26232/fd/2

This file was deleted.

1 change: 0 additions & 1 deletion vendor/github.com/prometheus/procfs/fixtures/26232/fd/3

This file was deleted.

1 change: 0 additions & 1 deletion vendor/github.com/prometheus/procfs/fixtures/26232/fd/4

This file was deleted.

1 change: 0 additions & 1 deletion vendor/k8s.io/kubernetes/.bazelrc

This file was deleted.

1 change: 0 additions & 1 deletion vendor/k8s.io/kubernetes/.kazelcfg.json

This file was deleted.

1 change: 0 additions & 1 deletion vendor/k8s.io/kubernetes/BUILD.bazel

This file was deleted.

1 change: 0 additions & 1 deletion vendor/k8s.io/kubernetes/Makefile

This file was deleted.

1 change: 0 additions & 1 deletion vendor/k8s.io/kubernetes/Makefile.generated_files

This file was deleted.

1 change: 0 additions & 1 deletion vendor/k8s.io/kubernetes/WORKSPACE

This file was deleted.

1 change: 0 additions & 1 deletion vendor/k8s.io/kubernetes/cluster/gce/cos

This file was deleted.

1 change: 0 additions & 1 deletion vendor/k8s.io/kubernetes/cluster/gce/custom

This file was deleted.

1 change: 0 additions & 1 deletion vendor/k8s.io/kubernetes/cluster/gce/ubuntu

This file was deleted.

This file was deleted.

This file was deleted.