lib/cloud_powers/zenv.rb in cloud_powers-1.0.1 vs lib/cloud_powers/zenv.rb in cloud_powers-1.1.0

- old
+ new

@@ -9,39 +9,18 @@ # System ENV, dotenv ENV and instance variables are considered for now but this # will also use elasticache/redis...some other stuff too, in the coming versions module Zenv include Smash::CloudPowers::Helpers - # Attempts to find a file by searching the current directory for the file - # then walking up the file tree and searching at each stop all the way up - # to the root directory - # - # Parameters - # * name +String+ - name of the file or directory to find - # - # Returns - # +Pathname+ - path to the file or directory given as the +name+ parameter - def file_tree_search(name) - next_dir = Pathname.new(`pwd`.strip).parent - current_dir = Pathname.new(`pwd`.strip) - until(next_dir == current_dir) do - path = Dir.glob("#{current_dir}/#{name}").first - return current_dir unless path.nil? - current_dir = next_dir - next_dir = next_dir.parent - end - return nil - end - # Search through the {Dotenv}[https://github.com/bkeepers/dotenv] # variables for a key or if no key is given, return all the .env-vars # and their values # # Parameters # * key +String+ - def env_vars(key = '') - return ENV if key.empty? + return ENV if key.empty? || key.nil? ENV[to_snake(key).upcase] end # Search through the instance variables for a key or if no key is given, # return all the i-vars and their values @@ -52,65 +31,152 @@ # the value of the +key+ searched for def i_vars(key = '') name = to_i_var(key) # if no key is given, return a +Hash+ of all i-var/value pairs - if key.empty? - return self.instance_variables.inject({}) do |r, v| - r.tap { |h| h[name] = self.instance_variable_get(name) } + if key.empty? || key.nil? + self.instance_variables.inject({}) do |r, v| + r.tap { |h| h[to_i_var(v)] = self.instance_variable_get(v.to_s) } end + else + self.instance_variable_get(name) end + end - self.instance_variable_get(name) + # Get the PID for the current process + # + # Returns + # * +String+ + # + # Notes + # * See <tt>::Process#pid()</tt> + def pid + Process.pid end - # PROJECT_ROOT should be set as early as possible in this Node's initilize - # method. This method tries to search for it, using #zfind() and if a `nil` - # result is returned from that search, `pwd` is used as the PROJECT_ROOT. + def lsof_cwd + to_realpath((`lsof -p #{Process.pid} | grep cwd`).split(' ').last.strip) + end + + def process_search + search_results = proc_cwd || lsof_cwd || ps_cwd || nil + paths_lcd(search_results, called_from) + end + + # # Search the output of <tt>`ps ...`</tt> to find this process' working + # # directory + # # + # # Returns + # # * +Pathname+ + # def path_resolution(one, two) + # logger.debug("path_resolution request from #{caller.first} as #{proc_cwd}") + # Pathname.new(sys_command_output).realpath + # end + + # Ask <i>Linux</i> systems what directory the process is running from. # # Returns + # * +Pathname+ - the lcoation containing the file that was called to run + # this program + # * +nil+ - if the OS doesn't support the proc methods, +nil+ is returned + def proc_cwd + begin + to_realpath(`ls -l /proc/#{pid}/cwd`.split(/\->\s?/).last.strip) + rescue NoMethodError => e + logger.debug('this system does not support /proc files system queries') + nil + end + end + + # Get the location of the current working directory for the project that + # is calling this method. + # + # Returns + # * +Pathname+ + # + # Notes: + # * Tested on Ubuntu, Mac and Centos 7 + # * Similar methods: + # * * <tt>proc_cwd</tt> + # * * <tt>called_from</tt> + def ps_cwd + begin + ef = `ps -ef | grep #{pid}`.split("\n").first.split(' ').last + aux = `ps aux | grep #{pid}`.split("\n").first.split(' ').last + Pathname.new(/[A-Za-z]*\.[A-Za-z]+$/ =~ ef ? ef : aux).realpath + rescue Exception => e + if e.nil? + logger.debug('This system does not support ps functionality') + nil + else + super + end + end + end + + # <tt>PROJECT_ROOT</tt>, <tt>project_root= your_project_root</tt> or + # <tt>@project_root</tt> should be set as early as possible in this + # Node's initilize process. This method tries to search for it, using + # <tt>Zenv#zfind</tt> and if that fails, another search through system + # tools is run to make a best attempt at finding the lowest common path. + # + # Returns # +Pathname+ - path to the project root or where ever <tt>`pwd`</tt> resolves # to for the caller # # Notes # * TODO: improve this...it needs to find the gem's method's caller's project # root or at least the gem's method's caller's file's location. # # Example - # # called from cerebrum/cerebrum.rb in /home/ubuntu - # project_root + # /home/ubuntu/cerebrum$ ruby -e cerebrum.rb 'Cerebrum.new.project_root' # # => '/home/ubuntu/cerebrum/' - # # or - # # called from go_nuts.rb#begin_going_crazy():(line -999999999.9) in /Users/crazyman/.ssh/why/all/the/madness/ + # or + # <tt>project_root</tt> invoked from somewhere in + # <tt>/Users/crazyman/.ssh/why/all/the/wasted_time</tt> + # <tt>called_from</tt> is + # <tt>/Users/crazyman/.ssh/why/all/the/insanity/go_nuts.rb#ok():(line -999999999.9)</tt> + # and + # <tt>/proc/<pid>/cwd</tt> is /Users/crazyman/.ssh/why/all/the/madness/ + # and + # # caller is + # [ + # ... , /Users/crazyman/.rbenv/versions/2.4.0/lib/ruby/ + # gems/2.4.0/gems/rspec-core-3.5.4/lib/rspec/core/hooks.rb, ...]</tt> + # and + # <tt>ps -ef | grep #{pid}...</tt> is <tt>[ + # ..., /Users/crazyman/.rbenv/versions/2.4.0/lib/ruby/ + # gems/2.4.0/gems/rspec-core-3.5.4/lib/rspec/core/hooks.rb, ...]</tt> + # then # project_root - # # => '/Users/crazyman/.ssh/why/all/the/madness/' + # # => '/Users/crazyman/.ssh/why/all/the' def project_root if @project_root.nil? - file_home = Pathname.new( - caller_locations.first.path.strip.split(/\//).last).realdirpath.parent - # path = (zfind('PROJECT_ROOT') or file_home) - @project_root = Pathname.new(file_home) + new_root = to_realpath(zfind('project root') || process_search) + logger.info("project root set to:#{new_root} by:#{called_from}") + @project_root = new_root + else + @project_root end - @project_root end # Manually set the +@project_root+ i-var as a +Pathname+ object. # # Parameters # * +String+|+Pathname+ - new path to the project root # # Returns - # +Pathname+ - +@project_root+ + # +@project_root+ [+Pathname+] # # Example # project_root # # => '/home/ubuntu/cerebrum/' # project_root = Pathname.new(`pwd`) # project_root == `pwd` # # => true - def project_root=(var) - @project_root = Pathname.new(var) + def project_root=(path) + @project_root = to_pathname(path).realpath end # Search through the system environment variables for a key or if no key # is given, return all the system-env-vars and their values # @@ -121,25 +187,11 @@ # * if a +key+ is given as a parameter, +String+ # * if no +key+ is given as a parameter, +Hash+ # with this structure +{ key => value, ... }+ is returned for all keys with a value. # Keys with no value are ommitted from the result. def system_vars(key = '') - name = to_snake(key).upcase - if key.empty? - # Separate key-value pairs from the large string received by `ENV` - separate_pairs = `ENV`.split(/\n/).map do |string_pair| - string_pair.split('=') - end - # Separate key-value pairs from each other into a hash of - # { key => value, other_key => other_value } - # * keys with no value are removed - separate_pairs.inject({}) do |res, pair| - res.tap { |h_res| h_res[pair.first] = pair.last unless (pair.first == pair.last) } - end - else - Object::ENV.has_key?(name) ? Object::ENV.fetch(name) : nil - end + (key.empty? || key.nil?) ? ::ENV.to_h : ::ENV[to_snake(key).upcase] end # ZFind looks for the key in a preditermined order of importance: # * i-vars are considered first becuase they might be tracking different # locations for multiple jobs or something like that. @@ -150,16 +202,29 @@ # # Parameters # * key +String+|+Symbol+ - the key to search for # # Returns - # * +String+ + # * +Object+ - whatever type you were looking for, storing or accidentally + # now dealing with is what can be returned # # Notes # * TODO: implement a search for all 3 that can find close matches - def zfind(key) - project_root if @project_root.nil? + def zfind(key = '') i_vars(key) || env_vars(key) || system_vars(key) + end + + # Get anything that matches, within the same area that <tt>#zfind</tt> + # can search through. This has the feel of <tt>Hash#select</tt>./ + def zselect(key = '') + vars = system_vars.merge(env_vars).merge(i_vars) + if (key.empty? || key.nil?) + vars.values + else + vars.select { |k,v| %r"#{to_snake(key)}" =~ to_snake(k) }.values + # results = vars.select { |k,v| %r"#{to_snake(key)}" =~ to_snake(k) } + # (results.count == 1) ? results.values.first : results + end end end end end