class Object
Constants
- COLOR_GREEN
- COLOR_RED
Public Instance Methods
absolute path
# File lib/central.rb, line 183 def abs(path) File.absolute_path(File.expand_path(path)) end
change current working directory
# File lib/central.rb, line 188 def chdir(dir) Dir.chdir(abs(dir)) end
function used to check that system has all required tools installed
# File lib/central.rb, line 161 def check_tool(name, check) _, output, = shell(check + ' 2>&1') if output == '' || output.downcase.include?('command not found') fail "#{name} not found, please install it to use central" end rescue Errno::ENOENT fail "#{name} not found, please install it to use central" end
change file permissions
# File lib/central.rb, line 309 def chmod(path, permissions, recursive: false) path = abs(path) recursive = recursive ? '-R ' : '' shell("chmod #{recursive}#{permissions} \"#{path}\"") end
putsc, puts with color
# File lib/central.rb, line 38 def color(message, color) if $colored "\e[#{color}m#{message}\e[0m" else message end end
# File lib/central.rb, line 449 def compare_file(from, to) from = abs(from) to = abs(to) FileUtils.compare_file(from, to) end
copy
# File lib/central.rb, line 468 def copy(from, to) from = abs(from) to = abs(to) if dir_exists?(from) dir_entries(from).each do |f| FileUtils.mkdir_p(to) copy("#{from}/#{f}", "#{to}/#{f}") end else copy_file(from, to) end end
# File lib/central.rb, line 456 def copy_file(from, to) from = abs(from) to = abs(to) fail "Couldn't access file", from unless file_exists?(from) return if file_exists?(to) && FileUtils.compare_file(from, to) FileUtils.copy_file(from, to) info 'Copied file', "#{from} → #{to}" end
download url into a path using curl
# File lib/central.rb, line 372 def curl(url, path, content_length_check: false, verbose: false) path = abs(path) if content_length_check and file_exists?(path) content_length = curl_headers(url, verbose: verbose)['content-length'].to_i return if file_size(path) == content_length end info 'Downloading', "#{url} → #{path}" exit_code, output, = shell("curl -s -S \"#{url}\"", verbose: verbose, silent: true) unless exit_code.success? error output fail "Couldn't download file from", url end File.write(path, output) info 'Downloaded', "#{url} → #{path}" end
get url response headers as Hash using curl
# File lib/central.rb, line 390 def curl_headers(url, method: 'HEAD', verbose: false) exit_code, output, = shell("curl -I -X #{method} -s -S \"#{url}\"", verbose: verbose, silent: true) unless exit_code.success? error output fail "Couldn't get headers from", url end headers = {} output.scan(/^(?!HTTP)([^:]+):(.*)$/).each do |m| headers[m[0].strip.downcase] = m[1].sub("\r","").strip end headers end
get directory entries
# File lib/central.rb, line 214 def dir_entries(path) Dir.entries(abs(path)).select { |f| f != '.' && f != '..' } end
check if directory exists
# File lib/central.rb, line 219 def dir_exists?(path) path = abs(path) Dir.exist?(path) end
process erb template into an output_file
# File lib/central.rb, line 502 def erb(file, output_file = nil, monitor = true) file = abs(file) fail 'No erb file found', file unless file_exists?(file) if output_file.nil? output_file = file.end_with?('.erb') ? file[0...-4] : file + '.out' end $monitors[file] = proc { erb(file, output_file, false) } if monitor out = ERB.new(File.read(file)).result return if File.exist?(output_file) && File.read(output_file) == out File.write(output_file, out) info 'Processed erb', "#{file} → #{output_file}" end
error
# File lib/central.rb, line 53 def error(message, param = nil) puts color(message, COLOR_RED) + (param.nil? ? '' : ': ' + param) end
fail, print message to stderr and exit with 1
# File lib/central.rb, line 59 def fail(message, param = nil) error message, param exit 1 end
get file creation time
# File lib/central.rb, line 204 def file_ctime(path) File.new(abs(path)).ctime end
get directory name of a path
# File lib/central.rb, line 237 def file_dir(path) File.dirname(abs(path)) end
check if file exists
# File lib/central.rb, line 193 def file_exists?(path) path = abs(path) File.file?(path) && File.readable?(path) end
get file modification time
# File lib/central.rb, line 209 def file_mtime(path) File.new(abs(path)).mtime end
get file name of a path, optionally strip suffix if needed
# File lib/central.rb, line 225 def file_name(path, strip_suffix: '') File.basename(abs(path), strip_suffix) end
get file size
# File lib/central.rb, line 199 def file_size(path) File.new(abs(path)).size end
get file suffix of a path
# File lib/central.rb, line 230 def file_suffix(path) path = file_name(path) suffix_index = path =~ /\.[^.]+$/ return path[suffix_index, path.size - suffix_index] if suffix_index end
# File lib/central.rb, line 94 def freebsd? os == 'freebsd' end
git clone url into a path
# File lib/central.rb, line 339 def git(url, path, branch: nil, silent: true, depth: nil) path = abs(path) if dir_exists?(path) && dir_exists?("#{path}/.git") cwd = pwd chdir path out = nil if branch _, out, = shell('git fetch 2>&1', silent: silent) puts out if silent && out.size.positive? _, out, = shell("git checkout #{branch} 2>&1", silent: silent) unless out.downcase.include? 'is now at' puts out if silent end _, out, = shell("git pull origin #{branch} 2>&1", silent: silent) else _, out, = shell('git pull 2>&1', silent: silent) end unless out.downcase.include? 'already up' puts out if silent info 'Git repository pulled', "#{url} → #{path}" end chdir cwd else branch = branch ? "-b #{branch} " : '' depth = depth ? "--depth #{depth} " : '' _, out, = shell("git clone #{depth}#{branch}#{url} \"#{path}\" 2>&1", silent: silent) puts out if silent info 'Git repository cloned', "#{url} → #{path}" end end
get hostname
# File lib/central.rb, line 65 def hostname Socket.gethostname end
info
# File lib/central.rb, line 47 def info(message, param = nil) puts color(message, COLOR_GREEN) + (param.nil? ? '' : ': ' + param) end
# File lib/central.rb, line 82 def linux? os == 'linux' end
list directory content
# File lib/central.rb, line 431 def ls(path, dotfiles: false, grep: '', dir: true, file: true) path = abs(path) dotfiles = dotfiles ? '-a ' : '' command = "ls -1 #{dotfiles}\"#{path}\" 2>&1" command += " | grep #{grep}" unless grep.empty? _, output, = shell(command) if output.downcase.end_with?('no such file or directory') fail "Couldn't ls directory", path end ls = output.split("\n") ls = ls.keep_if { |f| !File.directory?("#{path}/#{f}") } unless dir ls = ls.keep_if { |f| !File.file?("#{path}/#{f}") } unless file ls end
# File lib/central.rb, line 90 def macos? os == 'osx' end
mirror
# File lib/central.rb, line 482 def mirror(from, to) from = abs(from) to = abs(to) if dir_exists?(from) from_entries = dir_entries(from) if dir_exists?(to) dir_entries(to).each do |f| rm("#{to}/#{f}", recursive: true) unless from_entries.include?(f) end end from_entries.each do |f| FileUtils.mkdir_p(to) copy("#{from}/#{f}", "#{to}/#{f}") end else copy_file(from, to) end end
make directory including intermediate directories
# File lib/central.rb, line 258 def mkdir(path) path = abs(path) return if dir_exists?(path) exit_code, out, = shell("mkdir -p \"#{path}\" 2>&1") unless exit_code.success? error out fail "Couldn't create directory", path end info 'Created directory', path end
monitor file for changes and execute proc if file changed
# File lib/central.rb, line 520 def monitor(file, &block) file = abs(file) fail 'No file found', file unless file_exists?(file) $monitors[file] = block end
get option, returns Array if multiple or nil if none
# File lib/central.rb, line 18 def option(opt) options = $options.filter { |option| option.index(opt) == 0 } if options.size == 0 return nil elsif options.size == 1 return options[0] else return options end end
get operating system
# File lib/central.rb, line 70 def os if RUBY_PLATFORM.include?('linux') 'linux' elsif RUBY_PLATFORM.include?('darwin') 'osx' elsif RUBY_PLATFORM.include?('freebsd') 'freebsd' elsif RUBY_PLATFORM.include?('solaris') 'solaris' end end
# File lib/central.rb, line 86 def osx? os == 'osx' end
current working directory
# File lib/central.rb, line 178 def pwd Dir.pwd end
read content of a file
# File lib/central.rb, line 405 def read(file) file = abs(file) return File.read(file) if file_exists?(file) fail "Couldn't read file", file end
remove file/directory
# File lib/central.rb, line 271 def rm(path, recursive: false) path = abs(path) recursive = recursive ? '-R ' : '' is_dir = dir_exists?(path) is_symlink = symlink?(path) exit_code, out, = shell("rm #{recursive}-f \"#{path}\" 2>&1") unless exit_code.success? error out fail "Couldn't remove path", path end if is_dir info 'Removed directory', path elsif is_symlink info 'Removed symlink', path else info 'Removed file', path end end
remove directory recursively
# File lib/central.rb, line 291 def rmdir(path) rm(path, recursive: true) end
run configuration.rb file
# File lib/central.rb, line 528 def run(file) cwd = pwd file = abs(file) file = File.join(file,'configuration.rb') if not file_exists?(file) and dir_exists?(file) fail 'No configuration file found', file unless file_exists?(file) info 'Running configuration', file file_cwd = file_dir(file) chdir file_cwd load file chdir cwd end
run central configuration
# File lib/central.rb, line 547 def run_central(configurations, colored = true) $colored = colored if configurations.instance_of?(Array) && !configurations.empty? configurations.each { |configuration| run configuration } elsif configurations.instance_of?(String) run configurations else run 'configuration.rb' end end
run configuration.rb file only if it exists
# File lib/central.rb, line 542 def run_if_exists(file) run file if file_exists?(file) end
run monitors
# File lib/central.rb, line 559 def run_monitors info 'Monitoring files for changes (press Ctrl-C to stop)' file_mtimes = {} $monitors.keys.each { |f| file_mtimes[f] = File.mtime(f) } loop do $monitors.keys.each do |f| file_mtime = File.mtime(f) next if file_mtime == file_mtimes[f] info 'File modified', f $monitors[f].call file_mtimes[f] = file_mtime end begin sleep(0.5) rescue Interrupt exit 0 end end end
calculate SHA2 digest for a file
# File lib/central.rb, line 253 def sha2(file) Digest::SHA256.hexdigest read(file) end
run shell command and get output, optionaly can print command running if verbose and if not silent will also print to stdout and stderr
# File lib/central.rb, line 104 def shell(command, verbose: false, silent: true) info 'Executing', command if verbose exit_code = nil stdout = String.new stdout_line = String.new stderr = String.new stderr_line = String.new Open3.popen3(command) do |_, o, e, t| stdout_open = true stderr_open = true while stdout_open || stderr_open if stdout_open begin ch = o.read_nonblock(1) stdout += ch unless silent stdout_line += ch if ch == "\n" STDOUT.puts stdout_line stdout_line = '' end end rescue IO::WaitReadable IO.select([o], nil, nil, 0.01) unless stderr_open rescue EOFError stdout_open = false end end next unless stderr_open begin ch = e.read_nonblock(1) stderr += ch unless silent stderr_line += ch if ch == "\n" STDERR.puts stderr_line stderr_line = '' end end rescue IO::WaitReadable IO.select([e], nil, nil, 0.01) unless stdout_open rescue EOFError stderr_open = false end end exit_code = t.value end [exit_code, stdout, stderr] end
# File lib/central.rb, line 98 def solaris? os == 'solaris' end
source file in sh/bash/zsh script
# File lib/central.rb, line 419 def source(file, source) file = abs(file) source = abs(source) source_line = "source \"#{source}\"" _, out, = shell("grep -Fx '#{source_line}' \"#{file}\"") return unless out == '' shell("echo '#{source_line}' >> \"#{file}\"") info 'Added source', "#{source} line to #{file}" end
run shell command with sudo prefix, acts same as shell
# File lib/central.rb, line 156 def sudo(command, verbose:, silent:) shell('sudo ' + command, verbose: verbose, silent: silent) end
symlink path
# File lib/central.rb, line 316 def symlink(from, to) from = abs(from) to = abs(to) if symlink?(from) if symlink_path(from) != to rm from symlink from, to end elsif file_exists?(from) fail "File #{from} exists in place of symlink..." elsif dir_exists?(from) fail "Directory #{from} exists in place of symlink..." else exit_code, out, = shell("ln -s \"#{to}\" \"#{from}\" 2>&1") unless exit_code.success? error out fail "Couldn't create symlink", "#{from} → #{to}" end info 'Created symlink', "#{from} → #{to}" end end
check if file is symlink
# File lib/central.rb, line 242 def symlink?(symlink) File.symlink?(abs(symlink)) end
get full path of symlink
# File lib/central.rb, line 247 def symlink_path(symlink) _, out, = shell("readlink \"#{abs(symlink)}\" 2>&1") out.strip end
touch file
# File lib/central.rb, line 296 def touch(path) path = abs(path) return if file_exists?(path) exit_code, out, = shell("touch \"#{path}\" 2>&1") unless exit_code.success? error out fail "Couldn't touch file", path end info 'Touched file', path end
write content into a file
# File lib/central.rb, line 413 def write(file, content) file = abs(file) File.write(file, content) end