class Flor::Tools::Shell

Constants

ALIASES

command helpers

COMMANDS

enumerate commands (for cmd_help)

Attributes

c[R]

Public Class Methods

new(argv=nil) click to toggle source
# File lib/flor/tools/shell.rb, line 15
def initialize(argv=nil)

  env = ENV['FLOR_ENV'] || 'shell'

  @root = File.directory?(env) ? env : "envs/#{env}"

  prepare_home

  over_conf = {}
    #
  c = ENV['FLOR_STO_URI']; over_conf['sto_uri'] = c if c

  @unit = Flor::Unit.new("#{@root}/etc/conf.json", over_conf)

  @unit.conf['unit'] = 'cli'
  #unit.hooker.add('journal', Flor::Journal)

  prepare_db
  prepare_hooks

  @hook = 'on'
  @mute = false
  @paging = true

  if ENV['FLOR_NO_START']
    @unit.check_migration_version
  else
    @unit.start
  end

  @flow_path = File.join(@root, 'home/scratch.flo')
  @ra_flow_path = File.join(@root, 'home/ra_scratch.flo')
  @payload_path = File.join(@root, 'home/payload.json')
  @variables_path = File.join(@root, 'home/variables.json')

  @c = Flor.colours({})

  load_floshrc

  if argv && argv.any?
    do_eval(argv.join(' '))
  else
    print_header
    do_loop
  end
end

Protected Class Methods

is_alias?(c) click to toggle source
# File lib/flor/tools/shell.rb, line 220
def self.is_alias?(c)

  !! ALIASES.values.find { |a| a.include?(c) }
end
make_alias(a, b) click to toggle source
# File lib/flor/tools/shell.rb, line 211
def self.make_alias(a, b)

  define_method("hlp_#{a}") { "alias to #{b.inspect}" }
  alias_method "man_#{a}", "man_#{b}" rescue nil
  alias_method "cmd_#{a}", "cmd_#{b}"

  (ALIASES[b] ||= []) << a
end

Protected Instance Methods

arg(line, index=1) click to toggle source
# File lib/flor/tools/shell.rb, line 227
def arg(line, index=1); args(line)[index]; end
Also aliased as: fname
argc(line) click to toggle source
# File lib/flor/tools/shell.rb, line 226
def argc(line); args(line).count; end
args(line) click to toggle source
# File lib/flor/tools/shell.rb, line 225
def args(line); line.split(/\s+/); end
aright(val) click to toggle source
# File lib/flor/tools/shell.rb, line 279
def aright(val)

  { value: val, alignment: :right }
end
choose_execution_path(frag, option) click to toggle source
# File lib/flor/tools/shell.rb, line 230
def choose_execution_path(frag, option)

  fail ArgumentError.new("'frag' argument missing") \
    unless frag

  exe = lookup_execution(frag)

  fail ArgumentError.new("execution matching \"%#{frag}%\" not found") \
    unless exe

  d = File.join(@root, 'tmp')
  FileUtils.mkdir_p(d)
  fn = File.join(d, "exe__#{exe.exid}.rb")

  File.open(fn, 'wb') { |f| PP.pp(exe.data, f, 79) } \
    if ! File.exist?(fn) || option == 'force'

  fn
end
choose_path(line) click to toggle source
# File lib/flor/tools/shell.rb, line 250
def choose_path(line)

  b = arg(line, 2)
  c = arg(line, 3)

  case fname(line)
  when /\Av/,
    @variables_path
  when /\Ap/
    @payload_path
  when /\At/
    fail ArgumentError.new("'frag' argument missing") unless b
    Dir[File.join(@root, 'var/tasks/**/*.json')].find { |pa| pa.index(b) }
  when /\Ar/
    @ra_flow_path
  when /\Ae/
    choose_execution_path(b, c)
  else
    @flow_path
  end
end
cmd_cancel(line) click to toggle source
# File lib/flor/tools/shell.rb, line 1016
def cmd_cancel(line)

  exid, nid = lookup_exid_nid(line)

  @unit.cancel(exid: exid, nid: nid)

  puts @c.yellow("cancel message queued for #{exid} #{nid}")
end
cmd_cat(line) click to toggle source
# File lib/flor/tools/shell.rb, line 611
def cmd_cat(line)

  puts "  # #{@flow_path}\n"
  File.readlines(@flow_path).each { |l| puts "  #{l}" }
