module FPM::Util
Some utility functions
Public Instance Methods
copied_entries()
click to toggle source
# File lib/fpm/util.rb, line 205 def copied_entries # TODO(sissel): I wonder that this entry-copy knowledge needs to be put # into a separate class/module. As is, calling copy_entry the same way # in slightly different contexts will result in weird or bad behavior. # What I mean is if we do: # pkg = FPM::Package::Dir... # pkg.output()... # pkg.output()... # The 2nd output call will fail or behave weirdly because @copied_entries # is already populated. even though this is anew round of copying. return @copied_entries ||= {} end
copy_entry(src, dst, preserve=false, remove_destination=false)
click to toggle source
# File lib/fpm/util.rb, line 182 def copy_entry(src, dst, preserve=false, remove_destination=false) case File.ftype(src) when 'fifo', 'characterSpecial', 'blockSpecial', 'socket' st = File.stat(src) rc = mknod_w(dst, st.mode, st.dev) raise SystemCallError.new("mknod error", FFI.errno) if rc == -1 when 'directory' FileUtils.mkdir(dst) unless File.exists? dst else # if the file with the same dev and inode has been copied already - # hard link it's copy to `dst`, otherwise make an actual copy st = File.lstat(src) known_entry = copied_entries[[st.dev, st.ino]] if known_entry FileUtils.ln(known_entry, dst) else FileUtils.copy_entry(src, dst, preserve=preserve, remove_destination=remove_destination) copied_entries[[st.dev, st.ino]] = dst end end # else... end
copy_metadata(source, destination)
click to toggle source
# File lib/fpm/util.rb, line 159 def copy_metadata(source, destination) source_stat = File::lstat(source) dest_stat = File::lstat(destination) # If this is a hard-link, there's no metadata to copy. # If this is a symlink, what it points to hasn't been copied yet. return if source_stat.ino == dest_stat.ino || dest_stat.symlink? File.utime(source_stat.atime, source_stat.mtime, destination) mode = source_stat.mode begin File.lchown(source_stat.uid, source_stat.gid, destination) rescue Errno::EPERM # clear setuid/setgid mode &= 01777 end unless source_stat.symlink? File.chmod(mode, destination) end end
default_shell()
click to toggle source
# File lib/fpm/util.rb, line 42 def default_shell shell = ENV["SHELL"] return "/bin/sh" if shell.nil? || shell.empty? return shell end
expand_pessimistic_constraints(constraint)
click to toggle source
# File lib/fpm/util.rb, line 218 def expand_pessimistic_constraints(constraint) name, op, version = constraint.split(/\s+/) if op == '~>' new_lower_constraint = "#{name} >= #{version}" version_components = version.split('.').collect { |v| v.to_i } version_prefix = version_components[0..-3].join('.') portion_to_work_with = version_components.last(2) prefix = '' unless version_prefix.empty? prefix = version_prefix + '.' end one_to_increment = portion_to_work_with[0].to_i incremented = one_to_increment + 1 new_version = ''+ incremented.to_s + '.0' upper_version = prefix + new_version new_upper_constraint = "#{name} < #{upper_version}" return [new_lower_constraint,new_upper_constraint] else return [constraint] end end
logger()
click to toggle source
# File lib/fpm/util.rb, line 250 def logger @logger ||= Cabin::Channel.get end
mknod_w(path, mode, dev)
click to toggle source
wrapper around mknod ffi calls
# File lib/fpm/util.rb, line 147 def mknod_w(path, mode, dev) rc = -1 case %x{uname -s}.chomp when 'Linux' # bits/stat.h #define _MKNOD_VER_LINUX 0 rc = xmknod(0, path, mode, FFI::MemoryPointer.new(dev)) else rc = mknod(path, mode, dev) end rc end
program_exists?(program)
click to toggle source
# File lib/fpm/util.rb, line 35 def program_exists?(program) # Scan path to find the executable # Do this to help the user get a better error message. return program_in_path?(program) if !program.include?("/") return File.executable?(program) end
program_in_path?(program)
click to toggle source
Is the given program in the system's PATH?
# File lib/fpm/util.rb, line 26 def program_in_path?(program) # return false if path is not set return false unless ENV['PATH'] # Scan path to find the executable # Do this to help the user get a better error message. envpath = ENV["PATH"].split(":") return envpath.select { |p| File.executable?(File.join(p, program)) }.any? end
safesystem(*args)
click to toggle source
Run a command safely in a way that gets reports useful errors.
# File lib/fpm/util.rb, line 49 def safesystem(*args) # ChildProcess isn't smart enough to run a $SHELL if there's # spaces in the first arg and there's only 1 arg. if args.size == 1 args = [ default_shell, "-c", args[0] ] end program = args[0] if !program_exists?(program) raise ExecutableNotFound.new(program) end logger.debug("Running command", :args => args) # Create a pair of pipes to connect the # invoked process to the cabin logger stdout_r, stdout_w = IO.pipe stderr_r, stderr_w = IO.pipe process = ChildProcess.build(*args) process.io.stdout = stdout_w process.io.stderr = stderr_w process.start stdout_w.close; stderr_w.close logger.debug('Process is running', :pid => process.pid) # Log both stdout and stderr as 'info' because nobody uses stderr for # actually reporting errors and as a result 'stderr' is a misnomer. logger.pipe(stdout_r => :info, stderr_r => :info) process.wait success = (process.exit_code == 0) if !success raise ProcessFailed.new("#{program} failed (exit code #{process.exit_code})" \ ". Full command was:#{args.inspect}") end return success end
safesystemout(*args)
click to toggle source
Run a command safely in a way that captures output and status.
# File lib/fpm/util.rb, line 90 def safesystemout(*args) if args.size == 1 args = [ ENV["SHELL"], "-c", args[0] ] end program = args[0] if !program.include?("/") and !program_in_path?(program) raise ExecutableNotFound.new(program) end logger.debug("Running command", :args => args) stdout_r, stdout_w = IO.pipe stderr_r, stderr_w = IO.pipe process = ChildProcess.build(*args) process.io.stdout = stdout_w process.io.stderr = stderr_w process.start stdout_w.close; stderr_w.close stdout_r_str = stdout_r.read stdout_r.close; stderr_r.close logger.debug("Process is running", :pid => process.pid) process.wait success = (process.exit_code == 0) if !success raise ProcessFailed.new("#{program} failed (exit code #{process.exit_code})" \ ". Full command was:#{args.inspect}") end return stdout_r_str end
tar_cmd()
click to toggle source
Get the recommended 'tar' command for this platform.
# File lib/fpm/util.rb, line 127 def tar_cmd # Rely on gnu tar for solaris and OSX. case %x{uname -s}.chomp when "SunOS" return "gtar" when "Darwin" # Try running gnutar, it was renamed(??) in homebrew to 'gtar' at some point, I guess? I don't know. ["gnutar", "gtar"].each do |tar| system("#{tar} > /dev/null 2> /dev/null") return tar unless $?.exitstatus == 127 end when "FreeBSD" # use gnutar instead return "gtar" else return "tar" end end