diff --git a/CHANGELOG.md b/CHANGELOG.md index a070d31..cb5a411 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ ## Development * Fix error `singleton can't be dumped (TypeError)` at the end of dynamic analysis ([#17](https://github.com/yujinakayama/transpec/issues/17)) +* Do not copy pseudo files (device, socket, etc.) in dynamic analysis ([#17](https://github.com/yujinakayama/transpec/issues/17)) ## v1.2.1 diff --git a/lib/transpec/dynamic_analyzer.rb b/lib/transpec/dynamic_analyzer.rb index e029a55..a1cdfd3 100644 --- a/lib/transpec/dynamic_analyzer.rb +++ b/lib/transpec/dynamic_analyzer.rb @@ -5,6 +5,8 @@ require 'transpec/file_finder' require 'transpec/project' require 'tmpdir' +require 'find' +require 'pathname' require 'fileutils' require 'shellwords' require 'English' @@ -127,7 +129,7 @@ def in_copied_project @in_copied_project = true Dir.mktmpdir do |tmpdir| - FileUtils.cp_r(@project.path, tmpdir) + copy_recursively(@project.path, tmpdir) @copied_project_path = File.join(tmpdir, @project.basename) Dir.chdir(@copied_project_path) do yield @@ -159,5 +161,44 @@ def run_rspec(paths) end end end + + def copy_recursively(source_root, destination_root) + source_root = File.expand_path(source_root) + source_root_pathname = Pathname.new(source_root) + + destination_root = File.expand_path(destination_root) + if File.directory?(destination_root) + destination_root = File.join(destination_root, File.basename(source_root)) + end + + Find.find(source_root) do |source_path| + relative_path = Pathname.new(source_path).relative_path_from(source_root_pathname).to_s + destination_path = File.join(destination_root, relative_path) + copy(source_path, destination_path) + end + end + + private + + def copy(source, destination) + if File.symlink?(source) + File.symlink(File.readlink(source), destination) + elsif File.directory?(source) + FileUtils.mkdir_p(destination) + elsif File.file?(source) + FileUtils.copy_file(source, destination) + end + + copy_permission(source, destination) if File.exist?(destination) + end + + def copy_permission(source, destination) + source_mode = File.lstat(source).mode + begin + File.lchmod(source_mode, destination) + rescue NotImplementedError, Errno::ENOSYS + File.chmod(source_mode, destination) + end + end end end diff --git a/spec/transpec/dynamic_analyzer_spec.rb b/spec/transpec/dynamic_analyzer_spec.rb index 93fdf9a..1e21f20 100644 --- a/spec/transpec/dynamic_analyzer_spec.rb +++ b/spec/transpec/dynamic_analyzer_spec.rb @@ -176,5 +176,66 @@ module Transpec end end end + + describe '#copy_recursively' do + it 'copies files recursively' do + [ + 'src/file1', + 'src/file2', + 'src/dir1/file', + 'src/dir2/file' + ].each do |path| + create_file(path, '') + end + + dynamic_analyzer.copy_recursively('src', 'dst') + + [ + 'dst/file1', + 'dst/file2', + 'dst/dir1/file', + 'dst/dir2/file' + ].each do |path| + File.exist?(path).should be_true + end + end + + it 'copies only directories, files and symlinks' do + create_file('src/file', '') + File.symlink('file', 'src/symlink') + Dir.mkdir('src/dir') + system('mkfifo', 'src/fifo') + + dynamic_analyzer.copy_recursively('src', 'dst') + + File.file?('dst/file').should be_true + File.symlink?('dst/symlink').should be_true + File.directory?('dst/dir').should be_true + File.exist?('dst/fifo').should be_false + end + + def chmod(mode, path) + File.lchmod(mode, path) + rescue NotImplementedError + File.chmod(mode, path) + end + + def permission(path) + format('%o', File.lstat(path).mode)[-4..-1] + end + + it 'preserves permission' do + create_file('src/file', '') + chmod(0755, 'src/file') + + Dir.mkdir('src/dir') + chmod(0600, 'src/dir') + + dynamic_analyzer.copy_recursively('src', 'dst') + + permission('dst/file').should == '0755' + permission('dst/dir').should == '0600' + end + end end end