end
cmd_conf(line) click to toggle source
# File lib/flor/tools/shell.rb, line 630
def cmd_conf(line)

  key, value = arg(line), (args(line)[2..-1] || []).join(' ')

  if key && @unit.conf.has_key?(key)
    puts Flor.to_d(
      { key: @unit.conf[key] }, colour: true, indent: 1, width: true)
  end

  if key && argc(line) > 2
    @unit.conf[key] = parse_single_json_value(value)
    puts "   #{@c.dg}# ==>#{@c.reset}"
    puts Flor.to_d(
      { key: @unit.conf[key] }, colour: true, indent: 1, width: true)
  elsif key
    # alreay done
  else
    page(Flor.to_d(@unit.conf, colour: true, indent: 1, width: true))
  end
end
cmd_debug(line) click to toggle source
# File lib/flor/tools/shell.rb, line 832
def cmd_debug(line)

  @unit.conf.select! { |k, v| ! k.match(/\Alog_/) }

  rest = line.match(/\A[a-z]+(\s+.+)?/)[1]
  rest = rest.strip if rest
  rest = nil if rest && rest == 'off'
  rest = 'stdout,dbg' if rest && %w[ on 1 ].include?(rest)

  @unit.conf.merge!(Flor::Conf.interpret_flor_debug(debug: rest)) if rest

  cmd_conf('') # display conf
end
cmd_detail(line) click to toggle source
# File lib/flor/tools/shell.rb, line 988
def cmd_detail(line)

  type, id = arg(line), arg(line, 2)

  fail ArgumentError.new(
    "please specify type (exe, ti, ta) and id (int) or fragment of id"
  ) unless type && id

  case type
  when /\Ae/ then detail_execution(id)
  when /\Ati/ then detail_timer(id)
  when /\At/ then detail_task(id)
  else puts "unknown type #{type.inspect}"
  end
end
cmd_edit(line) click to toggle source
# File lib/flor/tools/shell.rb, line 592
def cmd_edit(line)

  if path = choose_path(line)
    system("$EDITOR #{path}")
  else
    puts "not found"
  end
end
cmd_executions(line) click to toggle source
# File lib/flor/tools/shell.rb, line 723
def cmd_executions(line)

  o = StringIO.new

  exes = @unit.executions
  exes = exes.where(status: 'active') unless arg(line) == 'all'

  table = Terminal::Table.new(
    #title: 'executions',
    headings: %w[ id exid name started tis status ],
    style: table_style)
  #table.align_column(0, :right)

  exes
    .each { |e|
      vs = e.zero_variables
      table.add_row([
        aright(e.id),
        @c.yl(e.exid),
        %w[ execution_name process_name flow_name name ]
          .collect { |k| vs[k] }.compact.first,
        e.ctime[0, 19],
        aright(@unit.timers.where(exid: e.exid, status: 'active').count),
        e.failed? ? 'failed' : 'running'
      ]) }

  o.puts table
  o.puts "#{exes.count} execution#{exes.count != 1 ? 's' : ''}.\n"

  page(o)
end
cmd_exit(line) click to toggle source
# File lib/flor/tools/shell.rb, line 534
def cmd_exit(line)

  exit(line.split(/\s+/)[1].to_i)
end
cmd_flosh(line) click to toggle source
# File lib/flor/tools/shell.rb, line 1131
    def cmd_flosh(line)
      page %{
#{@c.yellow}# flosh#{@c.reset}

Flosh is a flor shell.

It's meant for demonstration purposes, to show how flor works.

Opening a flor shell, starts a flor scheduler pointing to #{@root}

#{@c.yellow}# flosh provided taskers#{@c.reset}

The following names can be used as "nato" taskers: alpha, bravo, charly, delta, fox, foxtrott, golf, echo, and hotel.

Nato taskers simply put their tasks under #{@root}/var/tasks/{tasker-name}/ as JSON files. Those file can be edited with the `edit task {frag}`.

Once edited (or not), a nato tasker task can be returned to flor (to the scheduler) with `return {frag}`.
      }
    end
cmd_help(line) click to toggle source
# File lib/flor/tools/shell.rb, line 493
def cmd_help(line)

  o = StringIO.new

  if cmd = arg(line)

    begin
      send("man_#{cmd}").split("\n").collect(&:strip).each do |l|
        if l[0, 1] == '*'
          o.puts " #{@c.dg}*#{@c.rs} #{l[1..-1].strip}"
        else
          o.puts "   #{@c.dark_gray(l)}"
        end
      end
    rescue
      fail ArgumentError.new("no 'manual' for #{cmd.inspect}")
    end

  else

    o.puts
    o.puts "## available commands:"
    o.puts
    COMMANDS.each do |c|
      o.print "* #{@c.yellow(c)}"
      if hlp = (send("hlp_#{c}") rescue nil)
        o.print " - #{hlp.strip}"
      end
      o.puts
    end
    o.puts
  end

  page(o)
