diff options
| author | Paul Buetow <paul@buetow.org> | 2025-02-28 23:35:40 +0200 |
|---|---|---|
| committer | Paul Buetow <paul@buetow.org> | 2025-02-28 23:35:40 +0200 |
| commit | 3b731cf56c8d8c8514a063c96d5d2a3428e42425 (patch) | |
| tree | 660b6068f918884d2e79fad07f529ee032a3a7c0 | |
| parent | 90daa76feb3d3fd79992b97029cb526da0e6c417 (diff) | |
can copy recursively a directory
| -rw-r--r-- | TODO.md | 2 | ||||
| -rw-r--r-- | lib/dslkeywords/file.rb | 58 | ||||
| -rw-r--r-- | test/lib/dslkeywords/directory_test.rb | 68 |
3 files changed, 116 insertions, 12 deletions
@@ -1,6 +1,6 @@ # TODO -* Recursively install a directory (rsync? custom file copier?) +* Recursively change file permissions (for files and dirs) * Change permissions of a directory recursively * CRON jobs * Fedora diff --git a/lib/dslkeywords/file.rb b/lib/dslkeywords/file.rb index 1c62790..0c6ab9a 100644 --- a/lib/dslkeywords/file.rb +++ b/lib/dslkeywords/file.rb @@ -8,6 +8,7 @@ require_relative '../chained' module RCM # Backup the file on change module FileBackup + # TODO: Make protected? def backup!(file_path, checksum = nil) return if @without_backup @@ -19,6 +20,12 @@ module RCM make_backup!(file_path, suffix) end + def different?(file_a, file_b) + checksum_a = Digest::SHA256.file(file_a).hexdigest + checksum_b = Digest::SHA256.file(file_b).hexdigest + [checksum_a == checksum_b, checksum_a, cecksum_b] + end + private def make_backup!(file_path, suffix) @@ -208,10 +215,8 @@ module RCM ::File.write(tmp_path, text) if ::File.file?(@file_path) - checksum = Digest::SHA256.file(@file_path).hexdigest - tmp_checksum = Digest::SHA256.file(tmp_path).hexdigest - - if tmp_checksum == checksum + different, checksum, = different?(@file_path, tmp_path) + unless different ::File.delete(tmp_path) # File has not changed, not doing anything return end @@ -260,6 +265,8 @@ module RCM end class Directory < BaseFile + def recursively = @recursively = true + def evaluate! return unless super @@ -273,8 +280,12 @@ module RCM permissions! end + private + def evaluate_present! - return if ::File.directory?(@file_path) + if ::File.directory?(@file_path) + return @recursively ? evaluate_present_recursively! : nil + end create_parent_directory! if @manage_directory @@ -287,15 +298,50 @@ module RCM return unless ::File.directory?(@file_path) backup!(@file_path) + @recursively = true if @is == :purged what = @is == :purged ? 'Purging' : 'Deleting' do? "#{what} directory #{@file_path}" do if ::File.directory?(@file_path) - @is == :purged ? FileUtils.rm_r(@file_path) : Dir.delete(@file_path) + @recursively ? FileUtils.rm_r(@file_path) : Dir.delete(@file_path) end end cleanup_parent_directory! if @manage_directory end + + def evaluate_present_recursively! + source_path = content + raise "Source #{source_path} is not a directory!" unless ::File.directory?(source_path) + + if ::File.exist?(@file_path) + raise "Destination #{@file_path} is not a directory!" unless ::File.directory?(@file_path) + + backup_resursively!(source_path, @file_path) unless @without_backup + end + + do? "Copying #{source_path} -> #{@file_path} resursively" do + Dir["#{source_path}/*"].each { FileUtils.cp_r(_1, @file_path) } + end + end + + def backup_recursively!(source, dest) + Dir.foreach(source) do |entry| + next if ['.', '..'].include?(entry) + + source_path = ::File.join(source, entry) + dest_path = ::File.join(dest, entry) + + if ::File.directory?(source_path) && !::File.directory?(dest_path) + raise "Unable to copy directory #{source_path} into non-directory #{dest_path}" + elsif !::File.directory?(source_path) && ::File.directory?(dest_path) + raise "Unable to copy non-directory #{source_path} into directory #{dest_path}" + elsif ::File.directory?(source_path) && ::File.directory?(dest_path) + backup_recursively!(source_path, dest_path) + else + backup!(dest_path) + end + end + end end class DSL diff --git a/test/lib/dslkeywords/directory_test.rb b/test/lib/dslkeywords/directory_test.rb index 9fd249f..3245603 100644 --- a/test/lib/dslkeywords/directory_test.rb +++ b/test/lib/dslkeywords/directory_test.rb @@ -6,9 +6,9 @@ require_relative '../../../lib/dsl' class RCMDirectoryTest < Minitest::Test DIR_PATH = './.directory_test.rcmtmp'.freeze - Minitest.after_run do - FileUtils.rm_r(DIR_PATH) if File.directory?(DIR_PATH) - end + # Minitest.after_run do + # FileUtils.rm_r(DIR_PATH) if File.directory?(DIR_PATH) + # end def test_create_directory configure_from_scratch do @@ -28,7 +28,6 @@ class RCMDirectoryTest < Minitest::Test directory delete do path DIR_PATH is absent - requires directory create end end refute File.directory?(DIR_PATH) @@ -42,11 +41,70 @@ class RCMDirectoryTest < Minitest::Test end directory purge do path DIR_PATH - requires touch create is purged without backup end end refute File.directory?(DIR_PATH) end + + def test_copy_directory_recursively + expected_files = {} + + configure_from_scratch do + 2.times do |i| + file "file_#{i + 10}_dest" do + path "#{DIR_PATH}/dest_dir/file_#{i + 10}.txt" + manage directory + expected_files["file_#{i + 10}.txt"] = "file_#{i + 10}_dest" + "file_#{i + 10}_dest" + end + file "file_#{i}_dest" do + path "#{DIR_PATH}/dest_dir/file_#{i}.txt" + manage directory + expected_files["file_#{i}.txt"] = "file_#{i}_dest" + "file_#{i}_dest" + end + file "file_#{i}_sub_dest" do + path "#{DIR_PATH}/dest_dir/sub/file_#{i}.txt" + expected_files["sub/file_#{i}.txt"] = "sub_file_#{i}_dest" + manage directory + "sub_file_#{i}_dest" + end + end + + 4.times do |i| + file "file_#{i}_source" do + path "#{DIR_PATH}/source_dir/file_#{i}.txt" + manage directory + expected_files["file_#{i}.txt"] = "file_#{i}_source" + "file_#{i}_source" + end + file "file_#{i}_sub_source" do + path "#{DIR_PATH}/source_dir/sub/file_#{i}.txt" + manage directory + expected_files["sub/file_#{i}.txt"] = "sub_file_#{i}_source" + "sub_file_#{i}_source" + end + end + + directory "#{DIR_PATH}/dest_dir" do + recursively + without backup + "#{DIR_PATH}/source_dir" + end + end + + expected_files.each do |file_path, content| + assert File.file?("#{DIR_PATH}/dest_dir/#{file_path}") + assert_equal content, File.read("#{DIR_PATH}/dest_dir/#{file_path}") + end + + actual_files = (Dir["#{DIR_PATH}/dest_dir/*"] + Dir["#{DIR_PATH}/dest_dir/*/*"]).select { File.file?(_1) } + actual_files.each do |file_path| + key = file_path.sub("#{DIR_PATH}/dest_dir/", '') + assert expected_files.key?(key) + assert_equal File.read(file_path), expected_files[key] + end + end end |
