diff --git a/lib/rscons.rb b/lib/rscons.rb index 859f381..8a22bfb 100644 --- a/lib/rscons.rb +++ b/lib/rscons.rb @@ -26,9 +26,16 @@ module Rscons # Remove all generated files def self.clean cache = Cache.new + # remove all built files cache.targets.each do |target| FileUtils.rm_f(target) end + # remove all created directories if they are empty + cache.directories.sort {|a, b| b.size <=> a.size}.each do |directory| + if (Dir.entries(directory) - ['.', '..']).empty? + Dir.rmdir(directory) rescue nil + end + end Cache.clear end end diff --git a/lib/rscons/builder.rb b/lib/rscons/builder.rb index f122001..f715291 100644 --- a/lib/rscons/builder.rb +++ b/lib/rscons/builder.rb @@ -24,7 +24,7 @@ module Rscons # Return the name of the target or false on failure. def standard_build(short_cmd_string, target, command, sources, env, cache) unless cache.up_to_date?(target, command, sources) - FileUtils.mkdir_p(File.dirname(target)) + cache.mkdir_p(File.dirname(target)) FileUtils.rm_f(target) return false unless env.execute(short_cmd_string, command) cache.register_build(target, command, sources) diff --git a/lib/rscons/builders/object.rb b/lib/rscons/builders/object.rb index ca10704..f4dcd82 100644 --- a/lib/rscons/builders/object.rb +++ b/lib/rscons/builders/object.rb @@ -55,7 +55,7 @@ module Rscons end command = env.build_command(env["#{com_prefix}COM"], vars) unless cache.up_to_date?(target, command, sources) - FileUtils.mkdir_p(File.dirname(target)) + cache.mkdir_p(File.dirname(target)) FileUtils.rm_f(target) return false unless env.execute("#{com_prefix} #{target}", command) deps = sources diff --git a/lib/rscons/cache.rb b/lib/rscons/cache.rb index 4eda621..ee133e5 100644 --- a/lib/rscons/cache.rb +++ b/lib/rscons/cache.rb @@ -36,6 +36,11 @@ module Rscons # ] # } # } + # directories: { + # 'build' => true, + # 'build/one' => true, + # 'build/two' => true, + # } # } class Cache #### Constants @@ -57,6 +62,7 @@ module Rscons def initialize @cache = YAML.load(File.read(CACHE_FILE)) rescue { targets: {}, + directories: {}, version: VERSION, } @lookup_checksums = {} @@ -137,6 +143,26 @@ module Rscons @cache[:targets].keys end + # Make any needed directories and record the ones that are created for + # removal upon a "clean" operation. + def mkdir_p(path) + parts = path.split(/[\\\/]/) + (0..parts.size).each do |i| + subpath = File.join(*parts[0, i + 1]) + unless File.exists?(subpath) + FileUtils.mkdir(subpath) + unless @cache[:directories].include?(subpath) + @cache[:directories][subpath] = true + end + end + end + end + + # Return a list of directories which were created as a part of the build + def directories + @cache[:directories].keys + end + # Private Instance Methods private diff --git a/lib/rscons/environment.rb b/lib/rscons/environment.rb index ac2cb8e..0c5c1f3 100644 --- a/lib/rscons/environment.rb +++ b/lib/rscons/environment.rb @@ -96,7 +96,6 @@ module Rscons end build_fname.gsub!('\\', '/') end - FileUtils.mkdir_p(File.dirname(build_fname)) build_fname end diff --git a/spec/build_tests_spec.rb b/spec/build_tests_spec.rb index 96bd2ca..7e35104 100644 --- a/spec/build_tests_spec.rb +++ b/spec/build_tests_spec.rb @@ -128,6 +128,24 @@ describe Rscons do Rscons.clean File.exists?('build/one/one.o').should be_false File.exists?('build/two/two.o').should be_false + File.exists?('build/one').should be_false + File.exists?('build/two').should be_false + File.exists?('build').should be_false + File.exists?('src/one/one.c').should be_true + end + + it 'does not clean created directories if other non-rscons-generated files reside there' do + lines = test_dir('build_dir') + `./build_dir`.should == "Hello from two()\n" + File.exists?('build/one/one.o').should be_true + File.exists?('build/two/two.o').should be_true + File.open('build/two/tmp', 'w') { |fh| fh.puts "dum" } + Rscons.clean + File.exists?('build/one/one.o').should be_false + File.exists?('build/two/two.o').should be_false + File.exists?('build/one').should be_false + File.exists?('build/two').should be_true + File.exists?('build').should be_true File.exists?('src/one/one.c').should be_true end