summaryrefslogtreecommitdiff
path: root/lib/leap_cli/macros/files.rb
blob: 602fdddb81c4b25a1281fbc9eb92c913f594184e (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
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
# encoding: utf-8

##
## FILES
##

module LeapCli
  module Macro

    #
    # inserts the contents of a file
    #
    def file(filename, options={})
      if filename.is_a? Symbol
        filename = [filename, @node.name]
      end
      filepath = Path.find_file(filename)
      if filepath
        if filepath =~ /\.erb$/
          return ERB.new(File.read(filepath, :encoding => 'UTF-8'), nil, '%<>').result(binding)
        else
          return File.read(filepath, :encoding => 'UTF-8')
        end
      else
        raise FileMissing.new(Path.named_path(filename), options)
      end
    end

    #
    # like #file, but allow missing files
    #
    def try_file(filename)
      return file(filename)
    rescue FileMissing
      return nil
    end

    #
    # returns the location of a file that is stored on the local
    # host, under PROVIDER_DIR/files.
    #
    def local_file_path(path, options={})
      if path.is_a? Symbol
        path = [path, @node.name]
      elsif path.is_a? String
        # ensure it prefixed with files/
        unless path =~ /^files\//
          path = "files/" + path
        end
      end
      local_path = Path.find_file(path)
      if local_path.nil?
        if options[:missing]
          raise FileMissing.new(Path.named_path(path), options)
        elsif block_given?
          yield
          return local_file_path(path, options) # try again.
        else
          Util::log 2, :skipping, "local_file_path(\"#{path}\") because there is no such file."
          return nil
        end
      else
        return local_path
      end
    end

    #
    # Returns the location of a file once it is deployed via rsync to the a
    # remote server. An internal list of discovered file paths is saved, in
    # order to rsync these files when needed.
    #
    # If the file does not exist, nil is returned.
    #
    # If there is a block given and the file does not actually exist, the
    # block will be yielded to give an opportunity for some code to create the
    # file.
    #
    # For example:
    #
    #   file_path(:dkim_priv_key) {generate_dkim_key}
    #
    # Notes:
    #
    # * Argument 'path' must be relative to Path.provider/files or
    #   Path.provider_base/files. It is OK for the path to be prefixed with
    #   with 'files/', this prefix will be ignored.
    #
    # * The path returned by this method is an absolute path on the server.
    #
    # * The path stored for use later by rsync is relative to the local
    #   Path.provider. It should always be prefixed with 'files/'
    #
    # * If the path does not exist locally, but exists in provider_base,
    #   then the default file from provider_base is copied locally. this
    #   is required for rsync to work correctly.
    #
    #   NOTE: this is an aweful way to do this. It would be better
    #         to rsync twice.
    #
    def remote_file_path(path, options={}, &block)
      local_path = local_file_path(path, options, &block)
      return nil if local_path.nil?

      # if file is under Path.provider_base, we must copy the default file to
      # to Path.provider in order for rsync to be able to sync the file.
      if local_path =~ /^#{Regexp.escape(Path.provider_base)}/
        local_provider_path = local_path.sub(/^#{Regexp.escape(Path.provider_base)}/, Path.provider)
        FileUtils.mkdir_p File.dirname(local_provider_path), :mode => 0700
        FileUtils.install local_path, local_provider_path, :mode => 0600
        Util.log :created, Path.relative_path(local_provider_path)
        local_path = local_provider_path
      end

      # ensure directories end with /, important for building rsync command
      if File.directory?(local_path) && local_path !~ /\/$/
        local_path += '/'
      end

      relative_path = Path.relative_path(local_path)
      @node.file_paths << relative_path
      return File.join(
        Leap::Platform.files_dir,
        relative_path.sub(/^files\//, '')
      )
    end

    # deprecated
    def file_path(path, options={})
      return remote_file_path(path, options)
    end

  end
end