end
cmd_hook(line) click to toggle source
# File lib/flor/tools/shell.rb, line 858
def cmd_hook(line)

  @hook =
    case arg(line)
    when 'true', 'on'
      'on'
    when 'false', 'off'
      'off'
    else
      puts "hook is #{@hook.inspect}"
      @hook
    end
end
cmd_launch(line) click to toggle source
# File lib/flor/tools/shell.rb, line 466
def cmd_launch(line)

  flow = File.read(@flow_path)
  variables = Flor::ConfExecutor.interpret_path(@variables_path)
  payload = Flor::ConfExecutor.interpret_path(@payload_path)
  domain = 'shell'

  vars = Flor::ConfExecutor.interpret_line("\n" + line[6..-1]) rescue {}
  variables.merge!(vars)

  exid = @unit.launch(
    flow, domain: domain, vars: variables, payload: payload)

  puts "  launched #{@c.green}#{exid}#{@c.reset}"
end
cmd_page(line, paging=:more) click to toggle source
# File lib/flor/tools/shell.rb, line 419
def cmd_page(line, paging=:more)

  current_paging = @paging
  @paging = paging

  line = line.strip.split(/\s+/, 2)[1]

  if line.nil? || line.empty?
    do_eval('man page')
  elsif File.exist?(line) && ! File.directory?(line)
    page(File.read(line))
  else
    do_eval(line)
  end

ensure

  @paging = current_paging
end
cmd_paging(line) click to toggle source
# File lib/flor/tools/shell.rb, line 382
def cmd_paging(line)

  @paging =
    case arg(line)
    when 'vi', 'vim' then :vi
    when 'no', 'off', 'false' then false
    when 'more', 'less' then :more
    #when 'on', 'true' then true
    else true
    end
  puts "paging set to #{@paging}"
end
cmd_parse(line) click to toggle source
# File lib/flor/tools/shell.rb, line 552
def cmd_parse(line)

  source = File.read(@flow_path)
  tree = Flor.parse(source, nil, {})

  case arg(line)
  when 'd', 'raw'
    puts Flor.to_d(tree, colours: true, indent: 1, max_width: 80)
  when 'djan'
    puts Flor.to_d(tree, colours: true, indent: 1)
  when 'pp'
    pp tree
  when 'p'
    p tree
  else
    puts Flor.tree_to_s(tree, '0', headers: false)
  end
end
cmd_read(line) click to toggle source
# File lib/flor/tools/shell.rb, line 404
def cmd_read(line)
  page(File.read(arg(line)))
end
cmd_reapply(line) click to toggle source
# File lib/flor/tools/shell.rb, line 1110
def cmd_reapply(line)

  exid, nid = lookup_exid_nid(line)

  t = File.read(@ra_flow_path)
  pl = Flor::ConfExecutor.interpret(@payload_path)

  @unit.re_apply(exid: exid, nid: nid, tree: t, payload: pl)

  puts @c.yellow("re-apply message queued for #{exid} #{nid}")
end
cmd_render(line) click to toggle source
# File lib/flor/tools/shell.rb, line 1060
def cmd_render(line)

  o = StringIO.new

  frag = arg(line)

  exe =
    @unit.executions.first(Sequel.like(:exid, "%#{frag}%")) ||
    fail(ArgumentError.new("execution matching \"%#{frag}%\" not found"))
  o.puts
  o.puts "  exid:    #{@c.yellow(exe.exid)}"
  o.puts "  status:  #{@c.yellow(exe.status)}"
  o.puts

  tree = exe.full_tree
  nodes = exe.nodes

  orphans = []

  nodes.each do |nid, n|
    if st = Flor.tree_locate(tree, nid)
      st << { node: n }
    else
      orphans << n
    end
  end

  @unit.pointers.where(exid: exe.exid, type: 'tasker').each do |pt|
    if st = Flor.tree_locate(tree, pt.nid)
      h = st.last.is_a?(Hash) ? st.last : (st << {})
      h[:tasker] = pt
    else
      orphans << pt
    end
  end

  render_node(o, tree, '0')

  page(o)
