Module: FalkorLib::Common Abstract
- Included in:
- FalkorLib::CLI::App, FalkorLib::CLI::Link, FalkorLib::CLI::Make
- Defined in:
- lib/falkorlib/common.rb
Overview
Recipe for all my toolbox and versatile Ruby functions I’m using everywhere. You’ll typically want to include the ‘FalkorLib::Common` module to bring the corresponding definitions into yoru scope.
@example:
require 'falkorlib'
include FalkorLib::Common
info 'exemple of information text'
really_continue?
run %{ echo 'this is an executed command' }
Falkor.config.debug = true
run %{ echo 'this is a simulated command that *will not* be executed' }
error "that's an error text, let's exit with status code 1"
Class Method Summary collapse
-
.ask(question, default_answer = '') ⇒ Object
Ask a question.
-
.bold(str) ⇒ Object
Default printing functions ###.
-
.command?(name) ⇒ Boolean
Check for the presence of a given command.
-
.cyan(str) ⇒ Object
Print a text in cyan.
-
.error(str) ⇒ Object
Print an error message and abort.
-
.exec_or_exit(cmd) ⇒ Object
Execute a given command - exit if status != 0.
-
.execute(cmd) ⇒ Object
Simpler version that use the system call.
-
.execute_in_dir(path, cmd) ⇒ Object
Execute in a given directory.
-
.green(str) ⇒ Object
Print a text in green.
-
.info(str) ⇒ Object
Print an info message.
-
.init_from_template(templatedir, rootdir, config = {}, options = { :erb_exclude => [], :no_interaction => false }) ⇒ Object
Bootstrap the destination directory ‘rootdir` using the template directory `templatedir`.
-
.init_rvm(rootdir = Dir.pwd, gemset = '') ⇒ Object
RVM init.
-
.list_items(glob_pattern, options = {}) ⇒ Object
List items from a glob pattern to ask for a unique choice Supported options: :only_files [boolean]: list only files in the glob :only_dirs [boolean]: list only directories in the glob :pattern_include [array of strings]: pattern(s) to include for listing :pattern_exclude [array of strings]: pattern(s) to exclude for listing :text [string]: text to put.
-
.load_config(file) ⇒ Object
Return the yaml content as a Hash object.
-
.nice_execute(cmd) ⇒ Object
Execute a given command, return exit code and print nicely stdout and stderr.
-
.normalized_path(dir = Dir.pwd, options = {}) ⇒ Object
normalize_path ###### Normalize a path and return the absolute path foreseen Ex: ‘.’ return Dir.pwd Supported options: * :relative [boolean] return relative path to the root dir.
-
.not_implemented ⇒ Object
simple helper text to mention a non-implemented feature.
-
.really_continue?(default_answer = 'Yes') ⇒ Boolean
Ask whether or not to really continue.
-
.red(str) ⇒ Object
Print a text in red.
-
.run(cmds) ⇒ Object
“Nice” way to present run commands Ex: run %{ hostname -f }.
-
.select_from(list, text = 'Select the index', default_idx = 0, raw_list = list) ⇒ Object
Display a indexed list to select an i.
-
.select_multiple_from(list, text = 'Select the index', default_idx = 1, raw_list = list) ⇒ Object
Display a indexed list to select multiple indexes.
-
.show_diff_and_write(content, outfile, options = { :no_interaction => false, :json_pretty_format => false, :no_commit => false }) ⇒ Object
Show the difference between a ‘content` string and an destination file (using Diff algorithm).
-
.store_config(filepath, hash, options = {}) ⇒ Object
Store the Hash object as a Yaml file Supported options: :header [string]: additional info to place in the header of the (stored) file :no_interaction [boolean]: do not interact.
-
.warning(str) ⇒ Object
Print an warning message.
-
.write_from_erb_template(erbfile, outfile, config = {}, options = { :no_interaction => false }) ⇒ Object
ERB generation of the file ‘outfile` using the source template file `erbfile` Supported options: :no_interaction [boolean]: do not interact :srcdir [string]: source dir for all considered ERB files.
-
.write_from_template(src, dstdir, options = { :no_interaction => false, :no_commit => false, :srcdir => '', :outfile => '' }) ⇒ Object
Blind copy of a source file ‘src` into its destination directory `dstdir` Supported options: :no_interaction [boolean]: do not interact :srcdir [string]: source directory, make the `src` file relative to that directory :outfile [string]: alter the outfile name (File.basename(src) by default) :no_commit [boolean]: do not (offer to) commit the changes.
Class Method Details
.ask(question, default_answer = '') ⇒ Object
Ask a question
88 89 90 91 92 93 94 95 96 |
# File 'lib/falkorlib/common.rb', line 88 def ask(question, default_answer = '') return default_answer if FalkorLib.config[:no_interaction] print "#{question} " print "[Default: #{default_answer}]" unless default_answer == '' print ": " STDOUT.flush answer = STDIN.gets.chomp (answer.empty?) ? default_answer : answer end |
.bold(str) ⇒ Object
Default printing functions ###
Print a text in bold
41 42 43 |
# File 'lib/falkorlib/common.rb', line 41 def bold(str) (COLOR == true) ? Term::ANSIColor.bold(str) : str end |
.command?(name) ⇒ Boolean
Check for the presence of a given command
111 112 113 114 |
# File 'lib/falkorlib/common.rb', line 111 def command?(name) `which #{name}` $?.success? end |
.cyan(str) ⇒ Object
Print a text in cyan
56 57 58 |
# File 'lib/falkorlib/common.rb', line 56 def cyan(str) (COLOR == true) ? Term::ANSIColor.cyan(str) : str end |
.error(str) ⇒ Object
Print an error message and abort
72 73 74 75 76 |
# File 'lib/falkorlib/common.rb', line 72 def error(str) #abort red("*** ERROR *** " + str) $stderr.puts red("*** ERROR *** " + str) exit 1 end |
.exec_or_exit(cmd) ⇒ Object
Execute a given command - exit if status != 0
152 153 154 155 156 157 158 |
# File 'lib/falkorlib/common.rb', line 152 def exec_or_exit(cmd) status = execute(cmd) if (status.to_i.nonzero?) error("The command '#{cmd}' failed with exit status #{status.to_i}") end status end |
.execute(cmd) ⇒ Object
Simpler version that use the system call
136 137 138 139 140 |
# File 'lib/falkorlib/common.rb', line 136 def execute(cmd) puts bold("[Running] #{cmd.gsub(/^\s*/, ' ')}") system(cmd) $?.exitstatus end |
.execute_in_dir(path, cmd) ⇒ Object
Execute in a given directory
143 144 145 146 147 148 149 |
# File 'lib/falkorlib/common.rb', line 143 def execute_in_dir(path, cmd) exit_status = 0 Dir.chdir(path) do exit_status = run %( #{cmd} ) end exit_status end |
.green(str) ⇒ Object
Print a text in green
46 47 48 |
# File 'lib/falkorlib/common.rb', line 46 def green(str) (COLOR == true) ? Term::ANSIColor.green(str) : str end |
.info(str) ⇒ Object
Print an info message
61 62 63 |
# File 'lib/falkorlib/common.rb', line 61 def info(str) puts green("[INFO] " + str) end |
.init_from_template(templatedir, rootdir, config = {}, options = { :erb_exclude => [], :no_interaction => false }) ⇒ Object
Bootstrap the destination directory ‘rootdir` using the template directory `templatedir`. the hash table `config` hosts the elements to feed ERB files which should have the extension .erb. The initialization is performed as follows:
-
a rsync process is initiated to duplicate the directory structure and the symlinks, and exclude .erb files
-
each erb files (thus with extension .erb) is interpreted, the corresponding file is generated without the .erb extension
Supported options:
:erb_exclude [array of strings]: pattern(s) to exclude from erb file
interpretation and thus to copy 'as is'
:no_interaction [boolean]: do not interact
325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 |
# File 'lib/falkorlib/common.rb', line 325 def init_from_template(templatedir, rootdir, config = {}, = { :erb_exclude => [], :no_interaction => false }) error "Unable to find the template directory" unless File.directory?(templatedir) warning "about to initialize/update the directory #{rootdir}" really_continue? unless [:no_interaction] run %( mkdir -p #{rootdir} ) unless File.directory?( rootdir ) run %( rsync --exclude '*.erb' --exclude '.texinfo*' -avzu #{templatedir}/ #{rootdir}/ ) Dir["#{templatedir}/**/*.erb"].each do |erbfile| relative_outdir = Pathname.new( File.realpath( File.dirname(erbfile) )).relative_path_from Pathname.new(templatedir) filename = File.basename(erbfile, '.erb') outdir = File.realpath( File.join(rootdir, relative_outdir.to_s) ) outfile = File.join(outdir, filename) unless [:erb_exclude].nil? exclude_entry = false [:erb_exclude].each do |pattern| exclude_entry |= erbfile =~ /#{pattern}/ end if exclude_entry info "copying non-interpreted ERB file" # copy this file since it has been probably excluded from teh rsync process run %( cp #{erbfile} #{outdir}/ ) next end end # Let's go info "updating '#{relative_outdir}/#{filename}'" puts " using ERB template '#{erbfile}'" write_from_erb_template(erbfile, outfile, config, ) end end |
.init_rvm(rootdir = Dir.pwd, gemset = '') ⇒ Object
RVM init
453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 |
# File 'lib/falkorlib/common.rb', line 453 def init_rvm(rootdir = Dir.pwd, gemset = '') rvm_files = { :version => File.join(rootdir, '.ruby-version'), :gemset => File.join(rootdir, '.ruby-gemset') } unless File.exist?( (rvm_files[:version]).to_s) v = select_from(FalkorLib.config[:rvm][:rubies], "Select RVM ruby to configure for this directory", 3) File.open( rvm_files[:version], 'w') do |f| f.puts v end end unless File.exist?( (rvm_files[:gemset]).to_s) g = (gemset.empty?) ? ask("Enter RVM gemset name for this directory", File.basename(rootdir)) : gemset File.open( rvm_files[:gemset], 'w') do |f| f.puts g end end end |
.list_items(glob_pattern, options = {}) ⇒ Object
List items from a glob pattern to ask for a unique choice Supported options:
:only_files [boolean]: list only files in the glob
:only_dirs [boolean]: list only directories in the glob
:pattern_include [array of strings]: pattern(s) to include for listing
:pattern_exclude [array of strings]: pattern(s) to exclude for listing
:text [string]: text to put
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 216 217 218 219 220 221 222 223 224 |
# File 'lib/falkorlib/common.rb', line 182 def list_items(glob_pattern, = {}) list = { 0 => 'Exit' } index = 1 raw_list = { 0 => 'Exit' } Dir[glob_pattern.to_s].each do |elem| #puts "=> element '#{elem}' - dir = #{File.directory?(elem)}; file = #{File.file?(elem)}" next if (![:only_files].nil?) && [:only_files] && File.directory?(elem) next if (![:only_dirs].nil?) && [:only_dirs] && File.file?(elem) entry = File.basename(elem) # unless options[:pattern_include].nil? # select_entry = false # options[:pattern_include].each do |pattern| # #puts "considering pattern '#{pattern}' on entry '#{entry}'" # select_entry |= entry =~ /#{pattern}/ # end # next unless select_entry # end unless [:pattern_exclude].nil? select_entry = false [:pattern_exclude].each do |pattern| #puts "considering pattern '#{pattern}' on entry '#{entry}'" select_entry |= entry =~ /#{pattern}/ end next if select_entry end #puts "selected entry = '#{entry}'" list[index] = entry raw_list[index] = elem index += 1 end text = ([:text].nil?) ? "select the index" : [:text] default_idx = ([:default].nil?) ? 0 : [:default] raise SystemExit, 'Empty list' if index == 1 #ap list #ap raw_list # puts list.to_yaml # answer = ask("=> #{text}", "#{default_idx}") # raise SystemExit.new('exiting selection') if answer == '0' # raise RangeError.new('Undefined index') if Integer(answer) >= list.length # raw_list[Integer(answer)] select_from(list, text, default_idx, raw_list) end |
.load_config(file) ⇒ Object
Return the yaml content as a Hash object
274 275 276 277 278 279 280 281 282 283 |
# File 'lib/falkorlib/common.rb', line 274 def load_config(file) unless File.exist?(file) raise FalkorLib::Error, "Unable to find the YAML file '#{file}'" end loaded = YAML.load_file(file) unless loaded.is_a?(Hash) raise FalkorLib::Error, "Corrupted or invalid YAML file '#{file}'" end loaded end |
.nice_execute(cmd) ⇒ Object
Execute a given command, return exit code and print nicely stdout and stderr
117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 |
# File 'lib/falkorlib/common.rb', line 117 def nice_execute(cmd) puts bold("[Running] #{cmd.gsub(/^\s*/, ' ')}") stdout, stderr, exit_status = Open3.capture3( cmd ) unless stdout.empty? stdout.each_line do |line| print "** [out] #{line}" $stdout.flush end end unless stderr.empty? stderr.each_line do |line| $stderr.print red("** [err] #{line}") $stderr.flush end end exit_status end |
.normalized_path(dir = Dir.pwd, options = {}) ⇒ Object
normalize_path ###### Normalize a path and return the absolute path foreseen Ex: ‘.’ return Dir.pwd Supported options:
* :relative [boolean] return relative path to the root dir
480 481 482 483 484 485 486 487 488 489 490 491 |
# File 'lib/falkorlib/common.rb', line 480 def normalized_path(dir = Dir.pwd, = {}) rootdir = (FalkorLib::Git.init?(dir)) ? FalkorLib::Git.rootdir(dir) : dir path = dir path = Dir.pwd if dir == '.' path = File.join(Dir.pwd, dir) unless (dir =~ /^\// || (dir == '.')) if ([:relative] || [:relative_to]) root = ([:relative_to]) ? [:relative_to] : rootdir relative_path_to_root = Pathname.new( File.realpath(path) ).relative_path_from Pathname.new(root) path = relative_path_to_root.to_s end path end |
.not_implemented ⇒ Object
simple helper text to mention a non-implemented feature
79 80 81 |
# File 'lib/falkorlib/common.rb', line 79 def not_implemented error("NOT YET IMPLEMENTED") end |
.really_continue?(default_answer = 'Yes') ⇒ Boolean
Ask whether or not to really continue
99 100 101 102 103 104 |
# File 'lib/falkorlib/common.rb', line 99 def really_continue?(default_answer = 'Yes') return if FalkorLib.config[:no_interaction] pattern = (default_answer =~ /yes/i) ? '(Y|n)' : '(y|N)' answer = ask( cyan("=> Do you really want to continue #{pattern}?"), default_answer) exit 0 if answer =~ /n.*/i end |
.red(str) ⇒ Object
Print a text in red
51 52 53 |
# File 'lib/falkorlib/common.rb', line 51 def red(str) (COLOR == true) ? Term::ANSIColor.red(str) : str end |
.run(cmds) ⇒ Object
“Nice” way to present run commands Ex: run %{ hostname -f }
162 163 164 165 166 167 168 169 170 171 172 173 |
# File 'lib/falkorlib/common.rb', line 162 def run(cmds) exit_status = 0 puts bold("[Running]\n#{cmds.gsub(/^\s*/, ' ')}") $stdout.flush #puts cmds.split(/\n */).inspect cmds.split(/\n */).each do |cmd| next if cmd.empty? system(cmd.to_s) unless FalkorLib.config.debug exit_status = $?.exitstatus end exit_status end |
.select_from(list, text = 'Select the index', default_idx = 0, raw_list = list) ⇒ Object
Display a indexed list to select an i
227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 |
# File 'lib/falkorlib/common.rb', line 227 def select_from(list, text = 'Select the index', default_idx = 0, raw_list = list) error "list and raw_list differs in size" if list.size != raw_list.size l = list raw_l = raw_list if list.is_a?(Array) l = raw_l = { 0 => 'Exit' } list.each_with_index do |e, idx| l[idx + 1] = e raw_l[idx + 1] = raw_list[idx] end end puts l.to_yaml answer = ask("=> #{text}", default_idx.to_s) raise SystemExit, 'exiting selection' if answer == '0' raise RangeError, 'Undefined index' if Integer(answer) >= l.length raw_l[Integer(answer)] end |
.select_multiple_from(list, text = 'Select the index', default_idx = 1, raw_list = list) ⇒ Object
Display a indexed list to select multiple indexes
246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 |
# File 'lib/falkorlib/common.rb', line 246 def select_multiple_from(list, text = 'Select the index', default_idx = 1, raw_list = list) error "list and raw_list differs in size" if list.size != raw_list.size l = list raw_l = raw_list if list.is_a?(Array) l = raw_l = { 0 => 'Exit', 1 => 'End of selection' } list.each_with_index do |e, idx| l[idx + 2] = e raw_l[idx + 2] = raw_list[idx] end end puts l.to_yaml choices = Array.new answer = 0 begin choices.push(raw_l[Integer(answer)]) if Integer(answer) > 1 answer = ask("=> #{text}", default_idx.to_s) raise SystemExit, 'exiting selection' if answer == '0' raise RangeError, 'Undefined index' if Integer(answer) >= l.length end while Integer(answer) != 1 choices end |
.show_diff_and_write(content, outfile, options = { :no_interaction => false, :json_pretty_format => false, :no_commit => false }) ⇒ Object
Show the difference between a ‘content` string and an destination file (using Diff algorithm). Obviosuly, if the outfile does not exists, no difference is proposed. Supported options:
:no_interaction [boolean]: do not interact
:json_pretty_format [boolean]: write a json content, in pretty format
:no_commit [boolean]: do not (offer to) commit the changes
return 0 if nothing happened, 1 if a write has been done
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 424 425 426 427 |
# File 'lib/falkorlib/common.rb', line 394 def show_diff_and_write(content, outfile, = { :no_interaction => false, :json_pretty_format => false, :no_commit => false }) if File.exist?( outfile ) ref = File.read( outfile ) if [:json_pretty_format] ref = JSON.pretty_generate(JSON.parse( IO.read( outfile ) )) end if ref == content warn "Nothing to update" return 0 end warn "the file '#{outfile}' already exists and will be overwritten." warn "Expected difference: \n------" Diffy::Diff.default_format = :color puts Diffy::Diff.new(ref, content, :context => 1) else watch = ([:no_interaction]) ? 'no' : ask( cyan(" ==> Do you want to see the generated file before commiting the writing (y|N)"), 'No') puts content if watch =~ /y.*/i end proceed = ([:no_interaction]) ? 'yes' : ask( cyan(" ==> proceed with the writing (Y|n)"), 'Yes') return 0 if proceed =~ /n.*/i info("=> writing #{outfile}") File.open(outfile.to_s, "w+") do |f| f.write content end if FalkorLib::Git.init?(File.dirname(outfile)) && ![:no_commit] do_commit = ([:no_interaction]) ? 'yes' : ask( cyan(" ==> commit the changes (Y|n)"), 'Yes') FalkorLib::Git.add(outfile, "update content of '#{File.basename(outfile)}'") if do_commit =~ /y.*/i end 1 end |
.store_config(filepath, hash, options = {}) ⇒ Object
Store the Hash object as a Yaml file Supported options:
:header [string]: additional info to place in the header of the (stored) file
:no_interaction [boolean]: do not interact
289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 |
# File 'lib/falkorlib/common.rb', line 289 def store_config(filepath, hash, = {}) content = "# " + File.basename(filepath) + "\n" content += "# /!\\ DO NOT EDIT THIS FILE: it has been automatically generated\n" if [:header] [:header].split("\n").each { |line| content += "# #{line}" } end content += hash.to_yaml show_diff_and_write(content, filepath, ) # File.open( filepath, 'w') do |f| # f.print "# ", File.basename(filepath), "\n" # f.puts "# /!\\ DO NOT EDIT THIS FILE: it has been automatically generated" # if options[:header] # options[:header].split("\n").each do |line| # f.puts "# #{line}" # end # end # f.puts hash.to_yaml # end end |
.warning(str) ⇒ Object
Print an warning message
66 67 68 |
# File 'lib/falkorlib/common.rb', line 66 def warning(str) puts cyan("/!\\ WARNING: " + str) end |
.write_from_erb_template(erbfile, outfile, config = {}, options = { :no_interaction => false }) ⇒ Object
ERB generation of the file ‘outfile` using the source template file `erbfile` Supported options:
:no_interaction [boolean]: do not interact
:srcdir [string]: source dir for all considered ERB files
364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 |
# File 'lib/falkorlib/common.rb', line 364 def write_from_erb_template(erbfile, outfile, config = {}, = { :no_interaction => false }) erbfiles = (erbfile.is_a?(Array)) ? erbfile : [ erbfile ] content = "" erbfiles.each do |f| erb = ([:srcdir].nil?) ? f : File.join([:srcdir], f) unless File.exist?(erb) warning "Unable to find the template ERBfile '#{erb}'" really_continue? unless [:no_interaction] next end #puts config.to_yaml content += ERB.new(File.read(erb.to_s), trim_mode: '<>').result(binding) end # error "Unable to find the template file #{erbfile}" unless File.exists? (erbfile ) # template = File.read("#{erbfile}") # output = ERB.new(template, nil, '<>') # content = output.result(binding) show_diff_and_write(content, outfile, ) end |
.write_from_template(src, dstdir, options = { :no_interaction => false, :no_commit => false, :srcdir => '', :outfile => '' }) ⇒ Object
Blind copy of a source file ‘src` into its destination directory `dstdir` Supported options:
:no_interaction [boolean]: do not interact
:srcdir [string]: source directory, make the `src` file relative to that directory
:outfile [string]: alter the outfile name (File.basename(src) by default)
:no_commit [boolean]: do not (offer to) commit the changes
436 437 438 439 440 441 442 443 444 445 446 447 448 449 |
# File 'lib/falkorlib/common.rb', line 436 def write_from_template(src, dstdir, = { :no_interaction => false, :no_commit => false, :srcdir => '', :outfile => '' }) srcfile = ([:srcdir].nil?) ? src : File.join([:srcdir], src) error "Unable to find the source file #{srcfile}" unless File.exist?( srcfile ) error "The destination directory '#{dstdir}' do not exist" unless File.directory?( dstdir ) dstfile = ([:outfile].nil?) ? File.basename(srcfile) : [:outfile] outfile = File.join(dstdir, dstfile) content = File.read( srcfile ) show_diff_and_write(content, outfile, ) end |