Deleting empty directories

P

Paul van Delst

Hello,

I'm putting together a script to automatically update a repository working copy. The
scenario is such that the versioned working copy itself is not being modified, but I am
simply rsync'ing changes from an unversioned source (i.e. just a bunch of directories),
and then committing (and then tagging) those files. It sounds weird, I know, but it's just
temporary. Honest.

Anyway, the need has arisen to delete empty directory heirarchies (rsync will delete the
files but not the directories because of the .svn subdirs). What I've done so far is this:

require 'fileutils'

def empty_dirs
@current.collect do |f|
f if (File.directory?(f) && Dir.glob("#{f}/*").empty?)
end.compact
end

def remove_empty_dirs
while not empty_dirs.empty?
empty_dirs.each {|d| FileUtils.rm_rf(d)}
end
end

where the @current contains the updated list of files in my versioned working copy after I
rsync'd, but before I started comparing the changes in my working copy. I created a dummy
repository with a relatively complicated heirarchy of directories to test the above and it
seems to work. However, two things bug me:

Firstly, in empty_dirs, I think

f if (File.directory?(f) && Dir.glob("#{f}/*").empty?)

looks ugly. My limited experience is that if something looks ugly it can usually be
expressed better. I haven't used collect too much either, so its intricacies escape me.


Secondly, I prefer not to test for negatives, as in

while not empty_dirs.empty?

I also would rather not have an open loop either, but if a directory contains empty
subdirectories, the parent directory is not considered empty, and etc. etc. As you can
probably tell, recursion is not my strong point.

Would any kind soul out there care to provide any pointers for cleaning up the methods above?

Thanks for any info,

cheers,

paulv

p.s. BTW, I think the remove_empty_dirs method still needs to remove the deleted
directories from @current to prevent them being tested again in the next call to empty_dirs.
 
D

dblack

Hi --

Hello,

I'm putting together a script to automatically update a repository working
copy. The scenario is such that the versioned working copy itself is not
being modified, but I am simply rsync'ing changes from an unversioned source
(i.e. just a bunch of directories), and then committing (and then tagging)
those files. It sounds weird, I know, but it's just temporary. Honest.

Anyway, the need has arisen to delete empty directory heirarchies (rsync will
delete the files but not the directories because of the .svn subdirs). What
I've done so far is this:

require 'fileutils'

def empty_dirs
@current.collect do |f|
f if (File.directory?(f) && Dir.glob("#{f}/*").empty?)
end.compact
end

def remove_empty_dirs
while not empty_dirs.empty?
empty_dirs.each {|d| FileUtils.rm_rf(d)}
end
end

where the @current contains the updated list of files in my versioned working
copy after I rsync'd, but before I started comparing the changes in my
working copy. I created a dummy repository with a relatively complicated
heirarchy of directories to test the above and it seems to work. However, two
things bug me:

Firstly, in empty_dirs, I think

f if (File.directory?(f) && Dir.glob("#{f}/*").empty?)

looks ugly. My limited experience is that if something looks ugly it can
usually be expressed better. I haven't used collect too much either, so its
intricacies escape me.

You're currently using collect plus compact, but you can actually just
use select. (That's not a general equivalence, but in this case it
applies.)

@current.select do |f|
File.directory?(f) && Dir["#{f}/*"].empty?
end

I'd be inclined to break things out a little. (Untested code follows
-- please test on expendable data :)

require 'fileutils'

def dirs
@current.select {|f| File.dir?(f) }
end

def empty_dirs
dirs.select {|d| Dir["#{d}/*"].empty? }
end

def non_empty_dirs
dirs - empty_dirs
end

def remove_empty_dirs
non_empty_dirs.each {|d| FileUtils.rm_rf(d) }
end
Secondly, I prefer not to test for negatives, as in

while not empty_dirs.empty?

You can use until instead of while not.
I also would rather not have an open loop either, but if a directory contains
empty subdirectories, the parent directory is not considered empty, and etc.
etc. As you can probably tell, recursion is not my strong point.

Would any kind soul out there care to provide any pointers for cleaning up
the methods above?

Thanks for any info,

cheers,

paulv

p.s. BTW, I think the remove_empty_dirs method still needs to remove the
deleted directories from @current to prevent them being tested again in the
next call to empty_dirs.

Or you can reset @current before each call, or some combination. I
haven't done either in my sample code; I'm just assuming that @current
is what it should be, but you'll definitely have to factor that in.


David

--
* Books:
RAILS ROUTING (new! http://www.awprofessional.com/title/0321509242)
RUBY FOR RAILS (http://www.manning.com/black)
* Ruby/Rails training
& consulting: Ruby Power and Light, LLC (http://www.rubypal.com)
 
P

Paul van Delst

Hi --

On Wed, 29 Aug 2007, Paul van Delst wrote:
[snip]
Anyway, the need has arisen to delete empty directory heirarchies
(rsync will delete the files but not the directories because of the
.svn subdirs). What I've done so far is this:

require 'fileutils'

def empty_dirs
@current.collect do |f|
f if (File.directory?(f) && Dir.glob("#{f}/*").empty?)
end.compact
end

def remove_empty_dirs
while not empty_dirs.empty?
empty_dirs.each {|d| FileUtils.rm_rf(d)}
end
end

[snip..asking for a better way]
You're currently using collect plus compact, but you can actually just
use select. (That's not a general equivalence, but in this case it
applies.)

@current.select do |f|
File.directory?(f) && Dir["#{f}/*"].empty?
end

I'd be inclined to break things out a little. (Untested code follows
-- please test on expendable data :)

require 'fileutils'

def dirs
@current.select {|f| File.dir?(f) }
end

def empty_dirs
dirs.select {|d| Dir["#{d}/*"].empty? }
end

def non_empty_dirs
dirs - empty_dirs
end

def remove_empty_dirs
non_empty_dirs.each {|d| FileUtils.rm_rf(d) }
end

Hello,

Excellent! David, thanks very much. The extra reduction of tasks is exactly what I was
looking for (it certainly is a skill that I am having difficulty mastering).

I changed the remove_empty_dirs to a) remove the empty, not non-empty, dirs (! :eek:), and b)
modify the @current file list:

def remove_empty_dirs
until empty_dirs.empty?
empty_dirs.each do |d|
@current.delete(d)
FileUtils.rm_rf(d)
end
end
end

Again, thanks very much.

cheers,

paulv
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,997
Messages
2,570,241
Members
46,831
Latest member
RusselWill

Latest Threads

Top