Class: TargetIO::TrainCompat::File

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

Class Method Summary collapse

Methods included from Support

clean_staging, read_file, remote_user, run_command, staging_file, sudo?, transport_connection, upload, write_file

Class Method Details

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



16
17
18
19
20
21
# File 'lib/chef/target_io/train/file.rb', line 16

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

Returns:

  • (Boolean)


73
74
75
# File 'lib/chef/target_io/train/file.rb', line 73

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

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



23
24
25
26
27
28
29
# File 'lib/chef/target_io/train/file.rb', line 23

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



9
10
11
12
13
14
# File 'lib/chef/target_io/train/file.rb', line 9

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



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

def method_missing(m, *args, **kwargs, &block)
  nonio    = i{extname join dirname path split}
  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)


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

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



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

def open(file_name, mode = "r")
  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)

    # Return name of new remote file to be used in later operations
    file_name = write_file(file_name, new_content) if (content != new_content) && !mode.start_with?("r")

    return file_name
  end

  io
end

.read(file_name) ⇒ Object



36
37
38
# File 'lib/chef/target_io/train/file.rb', line 36

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

.readable?(file_name) ⇒ Boolean

Returns:

  • (Boolean)


77
78
79
80
# File 'lib/chef/target_io/train/file.rb', line 77

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

.readlines(file_name) ⇒ Object

Raises:

  • (Errno::ENOENT)


66
67
68
69
70
71
# File 'lib/chef/target_io/train/file.rb', line 66

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

  content.split("\n")
end

Raises:

  • (Errno::EINVAL)


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

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

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

  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



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

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

  run_command(cmd).stdout.chop
end

.setgid?(file_name) ⇒ Boolean

Returns:

  • (Boolean)


116
117
118
# File 'lib/chef/target_io/train/file.rb', line 116

def setgid?(file_name)
  mode(file_name) & 04000 != 0
end

.setuid?(file_name) ⇒ Boolean

Returns:

  • (Boolean)


120
121
122
# File 'lib/chef/target_io/train/file.rb', line 120

def setuid?(file_name)
  mode(file_name) & 02000 != 0
end

.size?(file_name) ⇒ Boolean

Returns:

  • (Boolean)


128
129
130
# File 'lib/chef/target_io/train/file.rb', line 128

def size?(file_name)
  exist?(file_name) && size(file_name) > 0
end

.sticky?(file_name) ⇒ Boolean

Returns:

  • (Boolean)


124
125
126
# File 'lib/chef/target_io/train/file.rb', line 124

def sticky?(file_name)
  mode(file_name) & 01000 != 0
end

.tempfile(filename) ⇒ Object



144
145
146
147
# File 'lib/chef/target_io/train/file.rb', line 144

def tempfile(filename)
  tempdir = ::TargetIO::Dir.mktmpdir(path)
  ::File.join(tempdir, filename)
end

.world_readable?(file_name) ⇒ Boolean

Returns:

  • (Boolean)


132
133
134
# File 'lib/chef/target_io/train/file.rb', line 132

def world_readable?(file_name)
  mode(file_name) & 0001 != 0
end

.world_writable?(file_name) ⇒ Boolean

Returns:

  • (Boolean)


136
137
138
# File 'lib/chef/target_io/train/file.rb', line 136

def world_writable?(file_name)
  mode(file_name) & 0002 != 0
end

.writable?(file_name) ⇒ Boolean

Returns:

  • (Boolean)


82
83
84
85
# File 'lib/chef/target_io/train/file.rb', line 82

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

.zero?(file_name) ⇒ Boolean

Returns:

  • (Boolean)


140
141
142
# File 'lib/chef/target_io/train/file.rb', line 140

def zero?(file_name)
  exists?(file_name) && size(file_name) == 0
end