Module: Sinew::Util

Extended by:
Util
Included in:
Util
Defined in:
lib/sinew/util.rb

Overview

Helper module for executing commands and printing stuff out.

The general idea is to only print commands that are actually interesting. For example, mkdir_if_necessary won’t print anything if the directory already exists. That way we can scan output and see what changes were made without getting lost in repetitive commands that had no actual effect.

Defined Under Namespace

Classes: RunError

Constant Summary collapse

RESET =
"\e[0m"
RED =
"\e[1;37;41m"
GREEN =
"\e[1;37;42m"
YELLOW =
"\e[1;37;43m"
BLUE =
"\e[1;37;44m"
MAGENTA =
"\e[1;37;45m"
CYAN =
"\e[1;37;46m"

Instance Method Summary collapse

Instance Method Details

A nice printout in green.



183
184
185
186
187
# File 'lib/sinew/util.rb', line 183

def banner(s, color = GREEN)
  s = "#{s} ".ljust(72, " ")      
  $stderr.write "#{color}[#{Time.new.strftime('%H:%M:%S')}] #{s}#{RESET}\n"
  $stderr.flush
end

#chmod(file, mode) ⇒ Object

Chmod file to a new mode.



137
138
139
140
141
# File 'lib/sinew/util.rb', line 137

def chmod(file, mode)
  if File.stat(file).mode != mode
    FileUtils.chmod(mode, file, :verbose => verbose?)      
  end
end

#chown(file, user) ⇒ Object

Chown file to be owned by user.



125
126
127
128
129
130
131
132
133
134
# File 'lib/sinew/util.rb', line 125

def chown(file, user)
  user = user.to_s
  # who is the current owner?
  @uids ||= {}
  @uids[user] ||= Etc.getpwnam(user).uid
  uid = @uids[user]
  if File.stat(file).uid != uid
    run "chown #{user}:#{user} '#{file}'"        
  end
end

#cp(src, dst, owner = nil, mode = nil) ⇒ Object

Copy file or dir from src to dst. Optionally, set the mode and owner of dst.



84
85
86
87
88
89
90
91
92
# File 'lib/sinew/util.rb', line 84

def cp(src, dst, owner = nil, mode = nil)
  FileUtils.cp_r(src, dst, :preserve => true, :verbose => verbose?)
  if owner && !File.symlink?(dst)      
    chown(dst, owner) 
  end
  if mode
    chmod(dst, mode)
  end
end

#cp_if_necessary(src, dst, owner = nil, mode = nil) ⇒ Object

Copy file or dir from src to dst, but ONLY if dst doesn’t exist or has different contents than src. Optionally, set the mode and owner of dst.



104
105
106
107
108
109
# File 'lib/sinew/util.rb', line 104

def cp_if_necessary(src, dst, owner = nil, mode = nil)
  if !File.exists?(dst) || different?(src, dst)
    cp(src, dst, owner, mode)
    true
  end
end

#cp_with_mkdir(src, dst, owner = nil, mode = nil) ⇒ Object

Copy file or dir from src to dst, but create the dst directory first if necessary. Optionally, set the mode and owner of dst.



96
97
98
99
# File 'lib/sinew/util.rb', line 96

def cp_with_mkdir(src, dst, owner = nil, mode = nil)
  mkdir_if_necessary(File.dirname(dst))
  cp(src, dst, owner, mode)
end

#different?(a, b) ⇒ Boolean

Are two files different?

Returns:

  • (Boolean)


78
79
80
# File 'lib/sinew/util.rb', line 78

def different?(a, b)
  !FileUtils.compare_file(a, b)
end

#fatal(msg) ⇒ Object

Print a fatal error in red, then exit.



195
196
197
198
# File 'lib/sinew/util.rb', line 195

def fatal(msg)
  banner(msg, RED)
  exit(1)
end

#ln(src, dst) ⇒ Object

Create a symlink from src to dst.



157
158
159
# File 'lib/sinew/util.rb', line 157

def ln(src, dst)
  FileUtils.ln_sf(src, dst, :verbose => verbose?)
end

#ln_if_necessary(src, dst) ⇒ Object

Create a symlink from src to dst, but only if it hasn’t already been created.



163
164
165
166
167
168
169
170
171
172
173
174
175
# File 'lib/sinew/util.rb', line 163

def ln_if_necessary(src, dst)
  ln = false
  if !File.symlink?(dst)
    ln = true
  elsif File.readlink(dst) != src
    rm(dst)
    ln = true
  end
  if ln
    ln(src, dst)
    true
  end
