[PATCH] Add --stowdir and --delete options to chkstow

[email protected] Thu, 11 Feb 2016 18:40:10 +0100
Newsgroups gmane.comp.gnu.stow.devel
Message-ID <[email protected]>
--K8nIJk4ghYZn606h
Content-Type: text/plain; charset=utf-8
Content-Disposition: inline
Content-Transfer-Encoding: quoted-printable

Hello,

I use GNU stow to manage my dotfiles and I love it.  The only thing I mis=
sed was
a way to remove leftover symlinks whenever I removed a file in my dotfile=
s
repository.

When I looked at the source to find out how easy it might be to implement=
 what I
needed, I stumbled upon chkstow (Which I had not heard of before =E2=80=93=
 A quick
search tells me it=E2=80=99s not even mentioned in the man page) which wa=
s almost
exactly what I looked for.

However, it prints every single symlink that points to non-existing files=
, even
though I only care about those files that point to non-existing files in =
my stow
directory (ie. my dotfiles repository).  Since the target is my home dire=
ctory,
there=E2=80=99s lots of garbage, abandoned projects, etc. lying around wh=
ich contain
stale symlinks.

To accomplish my goals (which I hope are shared by others, hence I=E2=80=99=
m writing
this mail), I added the following command line options:

* --stowdir: Sets the stow directory, so chkstow can determine whether a =
path is
  inside it, in order to ignore symlinks that point to outside of it.  By
  default, this value is set to "/", to stay backwards compatible =E2=80=93=
 this way no
  symlink will be ignored except if you supply this option.

* --delete: Makes chkstow delete all the =E2=80=9Cbogus symlinks=E2=80=9D=
 it discovers.

Both changes are attached as seperate patches to this email.  Feel free t=
o tell
me what I did wrong, since this is the first snippet of perl code I wrote=
 in my
whole life.

Thanks :)

--K8nIJk4ghYZn606h
Content-Type: text/plain; charset=utf-8
Content-Disposition: attachment; filename="0001-Add-stowdir-option-to-chkstow.patch"

From b3d63d2503a0325adfd04e9292f67e62f7b28e02 Mon Sep 17 00:00:00 2001
From: shak-mar <[email protected]>
Date: Thu, 11 Feb 2016 18:18:02 +0100
Subject: [PATCH 1/2] Add --stowdir option to chkstow

---
 bin/chkstow.in | 20 +++++++++++++++++++-
 1 file changed, 19 insertions(+), 1 deletion(-)

diff --git a/bin/chkstow.in b/bin/chkstow.in
index c35ba26..30e72b0 100755
--- a/bin/chkstow.in
+++ b/bin/chkstow.in
@@ -5,7 +5,9 @@ use warnings;
 
 require 5.006_001;
 
+use Cwd;
 use File::Find;
+use File::Spec;
 use Getopt::Long;
 
 my $DEFAULT_TARGET = '/usr/local/';
@@ -14,6 +16,8 @@ our $Wanted   = \&bad_links;
 our %Package  = ();
 our $Stow_dir = '';
 our $Target   = $DEFAULT_TARGET;
+our $Stowdir  = '/';
+our $TopCwd   = Cwd::cwd();
 
 # put the main loop into a block so that tests can load this as a module
 if ( not caller() ) {
@@ -31,7 +35,13 @@ sub process_options {
 	'a|aliens'   => sub { $Wanted = \&aliens    },
 	'l|list'     => sub { $Wanted = \&list      },
 	't|target=s' => \$Target,
+	's|stowdir=s' => \$Stowdir,
 	) or usage();
+    if ($Stowdir and $Wanted != \&bad_links) {
+        print "Only use --stowdir with --badlinks!\n";
+        usage ();
+    }
+    $Stowdir = File::Spec->rel2abs($Stowdir);
     return;
 }
 
@@ -45,6 +55,8 @@ Options:
     -b, --badlinks        Report symlinks that point to non-existent files
     -a, --aliens          Report non-symlinks in the target directory
     -l, --list            List packages in the target directory
+    -s DIR, --stowdir=DIR Ignore bad links to files outside of this directory
+                          (default is "/", so no links are ignored)
 
 --badlinks is the default mode.
 EOT
@@ -85,7 +97,13 @@ sub skip_dirs {
 
 # checking for files that do not link to anything
 sub bad_links {
-    -l && !-e && print "Bogus link: $File::Find::name\n";
+    if (-l && !-e) {
+        my $relpath = $File::Find::name;
+        my $abspath = join('/', $TopCwd, $relpath);
+        my $rel_from_stow = File::Spec->abs2rel(readlink $abspath, $Stowdir);
+        index($rel_from_stow, "..") == 0 && return;
+        print "Bogus link: $relpath\n";
+    }
 }
 
 # checking for files that are not owned by stow
-- 
2.7.0


--K8nIJk4ghYZn606h
Content-Type: text/plain; charset=utf-8
Content-Disposition: attachment; filename="0002-Add-delete-option-to-chkstow.patch"

From 2995d8d5dc49282c71a7aa30aaffccc804d90f46 Mon Sep 17 00:00:00 2001
From: shak-mar <[email protected]>
Date: Thu, 11 Feb 2016 18:13:48 +0100
Subject: [PATCH 2/2] Add --delete option to chkstow

---
 bin/chkstow.in | 15 ++++++++++++---
 1 file changed, 12 insertions(+), 3 deletions(-)

diff --git a/bin/chkstow.in b/bin/chkstow.in
index 30e72b0..e0c53b3 100755
--- a/bin/chkstow.in
+++ b/bin/chkstow.in
@@ -18,6 +18,7 @@ our $Stow_dir = '';
 our $Target   = $DEFAULT_TARGET;
 our $Stowdir  = '/';
 our $TopCwd   = Cwd::cwd();
+our $Delete   = 0;
 
 # put the main loop into a block so that tests can load this as a module
 if ( not caller() ) {
@@ -36,9 +37,10 @@ sub process_options {
 	'l|list'     => sub { $Wanted = \&list      },
 	't|target=s' => \$Target,
 	's|stowdir=s' => \$Stowdir,
+	'd|delete'   => \$Delete,
 	) or usage();
-    if ($Stowdir and $Wanted != \&bad_links) {
-        print "Only use --stowdir with --badlinks!\n";
+    if (($Stowdir or $Delete) and $Wanted != \&bad_links) {
+        print "Only use --stowdir and --delete with --badlinks!\n";
         usage ();
     }
     $Stowdir = File::Spec->rel2abs($Stowdir);
@@ -57,6 +59,7 @@ Options:
     -l, --list            List packages in the target directory
     -s DIR, --stowdir=DIR Ignore bad links to files outside of this directory
                           (default is "/", so no links are ignored)
+    -d, --delete          Delete links discovered by --badlinks
 
 --badlinks is the default mode.
 EOT
@@ -102,7 +105,13 @@ sub bad_links {
         my $abspath = join('/', $TopCwd, $relpath);
         my $rel_from_stow = File::Spec->abs2rel(readlink $abspath, $Stowdir);
         index($rel_from_stow, "..") == 0 && return;
-        print "Bogus link: $relpath\n";
+        if ($Delete) {
+            print "Deleting bogus link: $file...\n";
+            unlink $abspath or die "Failed to delete $abspath: $!";
+        }
+        else {
+            print "Bogus link: $file\n";
+        }
     }
 }
 
-- 
2.7.0


--K8nIJk4ghYZn606h--