Class: Podgraph::Trestle

Inherits:
Object
  • Object
show all
Defined in:
lib/podgraph/trestle.rb

Constant Summary collapse

NNL_MARK =

#veputs uses this to decide to put a newline or not to put.

'__NNL__'

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(conf) ⇒ Trestle

conf

Typically must be a reference to some global variable.



63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
# File 'lib/podgraph/trestle.rb', line 63

def initialize(conf)
  @conf = conf
  @conf[:verbose] = 0
  @conf[:banner] = "Usage: #{File.basename($0)} [options]"
  @conf[:config] =  Meta::NAME + '.yaml'
  @conf[:config_dirs] =  [ENV['HOME']+'/.'+Meta::NAME,
                          File.absolute_path("#{File.dirname(File.expand_path($0))}/../etc"),
                          '/usr/etc', '/usr/local/etc', '/etc',
                          "#{Gem.dir}/gems/#{Meta::NAME}-#{Meta::VERSION}/etc"
                         ]
  @conf[:config_env] = [Meta::NAME.upcase + '_CONF']

  @cl_parsing_times = 0 # not used
  @cl_opt_protect = false
end

Instance Attribute Details

#cl_opt_protectObject (readonly)

Use this in your CL options to check if modifying some variable is not an idempotent act.



60
61
62
# File 'lib/podgraph/trestle.rb', line 60

def cl_opt_protect
  @cl_opt_protect
end

Class Method Details

.cmd_run(cmd) ⇒ Object

Execute cmd and return a list [exit_status, stderr, stdout]. Very handy.



17
18
19
20
21
22
23
24
# File 'lib/podgraph/trestle.rb', line 17

def self.cmd_run(cmd)
  so = sr = ''
  status = Open4::popen4(cmd) { |pid, stdin, stdout, stderr|
    so = stdout.read
    sr = stderr.read
  }
  [status.exitstatus, sr, so]
end

.errx(ec, t) ⇒ Object

Print an error message t and exit if ec > 0.



45
46
47
48
# File 'lib/podgraph/trestle.rb', line 45

def self.errx(ec, t)
  STDERR.puts File.basename($0) + ' error: ' + t.to_s
  exit ec if ec > 0
end

.gem_libdirObject

Return a directory with program libraries.



27
28
29
30
31
32
33
# File 'lib/podgraph/trestle.rb', line 27

def self.gem_libdir
  t = ["#{File.dirname(File.expand_path($0))}/../lib/#{Podgraph::Meta::NAME}",
       "#{Gem.dir}/gems/#{Podgraph::Meta::NAME}-#{Podgraph::Meta::VERSION}/lib/#{Podgraph::Meta::NAME}",
       "lib/#{Podgraph::Meta::NAME}"]
  t.each {|i| return i if File.readable?(i) }
  fail "all paths are invalid: #{t}"
end

.in_path?(file) ⇒ Boolean

Analogue to shell command which.

Returns:

  • (Boolean)


36
37
38
39
40
41
42
# File 'lib/podgraph/trestle.rb', line 36

def self.in_path?(file)
  return true if file =~ %r%\A/% and File.exist? file

  ENV['PATH'].split(File::PATH_SEPARATOR).any? do |path|
    File.exist? File.join(path, file)
  end
end

.warnx(t) ⇒ Object

Print a warning.



51
52
53
# File 'lib/podgraph/trestle.rb', line 51

def self.warnx(t)
  STDERR.puts File.basename($0) + ' warning: ' + t.to_s
end

Instance Method Details

#cl_parse(src, o = nil, simple = false) ⇒ Object

Parses CL-like options.

src

An array of options (usually ARGV).

If o is non nil function parses src immediately, otherwise it only creates OptionParser object and return it (if simple is false).



178
179
180
181
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
# File 'lib/podgraph/trestle.rb', line 178

def cl_parse(src, o = nil, simple = false)
  if ! o then
#        puts "NEW o (#{cl_opt_protect})" + src.to_s 
    o = OptionParser.new
    o.banner = @conf[:banner]
    o.on('-v', 'Be more verbose.') { |i|
#          puts "cl_parsing_times "+cl_parsing_times.to_s
      @conf[:verbose] += 1 unless cl_opt_protect
    }
    o.on('-V', 'Show version & exit.') { |i|
      puts Meta::VERSION
      exit 0
    }
    o.on('--config NAME', "Set a config name (default is #{@conf[:config]})") {|i|
      @conf[:config] = i
    }
    o.on('--config-dirs', 'Show possible config locations') {
      @conf[:config_dirs].each { |j|
        f = j + '/' + @conf[:config]
        puts (File.readable?(f) ? '* ' : '  ') +  f
      }
      exit 0
    }

    return o if ! simple
  end

  begin
    o.parse!(src)
    @cl_parsing_times += 1
  rescue
    Trestle.errx(1, $!.to_s)
  end
end

#config_flat_load(rvars) ⇒ Object

Load a config file immediately if it contains ‘/’ in its name, otherwise search through several dirs for it.

rvars

a list of requied variables in the config

Return a loaded filename or nil on error.



142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
# File 'lib/podgraph/trestle.rb', line 142

def config_flat_load(rvars)
  p = ->(f) {
    if File.readable?(f)
      begin
        myconf = YAML.load_file(f)
      rescue
        abort("cannot parse #{f}: #{$!}")
      end
      rvars.each { |i|
        fail "missing or nil '#{i}' in #{f}" if ! myconf.key?(i.to_sym) || ! myconf[i.to_sym]
      }
      @conf.merge!(myconf)
      return @conf[:config]
    end
    return nil
  }

  if @conf[:config].index('/')
    return p.call(@config[:config])
  else
    @conf[:config_dirs].each {|dir|
      return dir+'/'+@conf[:config] if p.call(dir + '/' + @conf[:config])
    }
  end

  return nil
end

#config_parse(rvars, &block) ⇒ Object

Run all configuration parsing in a batch.

rvars

A list of variable names which must be in the configuration file.

If no block is given, only standard CL options will be analysed.



103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
# File 'lib/podgraph/trestle.rb', line 103

def config_parse(rvars, &block)
  cb = ->(b, src) {
    if b
      block.call src
    else
      # very basic default options
      cl_parse(src, nil, true)
    end
  }
  
  # 1. parse env
  @conf[:config_env].each {|i|
#        puts '0 run:'
    cb.call(block_given?, ENV[i].shellsplit) if ENV.key?(i)
  }

  # 2. parse CL in case of '--config' option
#      puts "\n1 run"
  @cl_opt_protect = true
  cb.call(block_given?, ARGV.dup)
  @cl_opt_protect = false

  # 3. load the configuration file & do the final CL parsing
  begin
#        puts "\n2 run"
    r = config_flat_load(rvars)
  rescue
    Trestle.errx(1, "cannot load config: #{$!}")
  end
  veputs(1, "Loaded config: #{r}")
  cb.call(block_given?, ARGV)
end

#veputs(level, t) ⇒ Object

level

A verbose level.

t

A string to print.

Don’t print t with a newline if it contains NNL_MARK at the end.



83
84
85
86
87
88
89
90
91
92
93
94
95
# File 'lib/podgraph/trestle.rb', line 83

def veputs(level, t)
  t = t.dup
  nnl = nil
  if t.match(/#{NNL_MARK}$/)
    t.sub!(/#{$&}/, '')
    nnl = 1
  end

  if @conf[:verbose] >= level
    nnl ? print(t) : puts(t)
    STDOUT.flush
  end
end