Class: TargetIO::TrainCompat::File

Inherits:
Object
  • Object
show all
Defined in:
lib/chef/target_io/train/file.rb

Class Method Summary collapse

Class Method Details

.__transport_connectionObject



214
215
216
# File 'lib/chef/target_io/train/file.rb', line 214

def __transport_connection
  Chef.run_context&.transport_connection
end

.binread(name, length = nil, offset = 0) ⇒ Object



12
13
14
15
16
17
# File 'lib/chef/target_io/train/file.rb', line 12

def binread(name, length = nil, offset = 0)
  content = read(file_name)
  length = content.size - offset if length.nil?

  content[offset, length]
end

.executable?(file_name) ⇒ Boolean

START Could be in Train::File::...

Returns:

  • (Boolean)


71
72
73
# File 'lib/chef/target_io/train/file.rb', line 71

def executable?(file_name)
  mode(file_name) & 0111 != 0
end

.expand_path(file_name, dir_string = "") ⇒ Object



19
20
21
22
23
24
25
# File 'lib/chef/target_io/train/file.rb', line 19

def expand_path(file_name, dir_string = "")
  require "pathname" unless defined?(Pathname)

  # Will just collapse relative paths inside
  pn = Pathname.new File.join(dir_string, file_name)
  pn.cleanpath
end

.foreach(name) ⇒ Object



5
6
7
8
9
10
# File 'lib/chef/target_io/train/file.rb', line 5

def foreach(name)
  raise "TargetIO does not implement block-less File.foreach yet" unless block_given?

  contents = readlines(name)
  contents.each { |line| yield(line) }
end

.method_missing(m, *args, **kwargs, &block) ⇒ Object

passthrough or map calls to third parties



145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
# File 'lib/chef/target_io/train/file.rb', line 145

def method_missing(m, *args, **kwargs, &block)
  nonio    = %i{extname join dirname path split}

  # TODO: writable?
  passthru = %i{basename directory? exist? exists? file? path pipe? socket? symlink?}
  redirect_train = {
    blockdev?: :block_device?,
    chardev?: :character_device?,
  }
  redirect_utils = {
    chown: :chown,
    chmod: :chmod,
    symlink: :ln_s,
    delete: :rm,
    unlink: :rm,
  }
  filestat = %i{gid group mode owner selinux_label size uid}

  if %i{stat lstat}.include? m
    Chef::Log.debug "File::#{m} passed to Train.file.stat"

    follow_symlink = m == :stat
    tfile = __transport_connection.file(args[0], follow_symlink).stat

    require "ostruct" unless defined?(OpenStruct)
    OpenStruct.new(tfile)

  # Non-IO methods can be issued locally
  elsif nonio.include? m
    ::File.send(m, *args, **kwargs) # TODO: pass block

  elsif passthru.include? m
    Chef::Log.debug "File::#{m} passed to Train.file.#{m}"

    file_name, other_args = args[0], args[1..]

    file = __transport_connection.file(file_name)
    file.send(m, *other_args, **kwargs) # block?

  elsif m == :mtime
    # Solve a data type disparity between Train.file and File
    timestamp = __transport_connection.file(args[0]).mtime
    Time.at(timestamp)

  elsif filestat.include? m
    Chef::Log.debug "File::#{m} passed to Train.file.stat.#{m}"

    __transport_connection.file(args[0]).stat[m]

  elsif redirect_utils.key?(m)
    new_method = redirect_utils[m]
    Chef::Log.debug "File::#{m} redirected to TargetIO::FileUtils.#{new_method}"

    ::TargetIO::FileUtils.send(new_method, *args, **kwargs) # TODO: pass block

  elsif redirect_train.key?(m)
    new_method = redirect_train[m]
    Chef::Log.debug "File::#{m} redirected to Train.file.#{new_method}"

    file_name, other_args = args[0], args[1..]

    file = __transport_connection.file(file_name)
    file.send(redirect[m], *other_args, **kwargs) # TODO: pass block

  else
    raise "Unsupported File method #{m}"
  end
end

.new(filename, mode = "r") ⇒ Object

Raises:

  • (NotImplementedError)


27
28
29
30
# File 'lib/chef/target_io/train/file.rb', line 27

def new(filename, mode = "r")
  # Would need to hook into io.close (Closure?)
  raise NotImplementedError, "TargetIO does not implement File.new yet"
end

.open(file_name, mode = "r") ⇒ Object



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
# File 'lib/chef/target_io/train/file.rb', line 36

def open(file_name, mode = "r")
  # Would need to hook into io.close (Closure?)
  raise "TargetIO does not implement block-less File.open with modes other than read yet" if mode != "r" && !block_given?

  content = exist?(file_name) ? read(file_name) : ""
  new_content = content.dup

  io = StringIO.new(new_content)

  if mode.start_with? "w"
    io.truncate(0)
  elsif mode.start_with? "a"
    io.seek(0, IO::SEEK_END)
  end

  if block_given?
    yield(io)

    if (content != new_content) && !mode.start_with?("r")
      __transport_connection.file(file_name).content = new_content # Need Train 2.5+
    end
  end

  io
end

.read(file_name) ⇒ Object



32
33
34
# File 'lib/chef/target_io/train/file.rb', line 32

def read(file_name)
  readlines(file_name)&.join("\n") || ""
end

.readable?(file_name) ⇒ Boolean

Returns:

  • (Boolean)


75
76
77
78
# File 'lib/chef/target_io/train/file.rb', line 75

def readable?(file_name)
  cmd = format("test -r %s", file_name)
  __transport_connection.run_command(cmd).exit_status == 0
end

.readlines(file_name) ⇒ Object

Raises:

  • (Errno::ENOENT)


62
63
64
65
66
67
# File 'lib/chef/target_io/train/file.rb', line 62

def readlines(file_name)
  content = __transport_connection.file(file_name).content
  raise Errno::ENOENT if content.nil? # Not found

  content.split("\n")
end

Raises:

  • (Errno::EINVAL)


105
106
107
108
109
110
111
112
# File 'lib/chef/target_io/train/file.rb', line 105

def readlink(file_name)
  raise Errno::EINVAL unless symlink?(file_name)

  cmd = "readlink #{file_name}"
  Chef::Log.debug cmd

  __transport_connection.run_command(cmd).stdout.chop
end

.realpath(file_name) ⇒ Object

def ftype(file_name) case type(file_name) when :block_device "blockSpecial" when :character_device "characterSpecial" when :symlink "link" else type(file_name).to_s end end



98
99
100
101
102
103
# File 'lib/chef/target_io/train/file.rb', line 98

def realpath(file_name)
  cmd = "realpath #{file_name}" # coreutils, not MacOSX
  Chef::Log.debug cmd

  __transport_connection.run_command(cmd).stdout.chop
end

.writable?(file_name) ⇒ Boolean

Returns:

  • (Boolean)


80
81
82
83
# File 'lib/chef/target_io/train/file.rb', line 80

def writable?(file_name)
  cmd = format("test -w %s", file_name)
  __transport_connection.run_command(cmd).exit_status == 0
end