summaryrefslogtreecommitdiff
path: root/lib/dslkeywords/directory.rb
blob: 402bead969a727f3c73875df5f636e0f3a83eedb (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
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
require 'fileutils'

require_relative 'file'

module RCM
  # Manages directories: create, delete/purge, or recursively copy from
  # a source directory. Backup is performed before destructive operations.
  class Directory < BaseFile
    def recursively = @recursively = true

    def evaluate!
      return unless super

      case @is
      when :present
        evaluate_present!
      when :absent, :purged
        evaluate_absent!
      end
    ensure
      permissions!
    end

    private

    def evaluate_present!
      if ::File.directory?(@file_path)
        return @recursively ? evaluate_present_recursively! : nil
      end

      create_parent_directory! if @manage_directory

      do? "Creating directory #{@file_path}" do
        Dir.mkdir(@file_path)
      end
    end

    def evaluate_absent!
      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)
          @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_recursively!(source_path, @file_path) unless @without_backup
      end

      do? "Copying #{source_path} -> #{@file_path} recursively" do
        if ::File.directory?(@file_path)
          Dir["#{source_path}/*"].each { FileUtils.cp_r(_1, @file_path) }
        else
          FileUtils.cp_r(source_path, @file_path)
        end
      end
    end

    # TODO: Unit test this
    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
    def directory(file_path = nil, &block)
      return :directory if file_path.nil?
      return unless @conds_met

      d = Directory.new(file_path)
      d.content(d.instance_eval(&block))
      self << d
      d
    end
  end
end