commit 40dde666c0e7cae797b8652b1f4368e52c2c7b13 from: Stefan Sperling date: Thu Jul 23 14:21:29 2020 UTC add support for symlinks in the repository to 'got diff' commit - 4135d7d058f245363e836faa15dbedbd91bd1334 commit + 40dde666c0e7cae797b8652b1f4368e52c2c7b13 blob - 152352cad8daa30cc23016c559df4f22a087bd74 blob + 7e5ee06994a5158bc937ce8307bd19f51d7e0ef5 --- lib/diff.c +++ lib/diff.c @@ -114,16 +114,25 @@ diff_blobs(struct got_blob_object *blob1, struct got_b if (outfile) { char *modestr1 = NULL, *modestr2 = NULL; + int modebits; if (mode1 && mode1 != mode2) { + if (S_ISLNK(mode1)) + modebits = S_IFLNK; + else + modebits = (S_IRWXU | S_IRWXG | S_IRWXO); if (asprintf(&modestr1, " (mode %o)", - mode1 & (S_IRWXU | S_IRWXG | S_IRWXO)) == -1) { + mode1 & modebits) == -1) { err = got_error_from_errno("asprintf"); goto done; } } if (mode2 && mode1 != mode2) { + if (S_ISLNK(mode2)) + modebits = S_IFLNK; + else + modebits = (S_IRWXU | S_IRWXG | S_IRWXO); if (asprintf(&modestr2, " (mode %o)", - mode2 & (S_IRWXU | S_IRWXG | S_IRWXO)) == -1) { + mode2 & modebits) == -1) { err = got_error_from_errno("asprintf"); goto done; } @@ -550,9 +559,11 @@ diff_entry_old_new(struct got_tree_entry *te1, if (!id_match) return diff_modified_tree(&te1->id, &te2->id, label1, label2, repo, cb, cb_arg, diff_content); - } else if (S_ISREG(te1->mode) && S_ISREG(te2->mode)) { + } else if ((S_ISREG(te1->mode) || S_ISLNK(te1->mode)) && + (S_ISREG(te2->mode) || S_ISLNK(te2->mode))) { if (!id_match || - (te1->mode & S_IXUSR) != (te2->mode & S_IXUSR)) { + ((te1->mode & (S_IFLNK | S_IXUSR))) != + (te2->mode & (S_IFLNK | S_IXUSR))) { if (diff_content) return diff_modified_blob(&te1->id, &te2->id, label1, label2, te1->mode, te2->mode, blob - cfc0d4b524be60277183c28685d392dbde650020 blob + eaff0579c403d60f90fdc01f50fde183091286a2 --- lib/object.c +++ lib/object.c @@ -1700,6 +1700,14 @@ normalize_mode_for_comparison(mode_t mode) */ if (S_ISDIR(mode)) return mode & S_IFDIR; + + /* + * For symlinks, the only relevant bit is the IFLNK bit. + * This allows us to detect paths changing from a symlinks + * to a file or directory and vice versa. + */ + if (S_ISLNK(mode)) + return mode & S_IFLNK; /* For files, the only change we care about is the executable bit. */ return mode & S_IXUSR; blob - 649ab258d4c149e3942f5f2da369992a8dd44f69 blob + dbc39580319a7e28e9adc23ded3e53d643d3d6e0 --- regress/cmdline/diff.sh +++ regress/cmdline/diff.sh @@ -453,6 +453,123 @@ function test_diff_symlinks_in_work_tree { echo 'blob - /dev/null' >> $testroot/stdout.expected echo 'file + zeta.link' >> $testroot/stdout.expected echo '--- zeta.link' >> $testroot/stdout.expected + echo '+++ zeta.link' >> $testroot/stdout.expected + echo '@@ -0,0 +1 @@' >> $testroot/stdout.expected + echo '+epsilon/zeta' >> $testroot/stdout.expected + echo '\ No newline at end of file' >> $testroot/stdout.expected + + cmp -s $testroot/stdout.expected $testroot/stdout + ret="$?" + if [ "$ret" != "0" ]; then + diff -u $testroot/stdout.expected $testroot/stdout + fi + test_done "$testroot" "$ret" +} + +function test_diff_symlinks_in_repo { + local testroot=`test_init diff_symlinks_in_repo` + + (cd $testroot/repo && ln -s alpha alpha.link) + (cd $testroot/repo && ln -s epsilon epsilon.link) + (cd $testroot/repo && ln -s /etc/passwd passwd.link) + (cd $testroot/repo && ln -s ../beta epsilon/beta.link) + (cd $testroot/repo && ln -s nonexistent nonexistent.link) + (cd $testroot/repo && ln -s .got/foo dotgotfoo.link) + (cd $testroot/repo && git add .) + git_commit $testroot/repo -m "add symlinks" + local commit_id1=`git_show_head $testroot/repo` + + (cd $testroot/repo && ln -sf beta alpha.link) + (cd $testroot/repo && ln -sfh gamma epsilon.link) + (cd $testroot/repo && ln -sf ../gamma/delta epsilon/beta.link) + (cd $testroot/repo && ln -sf .got/bar $testroot/repo/dotgotfoo.link) + (cd $testroot/repo && git rm -q nonexistent.link) + (cd $testroot/repo && ln -sf epsilon/zeta zeta.link) + (cd $testroot/repo && git add .) + git_commit $testroot/repo -m "change symlinks" + local commit_id2=`git_show_head $testroot/repo` + + got diff -r $testroot/repo $commit_id1 $commit_id2 > $testroot/stdout + + echo "diff $commit_id1 $commit_id2" > $testroot/stdout.expected + echo -n 'blob - ' >> $testroot/stdout.expected + got tree -r $testroot/repo -c $commit_id1 -i | \ + grep 'alpha.link@ -> alpha$' | \ + cut -d' ' -f 1 >> $testroot/stdout.expected + echo -n 'blob + ' >> $testroot/stdout.expected + got tree -r $testroot/repo -c $commit_id2 -i | \ + grep 'alpha.link@ -> beta$' | \ + cut -d' ' -f 1 >> $testroot/stdout.expected + echo '--- alpha.link' >> $testroot/stdout.expected + echo '+++ alpha.link' >> $testroot/stdout.expected + echo '@@ -1 +1 @@' >> $testroot/stdout.expected + echo '-alpha' >> $testroot/stdout.expected + echo '\ No newline at end of file' >> $testroot/stdout.expected + echo '+beta' >> $testroot/stdout.expected + echo '\ No newline at end of file' >> $testroot/stdout.expected + echo -n 'blob - ' >> $testroot/stdout.expected + got tree -r $testroot/repo -c $commit_id1 -i | \ + grep 'dotgotfoo.link@ -> .got/foo$' | \ + cut -d' ' -f 1 >> $testroot/stdout.expected + echo -n 'blob + ' >> $testroot/stdout.expected + got tree -r $testroot/repo -c $commit_id2 -i | \ + grep 'dotgotfoo.link@ -> .got/bar$' | \ + cut -d' ' -f 1 >> $testroot/stdout.expected + echo '--- dotgotfoo.link' >> $testroot/stdout.expected + echo '+++ dotgotfoo.link' >> $testroot/stdout.expected + echo '@@ -1 +1 @@' >> $testroot/stdout.expected + echo '-.got/foo' >> $testroot/stdout.expected + echo '\ No newline at end of file' >> $testroot/stdout.expected + echo '+.got/bar' >> $testroot/stdout.expected + echo '\ No newline at end of file' >> $testroot/stdout.expected + echo -n 'blob - ' >> $testroot/stdout.expected + got tree -r $testroot/repo -c $commit_id1 -i epsilon | \ + grep 'beta.link@ -> ../beta$' | \ + cut -d' ' -f 1 >> $testroot/stdout.expected + echo -n 'blob + ' >> $testroot/stdout.expected + got tree -r $testroot/repo -c $commit_id2 -i epsilon | \ + grep 'beta.link@ -> ../gamma/delta$' | \ + cut -d' ' -f 1 >> $testroot/stdout.expected + echo '--- epsilon/beta.link' >> $testroot/stdout.expected + echo '+++ epsilon/beta.link' >> $testroot/stdout.expected + echo '@@ -1 +1 @@' >> $testroot/stdout.expected + echo '-../beta' >> $testroot/stdout.expected + echo '\ No newline at end of file' >> $testroot/stdout.expected + echo '+../gamma/delta' >> $testroot/stdout.expected + echo '\ No newline at end of file' >> $testroot/stdout.expected + echo -n 'blob - ' >> $testroot/stdout.expected + got tree -r $testroot/repo -c $commit_id1 -i | \ + grep 'epsilon.link@ -> epsilon$' | \ + cut -d' ' -f 1 >> $testroot/stdout.expected + echo -n 'blob + ' >> $testroot/stdout.expected + got tree -r $testroot/repo -c $commit_id2 -i | \ + grep 'epsilon.link@ -> gamma$' | \ + cut -d' ' -f 1 >> $testroot/stdout.expected + echo '--- epsilon.link' >> $testroot/stdout.expected + echo '+++ epsilon.link' >> $testroot/stdout.expected + echo '@@ -1 +1 @@' >> $testroot/stdout.expected + echo '-epsilon' >> $testroot/stdout.expected + echo '\ No newline at end of file' >> $testroot/stdout.expected + echo '+gamma' >> $testroot/stdout.expected + echo '\ No newline at end of file' >> $testroot/stdout.expected + echo -n 'blob - ' >> $testroot/stdout.expected + got tree -r $testroot/repo -c $commit_id1 -i | \ + grep 'nonexistent.link@ -> nonexistent$' | \ + cut -d' ' -f 1 | sed -e 's/$/ (mode 120000)/' \ + >> $testroot/stdout.expected + echo 'blob + /dev/null' >> $testroot/stdout.expected + echo '--- nonexistent.link' >> $testroot/stdout.expected + echo '+++ /dev/null' >> $testroot/stdout.expected + echo '@@ -1 +0,0 @@' >> $testroot/stdout.expected + echo '-nonexistent' >> $testroot/stdout.expected + echo '\ No newline at end of file' >> $testroot/stdout.expected + echo 'blob - /dev/null' >> $testroot/stdout.expected + echo -n 'blob + ' >> $testroot/stdout.expected + got tree -r $testroot/repo -c $commit_id2 -i | \ + grep 'zeta.link@ -> epsilon/zeta$' | \ + cut -d' ' -f 1 | sed -e 's/$/ (mode 120000)/' \ + >> $testroot/stdout.expected + echo '--- /dev/null' >> $testroot/stdout.expected echo '+++ zeta.link' >> $testroot/stdout.expected echo '@@ -0,0 +1 @@' >> $testroot/stdout.expected echo '+epsilon/zeta' >> $testroot/stdout.expected @@ -473,3 +590,4 @@ run_test test_diff_lightweight_tag run_test test_diff_ignore_whitespace run_test test_diff_submodule_of_same_repo run_test test_diff_symlinks_in_work_tree +run_test test_diff_symlinks_in_repo