Class: File

Inherits:
Object show all
Defined in:
lib/amp/dependencies/zip/stdrubyext.rb,
lib/amp/support/ruby_19_compatibility.rb,
lib/amp/support/support.rb

Direct Known Subclasses

BugFix::Tempfile

Defined Under Namespace

Classes: Stat

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.amp_atomic_write(file_name, mode = 'w', default_mode = nil, temp_dir = Dir.tmpdir, &block) ⇒ Object

taken from Rails’ ActiveSupport all or nothing babyyyyyyyy use this only for writes, otherwise it’s just inefficient file_name is FULL PATH



378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
# File 'lib/amp/support/support.rb', line 378

def self.amp_atomic_write(file_name, mode='w', default_mode=nil, temp_dir=Dir.tmpdir, &block)
  File.makedirs(File.dirname(file_name))
  FileUtils.touch(file_name) unless File.exists? file_name
  # this is sorta like "checking out" a file
  # but only if we're *just* writing
  new_path = join temp_dir, amp_make_tmpname(basename(file_name))
  unless mode == 'w'
    copy(file_name, new_path) # allowing us to use mode "a" and others
  end

  
  # open and close it
  val = Kernel::open new_path, mode, &block
  
  begin
    # Get original file permissions
    old_stat = stat(file_name)
  rescue Errno::ENOENT
    # No old permissions, write a temp file to determine the defaults
    check_name = ".permissions_check.#{Thread.current.object_id}.#{Process.pid}.#{rand(1000000)}"
    Kernel::open(check_name, "w") { }
    old_stat = stat(check_name)
    unlink(check_name)
    delete(check_name)
  end
  
  # do a chmod, pretty much
  begin
    nlink = File.amp_num_hardlinks(file_name)
  rescue Errno::ENOENT, OSError
    nlink = 0
    d = File.dirname(file_name)
    File.mkdir_p(d, default_mode) unless File.directory? d
  end
  
  new_mode = default_mode & 0666 if default_mode
  
  # Overwrite original file with temp file
  amp_force_rename(new_path, file_name)
  
  # Set correct permissions on new file
  chown(old_stat.uid, old_stat.gid, file_name)
  chmod(new_mode || old_stat.mode, file_name)
  
  val
end

.amp_directories_to(path, empty = false) ⇒ Array

All directories leading up to this path

Examples:

directories_to “/Users/ari/src/monkey.txt” # =>

["/Users/ari/src", "/Users/ari", "/Users"]

directories_to “/Users/ari/src/monkey.txt”, true # =>

["/Users/ari/src", "/Users/ari", "/Users", ""]

Parameters:

  • path (String)

    the path to the file we’re examining

  • empty (Boolean) (defaults to: false)

    whether or not to return an empty string as well

Returns:

  • (Array)

    the directories leading up to this path



494
495
496
497
498
499
500
501
502
# File 'lib/amp/support/support.rb', line 494

def self.amp_directories_to(path, empty=false)
  path = File.expand_path(path)
  dirs = path.split('/')[0..-2]
  ret  = []
  
  dirs.size.times { ret << dirs.join('/'); dirs.pop }
  ret << '' if empty
  ret
end

.amp_find_executable(command) ⇒ String?

TODO:

Add Windows Version.

Finds an executable for Amp::KernelMethods#command. Searches like the OS does. If command is a basename then PATH is searched for Amp::KernelMethods#command. PATH isn’t searched if command is an absolute or relative path. If command isn’t found, nil is returned. *nix only.

Parameters:

  • command (String)

    the executable to find

Returns:

  • (String, nil)

    If the executable is found, the full path is returned.



358
359
360
361
362
363
364
365
366
367
368
369
370
371
# File 'lib/amp/support/support.rb', line 358

def self.amp_find_executable(command)
  find_if_exists = proc do |executable|
    return executable if File.exist? executable
    return nil
  end
  
  return find_if_exists[command] if command.include?(File::SEPARATOR)
  ENV["PATH"].split(File::PATH_SEPARATOR).each do |path|
    executable = find_if_exists[File.join(path, command)]
    return executable if executable
  end
  
  nil
end

.amp_force_rename(file, dst) ⇒ Object

Forces a rename from file to dst, removing the dst file if it already exists. Avoids system exceptions that might result.

Parameters:

  • file (String)

    the source file path

  • dst (String)

    the destination file path



510
511
512
513
514
515
516
517
518
# File 'lib/amp/support/support.rb', line 510

def self.amp_force_rename(file, dst)
  return unless File.exist? file
  if File.exist? dst
    File.unlink dst
    File.rename file, dst
  else
    File.rename file, dst
  end
end

.amp_lookup_reg(a, b) ⇒ Object

TODO:

Add Windows Version

Does a registry lookup. *nix version.



345
346
347
# File 'lib/amp/support/support.rb', line 345

def self.amp_lookup_reg(a,b)
  nil
end

.amp_make_tmpname(basename) ⇒ String

Makes a fancy, quite-random name for a temporary file. Uses the file’s name, the current time, the process number, a random number, and the file’s extension to make a very random filename.

Of course, it could still fail.

Parameters:

  • basename (String)

    The base name of the file - just the file’s name and extension