end
cmd_return(line) click to toggle source
# File lib/flor/tools/shell.rb, line 798
def cmd_return(line)

  t = arg(line)

  fail ArgumentError.new(
    "please specify a task's exid-nid or a fragment of it"
  ) unless t

  path = Dir[File.join(@root, 'var/tasks/**/*.json')]
    .find { |pa| pa.index(t) }

  fail ArgumentError.new(
    "couldn't find a task matching #{t.inspect}"
  ) unless path

  puts "found task at #{path}"

  m = JSON.parse(File.read(path))
  @unit.return(m)
  FileUtils.rm(path)
end
cmd_t(line) click to toggle source
# File lib/flor/tools/shell.rb, line 654
def cmd_t(line)
  #page(`tree -C #{@root}`)
  page(`tree #{@root}`)
end
cmd_tasks(line) click to toggle source
# File lib/flor/tools/shell.rb, line 670
def cmd_tasks(line)

  o = StringIO.new

  frag = arg(line)

  table = Terminal::Table.new(
    #title: 'tasks',
    headings: %w[ id tasker nid exid payload mtime ],
    style: table_style)

  tas = Dir[File.join(@root, 'var/tasks/**/*.json')]
  tas = tas.select { |pa| pa.index(frag) } if frag

  tas
    .each_with_index { |pa, i|

      ss = pa.split('/')
      tasker = ss[-2]

      exid, nid = Flor.extract_exid_and_nid(ss[-1])

      data = JSON.parse(File.read(pa)) rescue nil
      data = data || { 'payload' => nil }
        #
      pl = Flor.to_d(
        data['payload'],
        colour: false, indent: nil, compact: true)
      pl = @c.dark_gray(pl[0, 21] + '...')

      mt = @c.dark_gray(File.mtime(pa).to_s[0, 19])

      table.add_row([
        aright(i), tasker, nid, @c.yellow(exid), pl, mt ]) }

  o.puts table
  o.puts "#{tas.count} task#{tas.count != 1 ? 's' : ''}.\n"

  page(o)
end
cmd_timers(line) click to toggle source
# File lib/flor/tools/shell.rb, line 759
def cmd_timers(line)

  o = StringIO.new

  tis = @unit.timers
  tis = tis.where(status: 'active') unless arg(line) == 'all'

  table = Terminal::Table.new(
    #title: 'timers',
    headings: [ 'id', 'nid', 'exid', 'type', 'schedule', 'next time' ],
    style: table_style)
  #table.align_column(0, :right)
  #table.align_column(4, :right)

  tis
    .each_with_index { |t, i|
      table.add_row([
        aright(t.id), t.nid, @c.yl(t.exid), t.type,
        aright(t.schedule), t.ntime[0, 19]
      ]) }

  o.puts table
  o.puts "#{tis.count} timer#{tis.count != 1 ? 's' : ''}.\n"

  page(o)
end
cmd_vi(line) click to toggle source
# File lib/flor/tools/shell.rb, line 450
def cmd_vi(line)
  cmd_page(line, :vi)
end
detail_execution(id) click to toggle source
# File lib/flor/tools/shell.rb, line 905
def detail_execution(id)

  o = StringIO.new

  exe = lookup_execution(id)

  eid = { id: exe.id, exid: exe.exid }.inspect
  con = Flor::Storage.from_blob(exe.values.delete(:content))
  exe.values[:content] = '...'

  o.puts @c.dg("--- exe #{eid} :")
  o.puts h_to_table(exe.values)
  o.puts @c.dg("  exe #{eid} content:")
  nodes = con.delete('nodes')
  con['nodes'] = '...'
  o.puts indent('  ', h_to_table(con))
  o.puts @c.dg("    exe #{eid} content/nodes:")
  table = Terminal::Table.new(
    headings: %w[ nid data ],
    style: table_style.merge(all_separators: true))
  nodes.each do |k, v|
    table.add_row([ k, Flor.to_d(v, colour: true, indent: 0, width: 70) ])
  end
  o.puts indent('    ', table)

  page(o)
end
detail_task(id) click to toggle source
# File lib/flor/tools/shell.rb, line 954
def detail_task(id)

  pa = Dir["#{@root}/var/tasks/**/*#{id}*.json"].first

  fail ArgumentError.new("found no task matching #{id}") unless pa

  ta = JSON.load(File.read(pa))
  tconf = ta['tconf']; ta['tconf'] = '...'
  payload = ta['payload']; ta['payload'] = '...'

  o = StringIO.new
  o.puts "#{@c.dg} #\n # path: #{pa}\n ##{@c.reset}"
  o.puts Flor.to_d(ta, colour: true, indent: 1, width: true)
  o.puts "#{@c.dg} # tconf:#{@c.reset}"
  o.puts Flor.to_d(tconf, colour: true, indent: 3, width: true)
  o.puts "#{@c.dg} # payload:#{@c.reset}"
  o.puts Flor.to_d(payload, colour: true, indent: 3, width: true)

  page(o)
