Module: ZBuild
- Defined in:
- lib/z_build.rb
Overview
Z’Build module is a collection of commonly used functions for creating light-weight build processes, written in Ruby. This library was authored in my spare time for Zoosk with a desire for more easily maintainable build processes, with a love for Ruby, and with a strong dislike for PHING/ANT and XML builds systems. Z’Build mostly concerns itself with directory creation, file copying, token replacement, and relative path management. At it’s core the Z’Build suite is intended to be minimal, sufficient, and transparent. If there is some aspect of your existing build that cannot be translated or mimicked with a series of Z’Build functions, then there may well be a missing feature, or otherwise there might be an opportunity to simplify your processes. However, it is expected that custom needs will require specialized code and as a library Z’Build is designed to be easily extended and works very well in conjuncation with build tools such as Ruby Rake. It is not meant to be a stand-alone build replacement - Rake/Thor/etc already do that very well. Here’s to hoping Z’Build makes your builds faster, your code simpler, and your life easier!
Instance Method Summary collapse
-
#clock(desc = 'Clocking Operation') { ... } ⇒ Fixnum
> Done [1 sec] => 1.
-
#default_permissions ⇒ Fixnum
Retrieve the default permission settings for file systems created using ZBuild.
-
#deploy_cp(from, to, opts = {}) ⇒ Object
Copy files from the working directory to deploy path.
-
#deploy_dir ⇒ String
The set deploy directory, or empty string if not set.
-
#deploy_dir_shift(path) { ... } ⇒ Object
Temporarily set the deploy directory to the specified path, then on completion of the given block the prior deploy directory will be automatically restored.
-
#deploy_mkdir(path, perm = self.default_permissions) ⇒ Object
Create all directories at the specified deploy path.
-
#deploy_path(path) ⇒ String
Retrieve a path relative to the set deploy directory.
-
#deploy_write(path, str, perm = 0750) ⇒ Object
Writes the content string to the specified file path.
-
#file_to_str(file) ⇒ String
Reads the specified file and returns contents as a string.
-
#glob(pattern) {|file_path, is_dir| ... } ⇒ Object
Given a specified path glob, yields the files and directories matching the glob pattern.
-
#info(message) ⇒ Object
Sends to stdout the message provided.
-
#open_temp_file(desc = '') {|f_handle, f_path| ... } ⇒ String
Creates a temporary file and returns generated path and file handle to the provided block.
-
#props_list_to_hash(*files) ⇒ Object
N-ary alternative to props_to_hash.
-
#props_to_hash(file, hash = {}) ⇒ Hash
Containing key/value pairs found in the specified file path, combined with the hash parameter.
-
#reset_deploy_dir ⇒ Object
Clears the deploy directory variable - requiring ZBuild specified deploy paths to be absolute.
-
#reset_working_dir ⇒ Object
Clears the working directory variable - requiring ZBuild specified paths to be absolute.
-
#run(shell_command, opts = {}) ⇒ String
Run shell commands.
-
#set_default_permissions(perms = 0750) ⇒ Object
Set the default permissions for file systems created using ZBuild.
-
#set_deploy_dir(path) ⇒ String
Specify a deploy directory - with a deploy directory set all functions requiring absolute paths for deploy parameters will become relative to the deploy directory set.
-
#set_working_dir(path) ⇒ String
Specify a working directory - with a working directory set all functions requiring absolute paths will become relative to the working directory.
-
#temp_file(content, desc = '') {|f_path| ... } ⇒ String
Short form of open_temp_file - writes content string immediately to temp file and yields the generated path.
-
#token_replace_file(file, token_to_replacement_hash, token_prefix = '', token_suffix = '') ⇒ String
Shortcut function to combine file_to_str + token_replace_str.
-
#token_replace_str(str, token_to_replacement_hash, token_prefix = '', token_suffix = '') ⇒ String
Perform token replacement on the specified string, with optionally specified token prefix and suffixes.
-
#walk_path(path) {|file_path, is_dir| ... } ⇒ Object
Walk to maxiumum depth the directory structure provided.
-
#warn(message) ⇒ Object
Sends to stdout the warning message provided.
-
#working_dir ⇒ String
The set working directory, or empty string if not set.
-
#working_dir_shift(path) { ... } ⇒ Object
Temporarily set the working directory to the specified path, then on completion of the given block the prior working directory will be automatically restored.
-
#working_path(path) ⇒ String
Retrieve a path relative to the set working directory.
Instance Method Details
#clock(desc = 'Clocking Operation') { ... } ⇒ Fixnum
> Done [1 sec]
=> 1
600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 |
# File 'lib/z_build.rb', line 600 def clock(desc='Clocking Operation', &block) @clock_count ||=0 @clock_count += 1 indent = " " * [0,@clock_count - 1].max puts "#{indent}#{desc}" t = Time.now.to_i yield run_time_sec = Time.now.to_i - t if run_time_sec < 60 run_time_str = "#{run_time_sec} sec" elsif run_time_sec < 3600 run_time_str = "#{run_time_sec / 60} min #{run_time_sec % 60} sec" else run_time_str = "#{run_time_sec / 3600} hr #{run_time_sec % 3600 / 60} min #{run_time_sec % 60} sec" end puts "#{indent}Done [#{run_time_str}]\n" @clock_count -= 1 run_time_sec end |
#default_permissions ⇒ Fixnum
Retrieve the default permission settings for file systems created using ZBuild.
77 78 79 |
# File 'lib/z_build.rb', line 77 def @default_permissions ||= 0750 end |
#deploy_cp(from, to, opts = {}) ⇒ Object
Copy files from the working directory to deploy path. When the recurse flag is set, contents from first directory’s contents are always copied as content to the second directory. If the intended behavior is to copy the first directory itself (in unix shell cp -r /path/dir dest/ vs cp -r /path/dir/ dest/), then one should instead call deploy_mkdir prior to a deploy_copy. This simplistic behavior is to make the calls more explicit and consequences less subtle than in a standard shell. The best way to conceptualzie this behavior is deploy_cp always copies directory content, and only sub-directories (as content) when the recurse flag is set.
209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 |
# File 'lib/z_build.rb', line 209 def deploy_cp(from, to, opts={}) working_path_given = self.working_path from deploy_path_given = self.deploy_path to queued_dirs = [] queued_files = {} working_exclude = opts[:exclude] ? opts[:exclude].to_a : [] # normalize excluded file relative path notations working_exclude = working_exclude.collect do |e| p = e.clone p = p.sub('./', '') # when working path is relative to root, walk path will return paths relative to root as well # so ensure all exclusion paths are also relative to root if from.start_with?('/') && !p.start_with?('/') p = File.join('/', p) elsif from.start_with?('./') && !p.start_with?('./') p = File.join('./', p) end if p.end_with? '/' p = p[0, p.size - 1] end p end if opts[:recurse] if !File.directory? working_path_given raise "Working path must be a directory when :recurse => true, given: #{working_path_given}" end if !File.directory? deploy_path_given raise "Deploy path must be a directory when :recurse => true, given: #{deploy_path_given}" end if !opts[:tokens] && !opts[:exclude] # when no token replacement and no exclusion is required, faster to do system copy # always join path to /. so that the contents will always be copied, and never the # directory itself - this maintains consistent behavior for the function # FileUtils requires the slash-dot /. whereas shell only requires either / or /* FileUtils.cp_r File.join(working_path_given, '/').concat('.'), deploy_path_given return end # from - the directory relative to working dir # deploy_path_given - the directory relative to the deploy dir self.walk_path(from) do |f_path, is_dir| should_exclude = false working_exclude.each do |e| if f_path.start_with? e should_exclude = true break end end if should_exclude # ignore files or directories marked for exclusion next end if is_dir # deploy_mkdir already creates relative to deploy path, so enqueue relative path queued_dirs.push File.join to, f_path.sub(from, '') next end # when recurse is invoked always copy the actual file name to the deploy dir given queued_files[f_path] = File.join deploy_path_given, f_path.sub(from, '') end else if File.directory? self.working_path(from) raise "Path given is a directory - not copied: #{self.working_path(from)}" end if !opts[:tokens] && !opts[:exclude] # when no token replacement and no exclusion is required, faster to do system copy if working_path_given.include? '*' FileUtils.cp Dir.glob(working_path_given), deploy_path_given else FileUtils.cp working_path_given, deploy_path_given end return end self.glob(from) do |f_path, is_dir| should_exclude = false working_exclude.each do |e| f_path_normalized = e if f_path_normalized.start_with?('./') && !e.start_with?('./') f_path_normalized = f_path_normalized.sub('./', '') end if f_path_normalized.start_with? e should_exclude = true break end end if should_exclude # ignore files or directories marked for exclusion next end if File.directory? deploy_path_given # given dir, so retain name of original file dest_path = File.join(deploy_path_given, File.basename(f_path)) else # deploy_path given is an actual file target dest_path = deploy_path_given end # f_path provided is relative to working dir - dest is absolute to deploy target queued_files[f_path] = dest_path end end # all directories queued are relative to deploy target queued_dirs.each do |d| self.deploy_mkdir d end queued_files.each do |relative_src, absolute_dest| File.open(absolute_dest, 'w') do |fh| if opts[:tokens].is_a? Hash fh.write self.token_replace_file(relative_src, opts[:tokens], opts[:token_prefix].to_s, opts[:token_suffix].to_s) else fh.write self.file_to_str(relative_src) end end end end |
#deploy_dir ⇒ String
Returns the set deploy directory, or empty string if not set.
454 455 456 |
# File 'lib/z_build.rb', line 454 def deploy_dir @deploy_dir ||= '' end |
#deploy_dir_shift(path) { ... } ⇒ Object
Temporarily set the deploy directory to the specified path, then on completion of the given block the prior deploy directory will be automatically restored.
57 58 59 60 61 62 63 64 65 |
# File 'lib/z_build.rb', line 57 def deploy_dir_shift(path, &block) restore_path = self.deploy_dir self.set_deploy_dir path yield self.set_deploy_dir restore_path end |
#deploy_mkdir(path, perm = self.default_permissions) ⇒ Object
this function works like the shell mkdir -p, so that /multiple/paths/deep will create all directories in the path
Create all directories at the specified deploy path.
141 142 143 144 145 146 147 148 |
# File 'lib/z_build.rb', line 141 def deploy_mkdir(path, perm=self.) deploy_path = self.deploy_path path # only create when does not already exist if !File.exist? deploy_path FileUtils.mkdir_p deploy_path, :mode => perm end end |
#deploy_path(path) ⇒ String
Retrieve a path relative to the set deploy directory.
437 438 439 440 441 442 443 444 |
# File 'lib/z_build.rb', line 437 def deploy_path(path) deploy_dir = self.deploy_dir if deploy_dir.empty? raise 'Deploy directory not set - set_deploy_dir must be invoked before deploy function use' end File.join(deploy_dir, path) end |
#deploy_write(path, str, perm = 0750) ⇒ Object
Writes the content string to the specified file path.
125 126 127 128 129 130 131 |
# File 'lib/z_build.rb', line 125 def deploy_write(path, str, perm=0750) deploy_path = self.deploy_path path File.open(deploy_path, 'w', perm) do |f| f.write str end end |
#file_to_str(file) ⇒ String
Reads the specified file and returns contents as a string.
517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 |
# File 'lib/z_build.rb', line 517 def file_to_str(file) str = '' working_path = File.join self.working_dir, file if !File.file? working_path raise "Specified file does not exist: #{working_path}" end File.open(working_path) do |fh| fh.each do |line| str += line end end str end |
#glob(pattern) {|file_path, is_dir| ... } ⇒ Object
Given a specified path glob, yields the files and directories matching the glob pattern.
541 542 543 544 545 546 547 548 549 550 551 |
# File 'lib/z_build.rb', line 541 def glob(pattern) relative_dir = File.dirname(pattern) working_dir = self.working_path pattern Dir.glob working_dir do |file_path| file_name = File.basename file_path is_dir = File.directory?(file_path) yield File.join(relative_dir, file_name), is_dir end end |
#info(message) ⇒ Object
Sends to stdout the message provided. Will indent relative to the number of clocked operations.
717 718 719 |
# File 'lib/z_build.rb', line 717 def info() puts "#{self.clock_indent}[INFO] #{}" end |
#open_temp_file(desc = '') {|f_handle, f_path| ... } ⇒ String
Creates a temporary file and returns generated path and file handle to the provided block. The file will be automatically deleted from the file system at the completion of the block. This function is useful in distinction from self.temp_file in that the temp file may be written to incrementally, rather than at once with a single string parameter, which under circumstance could cause a memory buffer error.
678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 |
# File 'lib/z_build.rb', line 678 def open_temp_file(desc='', &block) desc = desc.empty? ? '' : desc.to_s.match(/[a-zA-Z\s\d]*/).to_s.downcase.gsub(' ', '_') f_handle = Tempfile.new ['z_build', desc, Time.now.to_i].join('_') f_path = f_handle.path begin yield f_handle, f_handle.path if !f_handle.closed? f_handle.close end ensure f_handle.unlink end f_path end |
#props_list_to_hash(*files) ⇒ Object
N-ary alternative to props_to_hash. Takes n-property files, merges their key/value pairs into a hash in FIFO ordering, while performing variable replacement
829 830 831 832 833 834 835 836 |
# File 'lib/z_build.rb', line 829 def props_list_to_hash(*files) h = {} files.each do |f| h = self.props_to_hash f, h end h end |
#props_to_hash(file, hash = {}) ⇒ Hash
Returns containing key/value pairs found in the specified file path, combined with the hash parameter.
766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 |
# File 'lib/z_build.rb', line 766 def props_to_hash(file, hash={}) file_path = self.working_path file reprocess_keys = [] var_regex = /\$\{([a-zA-Z|\-|_|\d]+)\}/ if !File.file? file_path raise "Specified file does not exist: #{file_path}" end File.open(file_path) do |f| f.each do |line| line.to_s.strip! if line.empty? then next; end if line.start_with? '#' then next; end key, value = line.split '=' key = key.to_s.strip.to_s value = value.to_s.gsub(/#.*/, '').strip.to_s hash[key] = value # replace variable values defined by prior k,v pairs value.scan(var_regex).flatten.each do |var| if hash[var] == nil # key is expected but is not yet defined # mark key for re-visitation post processing reprocess_keys.push key next end # variable was found in hash - update keyed value with var replacement hash[key] = hash[key].gsub("${#{var}}", hash[var]) end end end # final pass var replacement for variables not defined using TOP-DOWN ordering reprocess_keys.each do |key| hash[key].scan(var_regex).flatten.each do |var| if hash[var] == nil # key is expected but is not yet defined - will not reprocess this variable self.warn "Failed to replace variable[#{var}] mapped to key[#{key}] found in file[#{file_path}]" next end hash[key] = hash[key].gsub("${#{var}}", hash[var]) end end hash end |
#reset_deploy_dir ⇒ Object
Clears the deploy directory variable - requiring ZBuild specified deploy paths to be absolute. By default all specified deploy paths must be absolute, however when a deploy directory is set, invoking this method requires them to be absolute again.
369 370 371 |
# File 'lib/z_build.rb', line 369 def reset_deploy_dir @deploy_dir = nil end |
#reset_working_dir ⇒ Object
Clears the working directory variable - requiring ZBuild specified paths to be absolute. By default all specified paths must be absolute, however when a working directory is set, invoking this method requires them to be absolute again.
408 409 410 |
# File 'lib/z_build.rb', line 408 def reset_working_dir @working_dir = nil end |
#run(shell_command, opts = {}) ⇒ String
Run shell commands
98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 |
# File 'lib/z_build.rb', line 98 def run(shell_command, opts={}) desc = opts[:desc] ? opts[:desc].to_s : "Running Command" if !opts[:quiet] output = "#{desc}: #{shell_command}" if opts[:regex_mask] mask_replace = opts[:mask_replace] ? opts[:mask_replace] : 'xxxx' output.gsub! opts[:regex_mask], mask_replace end self.info output end result = `#{shell_command}` if opts[:check_return] && !result.empty? raise "run failed for shell command: #{shell_command} result:#{result}" end result end |
#set_default_permissions(perms = 0750) ⇒ Object
Set the default permissions for file systems created using ZBuild.
70 71 72 |
# File 'lib/z_build.rb', line 70 def (perms=0750) @default_permissions = perms end |
#set_deploy_dir(path) ⇒ String
When deploy dir is set all function paramaters for the deploy directory will be assumed relative as well.
Specify a deploy directory - with a deploy directory set all functions requiring absolute paths for deploy parameters will become relative to the deploy directory set. This is not to be confused with the working directory - (see set_working_dir)
355 356 357 358 359 360 361 |
# File 'lib/z_build.rb', line 355 def set_deploy_dir(path) if !File.directory? path raise "Specified path is not a directory: #{path}" end @deploy_dir = path end |
#set_working_dir(path) ⇒ String
When working dir is set all paths yielded by blocks will be relative as well.
When working dir is set all function paramaters for the working directory will be assumed relative as well.
Specify a working directory - with a working directory set all functions requiring absolute paths will become relative to the working directory. The exception is paths meant for deploy function parameters - (see set_deploy_dir)
394 395 396 397 398 399 400 |
# File 'lib/z_build.rb', line 394 def set_working_dir(path) if !File.directory? path raise "Specified path is not a directory: #{path}" end @working_dir = path end |
#temp_file(content, desc = '') {|f_path| ... } ⇒ String
on yield the file has already been closed and the path is ready for reading/use
Short form of open_temp_file - writes content string immediately to temp file and yields the generated path. The temp file will be automatically deleted from the file system at the completion of the block.
643 644 645 646 647 648 649 650 651 652 653 654 |
# File 'lib/z_build.rb', line 643 def temp_file(content, desc='', &block) f_path = '' self.open_temp_file do |f_handle, path| f_path = path f_handle.write content f_handle.close yield path end f_path end |
#token_replace_file(file, token_to_replacement_hash, token_prefix = '', token_suffix = '') ⇒ String
Shortcut function to combine file_to_str + token_replace_str.
497 498 499 500 501 502 503 504 505 506 |
# File 'lib/z_build.rb', line 497 def token_replace_file(file, token_to_replacement_hash, token_prefix='', token_suffix='') # file_to_str accepts the path relative to working dir str = file_to_str file token_to_replacement_hash.each do |token, replacement| str = str.gsub "#{token_prefix}#{token}#{token_suffix}", replacement.to_s end str end |
#token_replace_str(str, token_to_replacement_hash, token_prefix = '', token_suffix = '') ⇒ String
Perform token replacement on the specified string, with optionally specified token prefix and suffixes.
476 477 478 479 480 481 482 |
# File 'lib/z_build.rb', line 476 def token_replace_str(str, token_to_replacement_hash, token_prefix='', token_suffix='') token_to_replacement_hash.each do |token, replacement| str = str.gsub "#{token_prefix}#{token}#{token_suffix}", replacement.to_s end str end |
#walk_path(path) {|file_path, is_dir| ... } ⇒ Object
Walk to maxiumum depth the directory structure provided.
570 571 572 573 574 575 576 577 578 579 |
# File 'lib/z_build.rb', line 570 def walk_path(path, &block) self.glob(File.join(path, '*')) do |f, is_dir| if is_dir self.walk_path f, &block end yield f, is_dir end end |
#warn(message) ⇒ Object
Sends to stdout the warning message provided. Will indent relative to the number of clocked operations.
709 710 711 |
# File 'lib/z_build.rb', line 709 def warn() puts "#{self.clock_indent}[WARN] #{}" end |
#working_dir ⇒ String
Returns the set working directory, or empty string if not set.
448 449 450 |
# File 'lib/z_build.rb', line 448 def working_dir @working_dir ||= '' end |
#working_dir_shift(path) { ... } ⇒ Object
Temporarily set the working directory to the specified path, then on completion of the given block the prior working directory will be automatically restored.
41 42 43 44 45 46 47 48 49 |
# File 'lib/z_build.rb', line 41 def working_dir_shift(path, &block) restore_path = self.working_dir self.set_working_dir path yield self.set_working_dir restore_path end |
#working_path(path) ⇒ String
Retrieve a path relative to the set working directory.
426 427 428 429 |
# File 'lib/z_build.rb', line 426 def working_path(path) working_dir = self.working_dir working_dir.empty? ? path : File.join(working_dir, path) end |