Returns:

  • (String)

    the pseudo-random name of the file to be created



434
435
436
437
438
439
440
441
442
443
444
# File 'lib/amp/support/support.rb', line 434

def self.amp_make_tmpname(basename)
  case basename
  when Array
    prefix, suffix = *basename
  else
    prefix, suffix = basename, "."+File.extname(basename)
  end

  t = Time.now.strftime("%Y%m%d")
  path = "#{prefix}#{t}-#{$$}-#{rand(0x100000000).to_s(36)}-#{suffix}"
end

.amp_name(file) ⇒ Object

Returns the full name of the file, excluding path information.

Parameters:

Returns:

  • the name of the file



525
526
527
# File 'lib/amp/support/support.rb', line 525

def self.amp_name(file)
  File.split(file.path).last
end

Finds the number of hard links to the file.

Parameters:

  • file (String)

    the full path to the file to lookup

Returns:

  • (Integer)

    the number of hard links to the file

Raises:



478
479
480
481
482
# File 'lib/amp/support/support.rb', line 478

def self.amp_num_hardlinks(file)
  lstat = File.lstat(file)
  raise OSError.new("no lstat on windows") if lstat.nil?
  lstat.nlink
end

.amp_set_executable(path, executable) ⇒ Object

TODO:

Windows version

Sets a file’s executable bit.

Parameters:

  • path (String)

    the path to the file

  • executable (Boolean)

    sets whether the file is executable or not



328
329
330
331
332
333
334
335
336
337
338
# File 'lib/amp/support/support.rb', line 328

def self.amp_set_executable(path, executable)
  s = File.lstat(path).mode
  sx = s & 0100
  if executable && !sx
    # Turn on +x for every +r bit when making a file executable
    # and obey umask. (direct from merc. source)
    File.chmod(s | (s & 0444) >> 2 & ~(File.umask(0)), path)
  elsif !executable && sx
    File.chmod(s & 0666 , path)
  end
end

.amp_split_extension(path) ⇒ String

Splits the path into two parts: pre-extension, and extension, including the dot. File.amp_split_extension “/usr/bin/conf.ini” => [“conf”,“.ini”]

Parameters:

  • path (String)

    the path to the file to split up

Returns:

  • (String, String)

    the [filename pre extension, file extension] of the file provided.



537
538
539
540
541
# File 'lib/amp/support/support.rb', line 537

def self.amp_split_extension(path)
  ext  = File.extname  path
  base = File.basename path, ext
  [base, ext]
end

.copy(*args) ⇒ Object

This is in ftools in Ruby 1.8.x, but now it’s in FileUtils. So this is essentially an alias to it. Silly ftools, trix are for kids.



53
54
55
# File 'lib/amp/support/ruby_19_compatibility.rb', line 53

def self.copy(*args)
  FileUtils.copy(*args)
end

.makedirs(*args) ⇒ Object

This is in ftools in Ruby 1.8.x, but now it’s in FileUtils. So this is essentially an alias to it. Silly ftools, trix are for kids.



65
66
67
# File 'lib/amp/support/ruby_19_compatibility.rb', line 65

def self.makedirs(*args)
  FileUtils.makedirs(*args)
end

.move(*args) ⇒ Object

This is in ftools in Ruby 1.8.x, but now it’s in FileUtils. So this is essentially an alias to it. Silly ftools, trix are for kids.



59
60
61
# File 'lib/amp/support/ruby_19_compatibility.rb', line 59

def self.move(*args)
  FileUtils.move(*args)
end

.read(fileName) ⇒ Object

singleton method read does not exist in 1.6.x



29
30
31
# File 'lib/amp/dependencies/zip/stdrubyext.rb', line 29

def self.read(fileName)
  open(fileName) { |f| f.read }
end

Instance Method Details

#[](range) ⇒ String

Reads a range from the file.

Parameters:

  • range (Range)

    the byte indices to read between (and including)

Returns:

  • (String)

    the data read from the file



451
452
453
454
455
456
457
# File 'lib/amp/support/support.rb', line 451

def [](range)
  p = pos
  seek(range.first)
  val = read(range.last - range.first + 1)
  seek p
  val
end

#amp_each_chunk(num_bytes = 4.kb) {|the| ... } ⇒ Object

Reads n bytes at a time and yield them from the given file

Parameters:

  • num_bytes (Integer) (defaults to: 4.kb)

    the number of bytes to yield

Yields:

  • Yields a chunk that is at most num_bytes from the file until the file is exhausted. Poor file, it’s so tired.

Yield Parameters:

  • the (String)

    chunk from the file.



466
467
468
469
470
471
# File 'lib/amp/support/support.rb', line 466

def amp_each_chunk(num_bytes = 4.kb)
  buffer = nil
  while buffer = read(num_bytes)
    yield buffer
  end
end

#amp_lexist?(filename) ⇒ Boolean

Checks if a file exists, without following symlinks.

Parameters:

  • filename (String)

    the path to the file to check

Returns:

  • (Boolean)

    whether or not the file exists (ignoring symlinks)



318
319
320
# File 'lib/amp/support/support.rb', line 318

def amp_lexist?(filename)
  !!File.lstat(filename) rescue false
end