end

#md5(s) ⇒ Object

checksum some text



221
222
223
# File 'lib/sinew/util.rb', line 221

def md5(s)
  Digest::MD5.hexdigest(s.to_s)
end

#mkdir(dir, owner = nil, mode = nil) ⇒ Object

Like mkdir -p. Optionally, set the owner and mode.



59
60
61
62
63
# File 'lib/sinew/util.rb', line 59

def mkdir(dir, owner = nil, mode = nil)
  FileUtils.mkdir_p(dir, :verbose => verbose?)
  chmod(dir, mode) if mode
  chown(dir, owner) if owner
end

#mkdir_if_necessary(dir, owner = nil, mode = nil) ⇒ Object

mkdir only if the directory doesn’t already exist. Optionally, set the owner and mode.



67
68
69
# File 'lib/sinew/util.rb', line 67

def mkdir_if_necessary(dir, owner = nil, mode = nil)
  mkdir(dir, owner, mode) if !(File.exists?(dir) || File.symlink?(dir))
end

#mv(src, dst) ⇒ Object

Move src to dst. Because this uses FileUtils, it works even if dst is on a different partition.



113
114
115
# File 'lib/sinew/util.rb', line 113

def mv(src, dst)
  FileUtils.mv(src, dst, :verbose => verbose?)
end

#mv_with_mkdir(src, dst) ⇒ Object

Move src to dst, but create the dst directory first if necessary.



119
120
121
122
# File 'lib/sinew/util.rb', line 119

def mv_with_mkdir(src, dst)
  mkdir_if_necessary(File.dirname(dst))
  mv(src, dst)
end

#pathify(s) ⇒ Object

Convert a string into something that could be a path segment



207
208
209
210
211
212
213
214
215
216
217
218
# File 'lib/sinew/util.rb', line 207

def pathify(s)
  s = s.gsub(/^\//, "")
  s = s.gsub("..", ",")
  s = s.gsub(/[?\/&]/, ",")
  s = s.gsub(/[^A-Za-z0-9_.,=-]/) do |i|
    hex = i.unpack("H2").first
    "%#{hex}"
  end
  s = "_root_" if s.empty?
  s = s.downcase
  s
end

#random_text(len) ⇒ Object

Generate some random text



201
202
203
204
# File 'lib/sinew/util.rb', line 201

def random_text(len)
  chars = ("A".."Z").to_a + ("a".."z").to_a + ("0".."9").to_a
  (1..len).map { chars[rand(chars.length - 1)] }.join("")
end

#rm(file) ⇒ Object

rm a file



144
145
146
# File 'lib/sinew/util.rb', line 144

def rm(file)
  FileUtils.rm(file, :force => true, :verbose => verbose?)
end

#rm_and_mkdir(dir) ⇒ Object

rm a dir and recreate it.



72
73
74
75
# File 'lib/sinew/util.rb', line 72

def rm_and_mkdir(dir)
  raise "don't do this" if dir == ""
  run "rm -rf #{dir} && mkdir -p #{dir}"
end

#rm_if_necessary(file) ⇒ Object

rm a file, but only if it exists.



149
150
151
152
153
154
# File 'lib/sinew/util.rb', line 149

def rm_if_necessary(file)
  if File.exists?(file)
    rm(file)
    true
  end
end

#run(command, args = nil) ⇒ Object

Run a command, raise an error upon failure. Output goes to $stdout/$stderr.



38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
# File 'lib/sinew/util.rb', line 38

def run(command, args = nil)
  line = nil
  if args
    args = args.map(&:to_s)
    line = "#{command} #{args.join(" ")}"
    vputs line
    system(command, *args)
  else
    line = command
    vputs line
    system(command)
  end
  if $? != 0
    if $?.termsig == Signal.list["INT"]
      raise "#{line} interrupted"
    end
    raise RunError, "#{line} failed : #{$?.to_i / 256}"
  end
end

#run_verbose!Object

Make all commands echo before running.



32
33
34
# File 'lib/sinew/util.rb', line 32

def run_verbose!
  @run_verbose = true
end

#touch(file) ⇒ Object

Touch a file



178
179
180
# File 'lib/sinew/util.rb', line 178

def touch(file)
  FileUtils.touch(file)      
end

#warning(msg) ⇒ Object

Print a warning in yellow.



190
191
192
# File 'lib/sinew/util.rb', line 190

def warning(msg)
  banner("Warning: #{msg}", YELLOW)
end