Module: Berkshelf::FileSyncer
Constant Summary collapse
- IGNORED_FILES =
Files to be ignored during a directory globbing
%w{. ..}.freeze
Instance Method Summary collapse
-
#glob(pattern, **kwargs) ⇒ Array<String>
Glob across the given pattern, accounting for dotfiles, removing Ruby’s dumb idea to include ‘.’ and ‘..’ as entries.
-
#sync(source, destination, options = {}) ⇒ true
Copy the files from
source
todestination
, while removing any files indestination
that are not present insource
.
Instance Method Details
#glob(pattern, **kwargs) ⇒ Array<String>
Globbing on windows is strange. Do not pass a path that contains “symlinked” directories. Dir.glob will not see them. As an example, ‘C:Documents and Settings’ is not a real directory and int recent versions of windows points at ‘C:users’. Some users have their temp directory still referring to ‘C:Documents and Settings’.
Glob across the given pattern, accounting for dotfiles, removing Ruby’s dumb idea to include ‘.’ and ‘..’ as entries.
27 28 29 30 31 32 |
# File 'lib/berkshelf/file_syncer.rb', line 27 def glob(pattern, **kwargs) Dir.glob(pattern, File::FNM_DOTMATCH, **kwargs).sort.reject do |file| basename = File.basename(file) IGNORED_FILES.include?(basename) end end |
#sync(source, destination, options = {}) ⇒ true
Copy the files from source
to destination
, while removing any files in destination
that are not present in source
.
The method accepts an optional :exclude
parameter to ignore files and folders that match the given pattern(s). Note the exclude pattern behaves on paths relative to the given source. If you want to exclude a nested directory, you will need to use something like **/directory.
56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 |
# File 'lib/berkshelf/file_syncer.rb', line 56 def sync(source, destination, = {}) unless File.directory?(source) raise ArgumentError, "`source' must be a directory, but was a " \ "`#{File.ftype(source)}'! If you just want to sync a file, use " \ "the `copy' method instead." end # Reject any files that match the excludes pattern excludes = Array([:exclude]).map do |exclude| [exclude, "#{exclude}/*"] end.flatten source_files = glob("**/*", base: source).reject do |source_file| excludes.any? { |exclude| File.fnmatch?(exclude, source_file, File::FNM_DOTMATCH) } end # Ensure the destination directory exists FileUtils.mkdir_p(destination) unless File.directory?(destination) # Copy over the filtered source files source_files.each do |relative_path| source_file = File.join(source, relative_path) # Create the parent directory parent = File.join(destination, File.dirname(relative_path)) FileUtils.mkdir_p(parent) unless File.directory?(parent) case File.ftype(source_file).to_sym when :directory FileUtils.mkdir_p("#{destination}/#{relative_path}") when :link target = File.readlink(source_file) destination = File.(destination) FileUtils.ln_sf(target, "#{destination}/#{relative_path}") when :file # TODO: Workaround issue related to [1] which impacts running ChefSpec on Github Actions # [1] https://github.com/docker/for-linux/issues/1015 FileUtils.touch(source_file) FileUtils.cp(source_file, "#{destination}/#{relative_path}") else type = File.ftype(source_file) raise "Unknown file type: `#{type}' at " \ "`#{source_file}'. Failed to sync `#{source_file}' to " \ "`#{destination}/#{relative_path}'!" end end if [:delete] # Remove any files in the destination that are not in the source files destination_files = glob("**/*", base: destination) # Remove any extra files that are present in the destination, but are # not in the source list extra_files = destination_files - source_files extra_files.each do |file| FileUtils.rm_rf(File.join(destination, file)) end end true end |