From f678803a5d32d2f3a49acb390a1745699ca8f86b Mon Sep 17 00:00:00 2001 From: Josh Holtrop Date: Sat, 7 Feb 2015 09:49:29 -0500 Subject: [PATCH] add Install builder - close #6 --- lib/rscons.rb | 4 +- lib/rscons/builders/install.rb | 59 ++++++++++++++++++++++++ spec/build_tests_spec.rb | 83 ++++++++++++++++++++++++++++++++++ 3 files changed, 145 insertions(+), 1 deletion(-) create mode 100644 lib/rscons/builders/install.rb diff --git a/lib/rscons.rb b/lib/rscons.rb index fc4bf5d..9add59d 100644 --- a/lib/rscons.rb +++ b/lib/rscons.rb @@ -6,10 +6,11 @@ require_relative "rscons/varset" require_relative "rscons/version" # default builders -require_relative "rscons/builders/command" require_relative "rscons/builders/cfile" +require_relative "rscons/builders/command" require_relative "rscons/builders/directory" require_relative "rscons/builders/disassemble" +require_relative "rscons/builders/install" require_relative "rscons/builders/library" require_relative "rscons/builders/object" require_relative "rscons/builders/preprocess" @@ -25,6 +26,7 @@ module Rscons :CFile, :Directory, :Disassemble, + :Install, :Library, :Object, :Preprocess, diff --git a/lib/rscons/builders/install.rb b/lib/rscons/builders/install.rb new file mode 100644 index 0000000..e8df7ac --- /dev/null +++ b/lib/rscons/builders/install.rb @@ -0,0 +1,59 @@ +require "pathname" + +module Rscons + module Builders + # The Install builder copies files/directories to new locations. + class Install < Builder + + # Run the builder to produce a build target. + # + # @param target [String] Target file name. + # @param sources [Array] Source file name(s). + # @param cache [Cache] The Cache object. + # @param env [Environment] The Environment executing the builder. + # @param vars [Hash,VarSet] Extra construction variables. + # + # @return [String,false] + # Name of the target file on success or false on failure. + def run(target, sources, cache, env, vars) + target_is_dir = (sources.length > 1) || + Dir.exists?(sources.first) || + Dir.exists?(target) + outdir = target_is_dir ? target : File.dirname(target) + # Collect the list of files to copy over. + file_map = {} + if target_is_dir + sources.each do |src| + if Dir.exists? src + Dir.glob("#{src}/**/*", File::FNM_DOTMATCH).select do |f| + File.file?(f) + end.each do |subfile| + subpath = Pathname.new(subfile).relative_path_from(Pathname.new(src)).to_s + file_map[subfile] = "#{outdir}/#{subpath}" + end + else + file_map[src] = "#{outdir}/#{File.basename(src)}" + end + end + else + file_map[sources.first] = target + end + printed_message = false + file_map.each do |src, dest| + # Check the cache and copy if necessary + unless cache.up_to_date?(dest, :Copy, [src], env) + unless printed_message + puts "#{name} #{target}" + printed_message = true + end + cache.mkdir_p(File.dirname(dest)) + FileUtils.cp(src, dest, :preserve => true) + end + cache.register_build(dest, :Copy, [src], env) + end + target if (target_is_dir ? Dir.exists?(target) : File.exists?(target)) + end + + end + end +end diff --git a/spec/build_tests_spec.rb b/spec/build_tests_spec.rb index c094919..c607a22 100644 --- a/spec/build_tests_spec.rb +++ b/spec/build_tests_spec.rb @@ -832,4 +832,87 @@ EOF end end + context "Install buildler" do + let(:base_env) do + test_dir("build_dir") + Rscons::Environment.new do |env| + env["CPPPATH"] = Dir["src/**/"] + env["sources"] = Dir["src/**/*.c"] + env.Program("simple.exe", "${sources}") + end + end + + it "copies a file to the target file name" do + env = base_env.clone do |env| + lines + env.Install("inst.exe", "simple.exe") + end + expect(lines).to eq(["Install inst.exe"]) + env.Install("inst.exe", "simple.exe") + env.process + expect(lines).to eq([]) + expect(File.exists?("inst.exe")).to be_truthy + expect(File.read("inst.exe", mode: "rb")).to eq(File.read("simple.exe", mode: "rb")) + FileUtils.rm("inst.exe") + env.Install("inst.exe", "simple.exe") + env.process + expect(lines).to eq(["Install inst.exe"]) + end + + it "copies a file to the target directory name" do + env = base_env.clone do |env| + lines + env.Directory("inst") + env.Install("inst", "simple.exe") + end + expect(lines).to eq([ + "Directory inst", + "Install inst", + ]) + env.Install("inst", "simple.exe") + env.process + expect(lines).to eq([]) + expect(File.exists?("inst/simple.exe")).to be_truthy + expect(File.read("inst/simple.exe", mode: "rb")).to eq(File.read("simple.exe", mode: "rb")) + end + + it "copies a directory to the non-existent target directory name" do + env = base_env.clone do |env| + lines + env.Install("dist/src", "src") + end + expect(lines).to eq(["Install dist/src"]) + env.Install("dist/src", "src") + env.process + expect(lines).to eq([]) + %w[src/one/one.c src/two/two.c src/two/two.h].each do |f| + expect(File.exists?("dist/#{f}")).to be_truthy + expect(File.read("dist/#{f}", mode: "rb")).to eq(File.read(f, mode: "rb")) + end + end + + it "copies a directory to the existent target directory name" do + env = base_env.clone do |env| + lines + env.Directory("dist/src") + env.Install("dist/src", "src") + end + expect(lines).to eq([ + "Directory dist/src", + "Install dist/src", + ]) + env.Install("dist/src", "src") + env.process + expect(lines).to eq([]) + %w[src/one/one.c src/two/two.c src/two/two.h].each do |f| + expect(File.exists?("dist/#{f}")).to be_truthy + expect(File.read("dist/#{f}", mode: "rb")).to eq(File.read(f, mode: "rb")) + end + FileUtils.rm("dist/src/two/two.c") + env.Install("dist/src", "src") + env.process + expect(lines).to eq(["Install dist/src"]) + end + end + end