end
detail_timer(id) click to toggle source
# File lib/flor/tools/shell.rb, line 933
def detail_timer(id)

  o = StringIO.new

  timer = @unit.timers[id.to_i]

  fail ArgumentError.new("timer #{id} not found") unless timer

  tid = { id: timer.id, exid: timer.exid, nid: timer.nid }.inspect
  timer = timer.values
  con = Flor::Storage.from_blob(timer.delete(:content))
  timer[:content] = '...'

  o.puts @c.dg("--- timer #{tid} :")
  o.puts Flor.to_d(timer, colour: true, indent: 1, width: true)
  o.puts @c.dg("--- timer #{tid} content:")
  o.puts Flor.to_d(con, colour: true, indent: 1, width: true)

  page(o)
end
do_eval(line) click to toggle source
# File lib/flor/tools/shell.rb, line 170
def do_eval(line)

  line = line.match(/\A([^#]*)(#.+)?\n*\z/)[1]
  return if line == ''

  md = line.split(/\s/).first
  cmd = "cmd_#{md}".to_sym

  if cmd.size > 4 && methods.include?(cmd)
    begin
      send(cmd, line)
    rescue ArgumentError => aerr
      puts @c.dark_gray(aerr.message)
    rescue StandardError, NotImplementedError => err
      p err
      err.backtrace[0, 7].each { |l| puts "  #{l}" }
    end
  else
    puts "unknown command #{md.inspect}"
  end
end
do_loop() click to toggle source
# File lib/flor/tools/shell.rb, line 192
def do_loop

  loop do

    line = prompt_and_read

    break unless line

    do_eval(line)
  end

  $stdout.puts
end
fname(line, index=1)
Alias for: arg
h_to_table(h) click to toggle source
# File lib/flor/tools/shell.rb, line 882
def h_to_table(h)

  table = Terminal::Table.new(
    headings: %w[ key value ],
    style: table_style)#.merge(all_separators: true))
  h.each do |k, v|
    table.add_row([ k, Flor.to_d(v, colour: true, indent: 0, width: 65) ])
  end

  table
end
hlp_cancel() click to toggle source
# File lib/flor/tools/shell.rb, line 1005
def hlp_cancel
  %{ cancel an execution node }
end
hlp_cat() click to toggle source
# File lib/flor/tools/shell.rb, line 602
def hlp_cat
  %{ prints the current flow }
end
hlp_conf() click to toggle source
# File lib/flor/tools/shell.rb, line 617
def hlp_conf
  %{ prints or sets in current unit configuration }
end
hlp_debug() click to toggle source
# File lib/flor/tools/shell.rb, line 821
def hlp_debug
  %{ re-sets debug flags }
end
hlp_detail() click to toggle source
# File lib/flor/tools/shell.rb, line 975
def hlp_detail
  %{ detail an execution, a task or a timer }
end
hlp_edit() click to toggle source
# File lib/flor/tools/shell.rb, line 571
def hlp_edit
  %{ edit vars, payload, flow or a task }
end
hlp_executions() click to toggle source
# File lib/flor/tools/shell.rb, line 712
def hlp_executions
  %{ lists the executions currently active }
end
hlp_exit() click to toggle source
# File lib/flor/tools/shell.rb, line 531
def hlp_exit
  %{ exits this repl, with the given int exit code or 0 }
end
hlp_flosh() click to toggle source
# File lib/flor/tools/shell.rb, line 1122
def hlp_flosh
  %{ displays flosh explanation }
end
hlp_help() click to toggle source
# File lib/flor/tools/shell.rb, line 482
def hlp_help
  %{ displays this help }
end
hlp_hook() click to toggle source
# File lib/flor/tools/shell.rb, line 846
def hlp_hook
  %{ turns hook for "failed"/"terminated" messages on or off }
end
hlp_launch() click to toggle source
# File lib/flor/tools/shell.rb, line 455
def hlp_launch
  %{ launches a new execution of #{@flow_path} }
end
hlp_page() click to toggle source
# File lib/flor/tools/shell.rb, line 408
def hlp_page
  %{ pages the output of the remainder of the command line }
end
hlp_paging() click to toggle source

the commands

# File lib/flor/tools/shell.rb, line 367
def hlp_paging
  %{ sets the paging mode }
end
hlp_parse() click to toggle source
# File lib/flor/tools/shell.rb, line 539
def hlp_parse
  %{ parses #{@flow_path} and displays the resulting tree }
end
hlp_read() click to toggle source
# File lib/flor/tools/shell.rb, line 395
def hlp_read
  %{ reads (pages) a file }
end
hlp_reapply() click to toggle source
# File lib/flor/tools/shell.rb, line 1102
def hlp_reapply
  %{ reapply at a given node with tree ra_sratch.flo }
end
hlp_render() click to toggle source
# File lib/flor/tools/shell.rb, line 1050
def hlp_render
  %{ render execution tree with error and tasks locations }
end
hlp_return() click to toggle source
# File lib/flor/tools/shell.rb, line 787
def hlp_return
  %{ returns a task to the unit }
end
hlp_t() click to toggle source
# File lib/flor/tools/shell.rb, line 651
def hlp_t
  %{ prints the file hierarchy for #{@root} }
end
hlp_tasks() click to toggle source
# File lib/flor/tools/shell.rb, line 659
def hlp_tasks
  %{ lists the tasks currently under var/tasks/ }
end
hlp_timers() click to toggle source
# File lib/flor/tools/shell.rb, line 756
def hlp_timers
  %{ list the timers currently active }
end
hlp_vi() click to toggle source
# File lib/flor/tools/shell.rb, line 439
def hlp_vi
  %{ runs the remainder of the command line and then edit output in vi }
end
indent(s, o) click to toggle source
# File lib/flor/tools/shell.rb, line 872
def indent(s, o)

  io = StringIO.new
  o.to_s.split("\n").each do |line|
    io.print(s); io.puts(line)
  end

  io.string
end
load_floshrc() click to toggle source
# File lib/flor/tools/shell.rb, line 126
def load_floshrc

  @mute = true

  [
    File.join(@root, 'etc/floshrc'),
    File.join(@root, 'home/.floshrc'),
    '.floshrc'
  ].each { |f| (File.readlines(f) rescue []).each { |l| do_eval(l) } }

ensure

  @mute = false
end
lookup_execution(id) click to toggle source
# File lib/flor/tools/shell.rb, line 894
def lookup_execution(id)

  if id.match(/\A\d+\z/)
    @unit.executions[id.to_i] ||
    fail(ArgumentError.new("execution #{id} not found"))
  else
    @unit.executions.first(Sequel.like(:exid, "%#{id}%")) ||
    fail(ArgumentError.new("execution matching \"%#{id}%\" not found"))
  end
end
lookup_exid_nid(line) click to toggle source
# File lib/flor/tools/shell.rb, line 284
def lookup_exid_nid(line)

  a, b = [ arg(line, 1), arg(line, 2) ]

  fail ArgumentError.new(
    "please specify an exid fragment and a full nid"
  ) unless b

  exid, nid = a.match(/\A[0-9_]+\z/) ? [ b, a ] : [ a, b ]

  onid = nid

  exes = @unit.executions
    .select(:exid, :content)
    .where(Sequel.like(:exid, "%#{exid}%"))
    .where(status: 'active')
    .all

  fail ArgumentError.new(
    "found no execution matching \"%#{exid}%\""
  ) if exes.empty?

  exe = exes
    .find { |e| e.data['nodes'][nid] }

  fail ArgumentError.new(
    "found #{exes.count} execution#{exes.count != 1 ? 's' : ''} " +
    "matching \"%#{exid}%\", but none with a #{onid.inspect} node"
  ) unless exe

  [ exe.exid, nid ]
end
man_cancel() click to toggle source
# File lib/flor/tools/shell.rb, line 1008
def man_cancel
  %{
    * cancel exid_fragment nid
      cancel the first node that matches
    * cancel exid_fragment 0
      cancel the first execution that matches
  }
end
man_cat() click to toggle source
# File lib/flor/tools/shell.rb, line 605
def man_cat
  %{
    * cat
      prints the current flow
  }
end
man_conf() click to toggle source
# File lib/flor/tools/shell.rb, line 620
def man_conf
  %{
    * conf
      prints current unit configuration
    * conf key
      prints value for a single key
    * conf key value
      sets value for key
  }
end
man_debug() click to toggle source
# File lib/flor/tools/shell.rb, line 824
def man_debug
  %{
    * debug off
      mute unit activity
    * debug on
      verbose unit activity
  }
end
man_detail() click to toggle source
# File lib/flor/tools/shell.rb, line 978
def man_detail
  %{
    * detail e|execution id|frag
      displays full execution information
    * detail ti|timer id
      displays full timer information
    * detail t|task frag
      displays task
  }
end
man_edit() click to toggle source
# File lib/flor/tools/shell.rb, line 574
def man_edit
  %{
    * edit v|variables
      edits the variables for the next execution
    * edit p|payload
      edits the payload for the next execution
    * edit [f|flow]
      edits the flow for the next execution
    * edit [e|exe] frag
      edits the execution data
    * edit [e|exe] frag force
      edits the execution data (redump the data)
    * edit t|task frag
      edits a task currently under var/tasks/
    * edit r
      edits the flow for re-applying
  }
end
man_executions() click to toggle source
# File lib/flor/tools/shell.rb, line 715
def man_executions
  %{
    * executions
      lists all the executions currently active
    * executions all
      lists all the executions
  }
end
man_flosh() click to toggle source
# File lib/flor/tools/shell.rb, line 1125
def man_flosh
  %{
    * flosh
      displays flosh explanation
  }
end
man_help() click to toggle source
# File lib/flor/tools/shell.rb, line 485
def man_help
  %{
    * help|man
      displays the list of commands and one-line help for each of them
    * help|man cmd
      displays the "manual" for the given command
  }
end
man_hook() click to toggle source
# File lib/flor/tools/shell.rb, line 849
def man_hook
  %{
    * hook on
      hook off, "failed" or "terminated" messages will get printed
      (asynchronously) to console
    * hook off
      messages will not get printed
  }
end
man_launch() click to toggle source
# File lib/flor/tools/shell.rb, line 458
def man_launch
  %{
    * launch
      launches an execution of the current flow
    * launch k0: v0, k1: v1, ...
      launches an execution with the given variables
  }
end
man_page() click to toggle source
# File lib/flor/tools/shell.rb, line 411
def man_page
  %{
    * page filepath
      reads the file and pages it
    * page command arg0 arg1 ... argN
      runs `command arg0 arg1 ... argN` and pages its output
  }
end
man_paging() click to toggle source
# File lib/flor/tools/shell.rb, line 370
def man_paging
  %{
    * paging off
      disable paging, command output will always be output to stdout
    * paging on
      enable paging, command output longer than terminal height will be paged
    * paging vi|vim
      always page into vim, whatever length, loses the colours
    * paging more|less
      always page into vim, whatever length, loses the colours
  }
end
man_parse() click to toggle source
# File lib/flor/tools/shell.rb, line 542
def man_parse
  %{
    * parse
      parses current #{@flow_path} and render with nids (best)
    * parse d|raw
      parses current #{@flow_path} and render with `.to_djan`
    * parse pp
      parses current #{@flow_path} and render with `pp`
  }
end
man_read() click to toggle source
# File lib/flor/tools/shell.rb, line 398
def man_read
  %{
    * read filename
      reads (pages) a file
  }
end
man_reapply() click to toggle source
# File lib/flor/tools/shell.rb, line 1105
def man_reapply
  %{
    * reapply exid_fragment nid
  }
end
man_render() click to toggle source
# File lib/flor/tools/shell.rb, line 1053
def man_render
  %{
    * render frag
      finds first execution matching fragment and renders its tree
      highlight current tasks positions
  }
end
man_return() click to toggle source
# File lib/flor/tools/shell.rb, line 790
def man_return
  %{
    * return fragment
      given a task filename fragment (for example "ache-0_0")
      reads the task payload and returns it to the unit (making the
      execution go on)
  }
end
man_tasks() click to toggle source
# File lib/flor/tools/shell.rb, line 662
def man_tasks
  %{
    * tasks
      lists all tasks currently under var/tasks/{tasker}/
    * tasks frag
      lists all tasks whose filename matches the frag
  }
end
man_vi() click to toggle source
# File lib/flor/tools/shell.rb, line 442
def man_vi
  %{
    * vi filepath
      reads the file and edits it
    * vi command arg0 arg1 ... argN
      runs `command arg0 arg1 ... argN` and opens its output with vi
  }
end
page(o) click to toggle source
# File lib/flor/tools/shell.rb, line 343
def page(o)

  return if @mute

  s = o.is_a?(String) ? o : o.string

  if @paging == false
    page_puts(s)
  elsif @paging == :vi
    page_vi(s)
  elsif @paging == :more
    page_more(s)
  else
    if s.lines.to_a.size > IO.console.winsize[0]
      page_more(s)
    else
      page_puts(s)
    end
  end
end
page_more(s) click to toggle source
# File lib/flor/tools/shell.rb, line 336
def page_more(s)
  IO.popen(
    @unit.conf['fls_more'] || 'less -R -N',
    mode: 'w'
  ) { |io| io.write(s) }
end
page_puts(s) click to toggle source
# File lib/flor/tools/shell.rb, line 327
def page_puts(s)
  ::Kernel.puts s
end
page_vi(s) click to toggle source
# File lib/flor/tools/shell.rb, line 330
def page_vi(s)
  IO.popen(
    @unit.conf['fls_vi'] || 'vi -',
    mode: 'w'
  ) { |io| io.write(Flor.decolour(s)) }
end
parse_single_json_value(s) click to toggle source
# File lib/flor/tools/shell.rb, line 66
def parse_single_json_value(s)

  Flor::ConfExecutor.interpret_line(s) rescue nil
end
prepare_db() click to toggle source
# File lib/flor/tools/shell.rb, line 85
def prepare_db

  @unit.storage.delete_tables if @unit.conf['sto_uri'].match(/memory/)
  @unit.storage.migrate unless @unit.storage.ready?
end
prepare_home() click to toggle source
# File lib/flor/tools/shell.rb, line 71
def prepare_home

  home = File.join(@root, 'home')
  return unless Dir.exists?(home)

  %w[ payload.json scratch.flo variables.json ].each do |fn|

    hfn = File.join(home, fn); next if File.exists?(hfn)

    FileUtils.cp(hfn + '.template', hfn)
    puts ".. prepared #{hfn}"
  end
end
prepare_hooks() click to toggle source
# File lib/flor/tools/shell.rb, line 91
def prepare_hooks

  @unit.hook do |message|

    if @hook == 'off'

      # do nothing

    elsif ! message['consumed']

      # do nothing

    elsif %w[ terminated failed ].include?(message['point'])

      sleep 0.4 # let eventual debug print its stuff

      message['payload'] = message.delete('payload')
      message['consumed'] = message.delete('consumed')
        # reorganize to make payload/consumed stand out

      #puts Flor.to_d(message, colour: true, indent: 1, width: true)
      #puts Flor.to_d(message, colour: true)

      c = Flor.colours
      s = StringIO.new
      s << c.dg("\n  /---\n")
      message.each do |k, v|
        s << c.dg << ('  | ') << k << ': ' << v.inspect << c.rs << "\n"
      end
      s << c.dg("  \\---")
      puts s.string
    end
  end
end
print(o) click to toggle source
print_header() click to toggle source
prompt() click to toggle source
# File lib/flor/tools/shell.rb, line 149
def prompt

  root = @c.dark_gray(@root + '/')

  time = Time.now.strftime(' %H:%M:%S')

  ec = @unit.executions.where(status: 'active').count
  exes = ' ' + @c.yellow("ex#{ec}")

  ti = @unit.timers.where(status: 'active').count
  tis = ti > 0 ? ' ' + @c.yellow("ti#{ti}") : ''

  ta = nil
  if Dir.exist?(File.join(@root, 'var/tasks'))
    ta = Dir[File.join(@root, 'var/tasks/**/*.json')].count
  end
  tas = ta > 0 ? ' ' + @c.yellow("ta#{ta}") : ''

  "#{root}#{time}#{exes}#{tis}#{tas} > "
end
prompt_and_read() click to toggle source
# File lib/flor/tools/shell.rb, line 1162
def prompt_and_read
  Readline.readline(prompt, true)
end
puts(o) click to toggle source
# File lib/flor/tools/shell.rb, line 322
def puts(o)

  ::Kernel.puts(o) unless @mute
end
render_node(o, t, nid) click to toggle source
# File lib/flor/tools/shell.rb, line 1026
    def render_node(o, t, nid)

      ni = nid
      head = t[0]
      h = t.last.is_a?(Hash) ? t.last : {}
      if h[:node]
      else
        ni = @c.dark_gray(ni)
        head = @c.dark_gray(head)
      end
      if h[:tasker]
#p h[:tasker]
        rest = @c.green("  <--")
      end

      o.puts "  #{ni} #{head}#{rest}"

      return unless t[1].is_a?(Array)

      t[1].each_with_index do |ct, i|
        render_node(o, t[1][i], "#{nid}_#{i}")
      end
    end
table_style() click to toggle source
# File lib/flor/tools/shell.rb, line 272
def table_style

  { border_x: "#{@c.dg}-#{@c.rs}",
    border_y: "#{@c.dg}|#{@c.rs}",
    border_i: "#{@c.dg}+#{@c.rs}" }
end