envo 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/bin/envo-install +18 -0
- data/bin/envo_gen_tmp_helper.rb +50 -0
- data/bin/envo_run +30 -0
- data/lib/envo.rb +45 -0
- data/lib/envo/cli/envo.bat +11 -0
- data/lib/envo/cli/envo.sh +6 -0
- data/lib/envo/cli/help.rb +20 -0
- data/lib/envo/cli/installer_bash.rb +131 -0
- data/lib/envo/cli/installer_win_cmd.rb +96 -0
- data/lib/envo/cli/runner.rb +129 -0
- data/lib/envo/cli_parser.rb +54 -0
- data/lib/envo/cmd_clean.rb +53 -0
- data/lib/envo/cmd_copy.rb +56 -0
- data/lib/envo/cmd_list.rb +50 -0
- data/lib/envo/cmd_list_add.rb +102 -0
- data/lib/envo/cmd_list_del.rb +78 -0
- data/lib/envo/cmd_path.rb +28 -0
- data/lib/envo/cmd_reset.rb +66 -0
- data/lib/envo/cmd_run.rb +68 -0
- data/lib/envo/cmd_set.rb +76 -0
- data/lib/envo/cmd_show.rb +82 -0
- data/lib/envo/cmd_swap.rb +49 -0
- data/lib/envo/cmd_unset.rb +45 -0
- data/lib/envo/context.rb +156 -0
- data/lib/envo/error.rb +7 -0
- data/lib/envo/host.rb +24 -0
- data/lib/envo/host_shell.rb +11 -0
- data/lib/envo/logger.rb +27 -0
- data/lib/envo/parse_result.rb +9 -0
- data/lib/envo/parsed_cmd.rb +10 -0
- data/lib/envo/script_parser.rb +58 -0
- data/lib/envo/shell/bash.rb +63 -0
- data/lib/envo/shell/win_cmd.rb +47 -0
- data/lib/envo/state.rb +71 -0
- data/lib/envo/val/list_val.rb +107 -0
- data/lib/envo/val/no_val.rb +35 -0
- data/lib/envo/val/path_list_val.rb +24 -0
- data/lib/envo/val/path_val.rb +41 -0
- data/lib/envo/val/string_val.rb +40 -0
- data/lib/envo/val/val_builder.rb +59 -0
- data/lib/envo/version.rb +4 -0
- metadata +89 -0
| @@ -0,0 +1,54 @@ | |
| 1 | 
            +
            module Envo
         | 
| 2 | 
            +
              class CliParser
         | 
| 3 | 
            +
                def self.opt?(opt)
         | 
| 4 | 
            +
                  opt =~ /^-/
         | 
| 5 | 
            +
                end
         | 
| 6 | 
            +
                def self.filter_opts_front(args)
         | 
| 7 | 
            +
                  front_opts = args.take_while { |a| opt?(a) }
         | 
| 8 | 
            +
                  args.shift(front_opts.size)
         | 
| 9 | 
            +
                  front_opts
         | 
| 10 | 
            +
                end
         | 
| 11 | 
            +
                def self.filter_opts_back(args)
         | 
| 12 | 
            +
                  back_opts = args.reverse.take_while { |a| opt?(a) }.reverse
         | 
| 13 | 
            +
                  args.pop(back_opts.size)
         | 
| 14 | 
            +
                  back_opts
         | 
| 15 | 
            +
                end
         | 
| 16 | 
            +
                def self.filter_opts(args)
         | 
| 17 | 
            +
                  filter_opts_front(args) + filter_opts_back(args)
         | 
| 18 | 
            +
                end
         | 
| 19 | 
            +
                def initialize(opts)
         | 
| 20 | 
            +
                  @known_cmds = {}
         | 
| 21 | 
            +
                  @known_opts = opts
         | 
| 22 | 
            +
                end
         | 
| 23 | 
            +
                def add_cmd(name, parse_func)
         | 
| 24 | 
            +
                  raise Envo::Error "cmd #{name} is already added to parser" if @known_cmds[name]
         | 
| 25 | 
            +
                  @known_cmds[name] = parse_func
         | 
| 26 | 
            +
                end
         | 
| 27 | 
            +
                def parse(argv)
         | 
| 28 | 
            +
                  result = ParseResult.new
         | 
| 29 | 
            +
                  cmd = nil
         | 
| 30 | 
            +
                  while !argv.empty?
         | 
| 31 | 
            +
                    arg = argv.shift
         | 
| 32 | 
            +
                    if CliParser.opt?(arg)
         | 
| 33 | 
            +
                      result.opts.merge! @known_opts.parse_cli(arg)
         | 
| 34 | 
            +
                    else
         | 
| 35 | 
            +
                      break cmd = arg
         | 
| 36 | 
            +
                    end
         | 
| 37 | 
            +
                  end
         | 
| 38 | 
            +
             | 
| 39 | 
            +
                  raise Envo::Error.new 'missing command' if !cmd
         | 
| 40 | 
            +
                  raise Envo::Error.new "unknown command '#{cmd}'" if !@known_cmds[cmd]
         | 
| 41 | 
            +
             | 
| 42 | 
            +
                  parsed_cmd = @known_cmds[cmd].(cmd, argv)
         | 
| 43 | 
            +
             | 
| 44 | 
            +
                  cmd_opts = {}
         | 
| 45 | 
            +
                  parsed_cmd.opts.each do |opt|
         | 
| 46 | 
            +
                    cmd_opts.merge! @known_opts.parse_cli(opt)
         | 
| 47 | 
            +
                  end
         | 
| 48 | 
            +
                  parsed_cmd.opts = cmd_opts
         | 
| 49 | 
            +
             | 
| 50 | 
            +
                  result.cmds << parsed_cmd
         | 
| 51 | 
            +
                  result
         | 
| 52 | 
            +
                end
         | 
| 53 | 
            +
              end
         | 
| 54 | 
            +
            end
         | 
| @@ -0,0 +1,53 @@ | |
| 1 | 
            +
            module Envo
         | 
| 2 | 
            +
              class CmdClean
         | 
| 3 | 
            +
                Name = 'clean'
         | 
| 4 | 
            +
                def self.register_help(help)
         | 
| 5 | 
            +
                  help.add_cmd "clean <name> ...", <<~EOF
         | 
| 6 | 
            +
                    cleans environent variables
         | 
| 7 | 
            +
                    unsets empty strings, non-existing paths, empty lists
         | 
| 8 | 
            +
                    removes duplicates from lists and non-existing paths from path lists
         | 
| 9 | 
            +
                  EOF
         | 
| 10 | 
            +
                end
         | 
| 11 | 
            +
             | 
| 12 | 
            +
                def self.register_cli_parser(parser)
         | 
| 13 | 
            +
                  parser.add_cmd(Name, ->(cmd, args) { parse_cli(args) })
         | 
| 14 | 
            +
                end
         | 
| 15 | 
            +
             | 
| 16 | 
            +
                def self.register_script_parser(parser)
         | 
| 17 | 
            +
                  parser.add_cmd(Name, ->(cmd, tokens, opts) { parse_tokens(tokens, opts) })
         | 
| 18 | 
            +
                end
         | 
| 19 | 
            +
             | 
| 20 | 
            +
                def self.parse_cli(args)
         | 
| 21 | 
            +
                  opts = CliParser.filter_opts(args)
         | 
| 22 | 
            +
                  parse_tokens(args, opts)
         | 
| 23 | 
            +
                end
         | 
| 24 | 
            +
             | 
| 25 | 
            +
                def self.parse_tokens(tokens, opts)
         | 
| 26 | 
            +
                  ParsedCmd.new(CmdClean.new(tokens), opts)
         | 
| 27 | 
            +
                end
         | 
| 28 | 
            +
             | 
| 29 | 
            +
                def initialize(names)
         | 
| 30 | 
            +
                  raise Error.new 'clean: no names provided' if names.empty?
         | 
| 31 | 
            +
                  @names = names
         | 
| 32 | 
            +
                end
         | 
| 33 | 
            +
             | 
| 34 | 
            +
                attr_reader :names, :show_names
         | 
| 35 | 
            +
             | 
| 36 | 
            +
                def execute(ctx)
         | 
| 37 | 
            +
                  @names.each do |name|
         | 
| 38 | 
            +
                    ename = ctx.expand_name(name)
         | 
| 39 | 
            +
             | 
| 40 | 
            +
                    if ctx.raw?
         | 
| 41 | 
            +
                      val = ctx.raw_get(ename)
         | 
| 42 | 
            +
                      ctx.unset(ename) if val && val.empty?
         | 
| 43 | 
            +
                    else
         | 
| 44 | 
            +
                      val = ctx.smart_get(ename)
         | 
| 45 | 
            +
                      if val.type != :empty
         | 
| 46 | 
            +
                        val.clean!
         | 
| 47 | 
            +
                        ctx.smart_set(ename, val)
         | 
| 48 | 
            +
                      end
         | 
| 49 | 
            +
                    end
         | 
| 50 | 
            +
                  end
         | 
| 51 | 
            +
                end
         | 
| 52 | 
            +
              end
         | 
| 53 | 
            +
            end
         | 
| @@ -0,0 +1,56 @@ | |
| 1 | 
            +
            module Envo
         | 
| 2 | 
            +
              class CmdCopy
         | 
| 3 | 
            +
                Name = 'copy'
         | 
| 4 | 
            +
                def self.register_help(help)
         | 
| 5 | 
            +
                  help.add_cmd 'copy <source-name> <target-name>', <<~EOF
         | 
| 6 | 
            +
                    copy value of source to target
         | 
| 7 | 
            +
                      shorthand: 'cp'
         | 
| 8 | 
            +
                  EOF
         | 
| 9 | 
            +
                end
         | 
| 10 | 
            +
             | 
| 11 | 
            +
                def self.register_cli_parser(parser)
         | 
| 12 | 
            +
                  parser.add_cmd(Name, ->(cmd, args) { parse_cli(args) })
         | 
| 13 | 
            +
                  parser.add_cmd('cp', ->(cmd, args) { parse_cli(args) })
         | 
| 14 | 
            +
                end
         | 
| 15 | 
            +
             | 
| 16 | 
            +
                def self.register_script_parser(parser)
         | 
| 17 | 
            +
                  parser.add_cmd(Name, ->(cmd, tokens, opts) { parse_tokens(tokens, opts) })
         | 
| 18 | 
            +
                end
         | 
| 19 | 
            +
             | 
| 20 | 
            +
                def self.parse_cli(args)
         | 
| 21 | 
            +
                  opts = CliParser.filter_opts(args)
         | 
| 22 | 
            +
                  parse_tokens(args, opts)
         | 
| 23 | 
            +
                end
         | 
| 24 | 
            +
             | 
| 25 | 
            +
                def self.parse_tokens(tokens, opts)
         | 
| 26 | 
            +
                  raise Envo::Error.new "copy: provide two names to copy. Use 'copy <source-name> <target-name>'" if tokens.size != 2
         | 
| 27 | 
            +
                  ParsedCmd.new(CmdCopy.new(tokens[0], tokens[1]), opts)
         | 
| 28 | 
            +
                end
         | 
| 29 | 
            +
             | 
| 30 | 
            +
                def initialize(source, target)
         | 
| 31 | 
            +
                  @source = source
         | 
| 32 | 
            +
                  @target = target
         | 
| 33 | 
            +
                end
         | 
| 34 | 
            +
             | 
| 35 | 
            +
                attr_accessor :source, :target
         | 
| 36 | 
            +
             | 
| 37 | 
            +
                def execute(ctx)
         | 
| 38 | 
            +
                  esrc = ctx.expand_name(@source)
         | 
| 39 | 
            +
                  raw_src = ctx.raw_get(esrc)
         | 
| 40 | 
            +
                  raise Envo::Error.new "copy: no such var '#{esrc}'" if !raw_src && !ctx.force?
         | 
| 41 | 
            +
                  return if !raw_src
         | 
| 42 | 
            +
             | 
| 43 | 
            +
                  etarget = ctx.expand_name(@target)
         | 
| 44 | 
            +
                  raw_target = ctx.raw_get(etarget)
         | 
| 45 | 
            +
             | 
| 46 | 
            +
                  ok = !raw_target
         | 
| 47 | 
            +
                  ok ||= ctx.ask("'#{etarget}' already exists. Overwrite?")
         | 
| 48 | 
            +
                  raise Envo::Error.new "'#{etarget}' exists" if !ok
         | 
| 49 | 
            +
             | 
| 50 | 
            +
                  return if esrc == etarget # copy something over itself...
         | 
| 51 | 
            +
                  return if !raw_src && !raw_target # no point in doing anything if they don't exist
         | 
| 52 | 
            +
             | 
| 53 | 
            +
                  ctx.raw_set(etarget, raw_src)
         | 
| 54 | 
            +
                end
         | 
| 55 | 
            +
              end
         | 
| 56 | 
            +
            end
         | 
| @@ -0,0 +1,50 @@ | |
| 1 | 
            +
            module Envo
         | 
| 2 | 
            +
              class CmdList
         | 
| 3 | 
            +
                Name = 'list'
         | 
| 4 | 
            +
                def self.register_help(help)
         | 
| 5 | 
            +
                  help.add_cmd "list <name>", "show value of list environment variable which is a list"
         | 
| 6 | 
            +
                  help.add_cmd "list <name> add <val>", <<~EOF
         | 
| 7 | 
            +
                    add value to list if it's not already inside
         | 
| 8 | 
            +
                      --front - adds value to front of list (moves it to front if it's already inside)
         | 
| 9 | 
            +
                      --back  - adds value to back of list (moves it to back if it's already inside)
         | 
| 10 | 
            +
                  EOF
         | 
| 11 | 
            +
                  help.add_cmd "list <name> del <val|index>", <<~EOF
         | 
| 12 | 
            +
                    remove a value from a list
         | 
| 13 | 
            +
                    if the provided value is an integer, it's interpreted as an index in the list
         | 
| 14 | 
            +
                  EOF
         | 
| 15 | 
            +
                end
         | 
| 16 | 
            +
             | 
| 17 | 
            +
                def self.register_cli_parser(parser)
         | 
| 18 | 
            +
                  parser.add_cmd(Name, ->(cmd, args) { parse_cli(args) })
         | 
| 19 | 
            +
                end
         | 
| 20 | 
            +
             | 
| 21 | 
            +
                def self.parse_cli(args)
         | 
| 22 | 
            +
                  opts = CliParser.filter_opts_front(args)
         | 
| 23 | 
            +
                  raise Envo::Error.new "list: missing name. Use 'list <name> <cmd> <args>'" if args.empty?
         | 
| 24 | 
            +
                  name = args.shift
         | 
| 25 | 
            +
                  return ParsedCmd.new(CmdShow.new([name], true), opts) if args.empty? # just list <name>
         | 
| 26 | 
            +
             | 
| 27 | 
            +
                  cmd = args.shift
         | 
| 28 | 
            +
                  return CmdListAdd.parse_cli_args(name, args, opts) if cmd == 'add'
         | 
| 29 | 
            +
                  return CmdListDel.parse_cli_args(name, args, opts) if cmd == 'del'
         | 
| 30 | 
            +
             | 
| 31 | 
            +
                  raise Envo::Error.new "list: unkonwn subcommand #{cmd}"
         | 
| 32 | 
            +
                end
         | 
| 33 | 
            +
             | 
| 34 | 
            +
                def self.register_script_parser(parser)
         | 
| 35 | 
            +
                  parser.add_cmd(Name, ->(cmd, tokens, opts) { parse_script(tokens, opts) })
         | 
| 36 | 
            +
                end
         | 
| 37 | 
            +
             | 
| 38 | 
            +
                def self.parse_script(tokens, opts)
         | 
| 39 | 
            +
                  raise Envo::Error.new "list: missing name. Use 'list <name> <cmd> <args>'" if tokens.empty?
         | 
| 40 | 
            +
                  name = tokens.shift
         | 
| 41 | 
            +
                  return ParsedCmd.new(CmdShow.new([name], true), opts) if tokens.empty? # just list <name>
         | 
| 42 | 
            +
             | 
| 43 | 
            +
                  cmd = tokens.shift
         | 
| 44 | 
            +
                  return CmdListAdd.parse_script(name, tokens, opts) if cmd == 'add'
         | 
| 45 | 
            +
                  return CmdListDel.parse_tokens(name, tokens, opts) if cmd == 'del'
         | 
| 46 | 
            +
             | 
| 47 | 
            +
                  raise Envo::Error.new "list: unkonwn subcommand #{cmd}"
         | 
| 48 | 
            +
                end
         | 
| 49 | 
            +
              end
         | 
| 50 | 
            +
            end
         | 
| @@ -0,0 +1,102 @@ | |
| 1 | 
            +
            module Envo
         | 
| 2 | 
            +
              class CmdListAdd
         | 
| 3 | 
            +
                def self.register_help(help)
         | 
| 4 | 
            +
                  help.add_cmd 'la <name> <val>', "shorthand for 'list <name> add <val>'"
         | 
| 5 | 
            +
                end
         | 
| 6 | 
            +
             | 
| 7 | 
            +
                def self.register_cli_parser(parser)
         | 
| 8 | 
            +
                  parser.add_cmd('la', ->(cmd, args) { parse_cli_all(args) })
         | 
| 9 | 
            +
                end
         | 
| 10 | 
            +
             | 
| 11 | 
            +
                def self.register_script_parser(parser)
         | 
| 12 | 
            +
                end
         | 
| 13 | 
            +
             | 
| 14 | 
            +
                def self.parse_cli_all(args)
         | 
| 15 | 
            +
                  opts = CliParser.filter_opts_front(args)
         | 
| 16 | 
            +
                  raise Envo::Error.new "list-add: missing name. Use 'la <name> <val>'" if args.empty?
         | 
| 17 | 
            +
                  parse_cli_args(args[0], args[1..], opts)
         | 
| 18 | 
            +
                end
         | 
| 19 | 
            +
             | 
| 20 | 
            +
                def self.parse_script(name, tokens, opts)
         | 
| 21 | 
            +
                  pos = nil
         | 
| 22 | 
            +
                  opts.filter! do |opt|
         | 
| 23 | 
            +
                    case opt
         | 
| 24 | 
            +
                    when 'front', 'top'
         | 
| 25 | 
            +
                      pos = :front
         | 
| 26 | 
            +
                      false
         | 
| 27 | 
            +
                    when 'back', 'bottom'
         | 
| 28 | 
            +
                      pos = :back
         | 
| 29 | 
            +
                      false
         | 
| 30 | 
            +
                    else
         | 
| 31 | 
            +
                      true
         | 
| 32 | 
            +
                    end
         | 
| 33 | 
            +
                  end
         | 
| 34 | 
            +
             | 
| 35 | 
            +
                  ParsedCmd.new(CmdListAdd.new(name, tokens, pos), opts)
         | 
| 36 | 
            +
                end
         | 
| 37 | 
            +
             | 
| 38 | 
            +
                def self.parse_cli_args(name, args, opts)
         | 
| 39 | 
            +
                  opts += CliParser.filter_opts(args)
         | 
| 40 | 
            +
                  pos = nil
         | 
| 41 | 
            +
                  opts.filter! do |opt|
         | 
| 42 | 
            +
                    case opt
         | 
| 43 | 
            +
                    when '--front', '--top'
         | 
| 44 | 
            +
                      pos = :front
         | 
| 45 | 
            +
                      false
         | 
| 46 | 
            +
                    when '--back', '--bottom'
         | 
| 47 | 
            +
                      pos = :back
         | 
| 48 | 
            +
                      false
         | 
| 49 | 
            +
                    else
         | 
| 50 | 
            +
                      true
         | 
| 51 | 
            +
                    end
         | 
| 52 | 
            +
                  end
         | 
| 53 | 
            +
             | 
| 54 | 
            +
                  ParsedCmd.new(CmdListAdd.new(name, args, pos), opts)
         | 
| 55 | 
            +
                end
         | 
| 56 | 
            +
             | 
| 57 | 
            +
                def initialize(name, values, pos)
         | 
| 58 | 
            +
                  raise Envo::Error.new 'list-add: no values to add provided' if values.empty?
         | 
| 59 | 
            +
                  @name = name
         | 
| 60 | 
            +
                  @values = values
         | 
| 61 | 
            +
                  @pos = pos
         | 
| 62 | 
            +
                end
         | 
| 63 | 
            +
             | 
| 64 | 
            +
                attr_accessor :name, :values, :pos
         | 
| 65 | 
            +
             | 
| 66 | 
            +
                def execute(ctx)
         | 
| 67 | 
            +
                  ename = ctx.expand_name(@name)
         | 
| 68 | 
            +
             | 
| 69 | 
            +
                  list = ctx.smart_get(ename)
         | 
| 70 | 
            +
             | 
| 71 | 
            +
                  ok = list.list?
         | 
| 72 | 
            +
                  if !ok
         | 
| 73 | 
            +
                    if list.type == :empty
         | 
| 74 | 
            +
                      ok ||= ctx.ask("#{ename} doesn't exist. Create?")
         | 
| 75 | 
            +
                    else
         | 
| 76 | 
            +
                      ok ||= ctx.ask("#{ename} is not a list, but a #{list.type}. Convert?")
         | 
| 77 | 
            +
                    end
         | 
| 78 | 
            +
                  end
         | 
| 79 | 
            +
                  raise Envo::Error.new "list-add: adding list item to a non-list" if !ok
         | 
| 80 | 
            +
             | 
| 81 | 
            +
                  list = list.to_list
         | 
| 82 | 
            +
             | 
| 83 | 
            +
                  ordered = @pos == :front ? values.reverse : values
         | 
| 84 | 
            +
                  ordered.each do |val|
         | 
| 85 | 
            +
                    val = ctx.expand_value(val)
         | 
| 86 | 
            +
             | 
| 87 | 
            +
                    ok = list.accept_item?(val)
         | 
| 88 | 
            +
                    ok ||= ctx.ask("Add #{val.type} to #{list.type}?")
         | 
| 89 | 
            +
                    raise Envo::Error.new "list-add: adding #{val.type} to #{list.type}" if !ok
         | 
| 90 | 
            +
             | 
| 91 | 
            +
                    idesc = val.invalid_description
         | 
| 92 | 
            +
                    ok = !idesc
         | 
| 93 | 
            +
                    ok ||= ctx.ask("Add #{idesc} to #{ename}?")
         | 
| 94 | 
            +
                    raise Envo::Error.new "list-add: adding #{idesc} to #{ename}" if !ok
         | 
| 95 | 
            +
             | 
| 96 | 
            +
                    list.insert(val.to_s, @pos)
         | 
| 97 | 
            +
                  end
         | 
| 98 | 
            +
             | 
| 99 | 
            +
                  ctx.smart_set(ename, list)
         | 
| 100 | 
            +
                end
         | 
| 101 | 
            +
              end
         | 
| 102 | 
            +
            end
         | 
| @@ -0,0 +1,78 @@ | |
| 1 | 
            +
            module Envo
         | 
| 2 | 
            +
              class CmdListDel
         | 
| 3 | 
            +
                def self.register_help(help)
         | 
| 4 | 
            +
                  help.add_cmd 'ld <name> <val|index>', "shorthand for 'list <name> del <val|index>'"
         | 
| 5 | 
            +
                end
         | 
| 6 | 
            +
             | 
| 7 | 
            +
                def self.register_cli_parser(parser)
         | 
| 8 | 
            +
                  parser.add_cmd('ld', ->(cmd, args) { parse_cli_all(args) })
         | 
| 9 | 
            +
                end
         | 
| 10 | 
            +
             | 
| 11 | 
            +
                def self.register_script_parser(parser)
         | 
| 12 | 
            +
                end
         | 
| 13 | 
            +
             | 
| 14 | 
            +
                def self.parse_cli_all(args)
         | 
| 15 | 
            +
                  opts = CliParser.filter_opts_front(args)
         | 
| 16 | 
            +
                  raise Envo::Error.new "list-del: missing name. Use 'ld <name> <val|index>'" if args.empty?
         | 
| 17 | 
            +
                  parse_cli_args(args[0], args[1..], opts)
         | 
| 18 | 
            +
                end
         | 
| 19 | 
            +
             | 
| 20 | 
            +
                def self.parse_cli_args(name, args, opts)
         | 
| 21 | 
            +
                  opts += CliParser.filter_opts(args)
         | 
| 22 | 
            +
                  parse_tokens(name, args, opts)
         | 
| 23 | 
            +
                end
         | 
| 24 | 
            +
             | 
| 25 | 
            +
                def self.parse_tokens(name, tokens, opts)
         | 
| 26 | 
            +
                  raise Envo::Error.new "list-del: provide one value or index to delete. Use 'list <name> del <val|index>'" if tokens.size != 1
         | 
| 27 | 
            +
                  ParsedCmd.new(CmdListDel.new(name, tokens[0]), opts)
         | 
| 28 | 
            +
                end
         | 
| 29 | 
            +
             | 
| 30 | 
            +
                def initialize(name, value)
         | 
| 31 | 
            +
                  @name = name
         | 
| 32 | 
            +
                  @value = value
         | 
| 33 | 
            +
                end
         | 
| 34 | 
            +
             | 
| 35 | 
            +
                attr_accessor :name, :value
         | 
| 36 | 
            +
             | 
| 37 | 
            +
                def execute(ctx)
         | 
| 38 | 
            +
                  ename = ctx.expand_name(@name)
         | 
| 39 | 
            +
             | 
| 40 | 
            +
                  list = ctx.smart_get(ename)
         | 
| 41 | 
            +
             | 
| 42 | 
            +
                  if list.type == :empty
         | 
| 43 | 
            +
                    return if ctx.force?
         | 
| 44 | 
            +
                    raise Envo::Error.new "list-del: deleting an item from a non-exiting value"
         | 
| 45 | 
            +
                  end
         | 
| 46 | 
            +
             | 
| 47 | 
            +
                  ok = list.list?
         | 
| 48 | 
            +
                  ok ||= ctx.ask("#{ename} is not a list, but a #{list.type}. Convert?")
         | 
| 49 | 
            +
                  raise Envo::Error.new "list-del: deleting an item from a non-list" if !ok
         | 
| 50 | 
            +
             | 
| 51 | 
            +
                  list = list.to_list
         | 
| 52 | 
            +
             | 
| 53 | 
            +
                  val = ctx.expand_value(@value)
         | 
| 54 | 
            +
                  if val.list?
         | 
| 55 | 
            +
                    raise Envo::Error.new "list-del: can't delete a list from a list" if !ctx.force?
         | 
| 56 | 
            +
                    return
         | 
| 57 | 
            +
                  end
         | 
| 58 | 
            +
                  val = val.to_s
         | 
| 59 | 
            +
             | 
| 60 | 
            +
                  index = val.to_i
         | 
| 61 | 
            +
                  if !ctx.raw? && index.to_s == val
         | 
| 62 | 
            +
                    deleted = list.delete_at(index)
         | 
| 63 | 
            +
                    if !deleted
         | 
| 64 | 
            +
                      raise Envo::Error.new "list-del: no index #{val} in #{ename}" if !ctx.force?
         | 
| 65 | 
            +
                      return
         | 
| 66 | 
            +
                    end
         | 
| 67 | 
            +
                  else
         | 
| 68 | 
            +
                    deleted = list.delete(val)
         | 
| 69 | 
            +
                    if !deleted
         | 
| 70 | 
            +
                      raise Envo::Error.new "list-del: no item '#{val}' in #{ename}" if !deleted
         | 
| 71 | 
            +
                      return
         | 
| 72 | 
            +
                    end
         | 
| 73 | 
            +
                  end
         | 
| 74 | 
            +
             | 
| 75 | 
            +
                  ctx.smart_set(ename, list)
         | 
| 76 | 
            +
                end
         | 
| 77 | 
            +
              end
         | 
| 78 | 
            +
            end
         | 
| @@ -0,0 +1,28 @@ | |
| 1 | 
            +
            module Envo
         | 
| 2 | 
            +
              class CmdPath
         | 
| 3 | 
            +
                Name = 'path'
         | 
| 4 | 
            +
                def self.register_help(help)
         | 
| 5 | 
            +
                  help.add_cmd "path <args>", <<~EOF
         | 
| 6 | 
            +
                    shorthand for 'list @path <args>'
         | 
| 7 | 
            +
                      shorthand: 'p'
         | 
| 8 | 
            +
                  EOF
         | 
| 9 | 
            +
                end
         | 
| 10 | 
            +
             | 
| 11 | 
            +
                def self.register_cli_parser(parser)
         | 
| 12 | 
            +
                  parser.add_cmd(Name, ->(cmd, args) { parse_cli(args) })
         | 
| 13 | 
            +
                  parser.add_cmd('p', ->(cmd, args) { parse_cli(args) })
         | 
| 14 | 
            +
                end
         | 
| 15 | 
            +
             | 
| 16 | 
            +
                def self.register_script_parser(parser)
         | 
| 17 | 
            +
                  parser.add_cmd(Name, ->(cmd, tokens, opts) { parse_script(tokens, opts) })
         | 
| 18 | 
            +
                end
         | 
| 19 | 
            +
             | 
| 20 | 
            +
                def self.parse_cli(args)
         | 
| 21 | 
            +
                  CmdList.parse_cli(args.unshift('@path'))
         | 
| 22 | 
            +
                end
         | 
| 23 | 
            +
             | 
| 24 | 
            +
                def self.parse_script(tokens, opts)
         | 
| 25 | 
            +
                  CmdList.parse_script(tokens.unshift('@path'), opts)
         | 
| 26 | 
            +
                end
         | 
| 27 | 
            +
              end
         | 
| 28 | 
            +
            end
         | 
| @@ -0,0 +1,66 @@ | |
| 1 | 
            +
            module Envo
         | 
| 2 | 
            +
              class CmdReset
         | 
| 3 | 
            +
                Name = 'reset'
         | 
| 4 | 
            +
                def self.register_help(help)
         | 
| 5 | 
            +
                  help.add_cmd 'reset <name>[=[<val>]]', <<~EOF
         | 
| 6 | 
            +
                    set or unset value of an existing environment variable
         | 
| 7 | 
            +
                    produce an error if the variable doesn't exist
         | 
| 8 | 
            +
                  EOF
         | 
| 9 | 
            +
                end
         | 
| 10 | 
            +
             | 
| 11 | 
            +
                def self.register_cli_parser(parser)
         | 
| 12 | 
            +
                  parser.add_cmd(Name, ->(cmd, args) { parse_cli(args) })
         | 
| 13 | 
            +
                end
         | 
| 14 | 
            +
             | 
| 15 | 
            +
                def self.register_script_parser(parser)
         | 
| 16 | 
            +
                  parser.add_cmd(Name, ->(cmd, tokens, opts) { parse_tokens(tokens, opts) })
         | 
| 17 | 
            +
                end
         | 
| 18 | 
            +
             | 
| 19 | 
            +
                def self.parse_cli(args)
         | 
| 20 | 
            +
                  opts = CliParser.filter_opts(args)
         | 
| 21 | 
            +
                  parse_tokens(args, opts)
         | 
| 22 | 
            +
                end
         | 
| 23 | 
            +
             | 
| 24 | 
            +
                def self.parse_tokens(args, opts)
         | 
| 25 | 
            +
                  raise Envo::Error.new "reset: missing name. Use 'reset <name> [= [<val>]]'" if args.empty? || args[0][0] == '='
         | 
| 26 | 
            +
                  if args.size == 1
         | 
| 27 | 
            +
                    arg = args[0]
         | 
| 28 | 
            +
                    cnt = arg.count('=')
         | 
| 29 | 
            +
                    return ParsedCmd.new(CmdReset.new(arg, nil), opts) if cnt == 0
         | 
| 30 | 
            +
                    if cnt == 1 && arg[-1] == '='
         | 
| 31 | 
            +
                      split = arg.split('=')
         | 
| 32 | 
            +
                      return ParsedCmd.new(CmdReset.new(split[0], nil), opts) if split.size == 1
         | 
| 33 | 
            +
                    end
         | 
| 34 | 
            +
                  elsif args.size == 2
         | 
| 35 | 
            +
                    return ParsedCmd.new(CmdReset.new(args[0], nil), opts) if args[1] == '='
         | 
| 36 | 
            +
                  end
         | 
| 37 | 
            +
             | 
| 38 | 
            +
                  helper = CmdSet.parse_cli(args).cmd
         | 
| 39 | 
            +
                  ParsedCmd.new(CmdReset.new(helper.name, helper), opts)
         | 
| 40 | 
            +
                end
         | 
| 41 | 
            +
             | 
| 42 | 
            +
                def self.parse_script(args)
         | 
| 43 | 
            +
                  puts "#{Name} parse_script"
         | 
| 44 | 
            +
                end
         | 
| 45 | 
            +
             | 
| 46 | 
            +
                def initialize(name, helper)
         | 
| 47 | 
            +
                  @name = name
         | 
| 48 | 
            +
                  @helper = helper
         | 
| 49 | 
            +
                end
         | 
| 50 | 
            +
             | 
| 51 | 
            +
                attr_accessor :name, :helper
         | 
| 52 | 
            +
             | 
| 53 | 
            +
                def execute(ctx)
         | 
| 54 | 
            +
                  ename = ctx.expand_name(@name)
         | 
| 55 | 
            +
             | 
| 56 | 
            +
                  raise Envo::Error.new "reset: no such var '#{ename}'" if !ctx.raw_get(ename)
         | 
| 57 | 
            +
             | 
| 58 | 
            +
                  if !@helper
         | 
| 59 | 
            +
                    ctx.unset(ename)
         | 
| 60 | 
            +
                  else
         | 
| 61 | 
            +
                    @helper.name = @name
         | 
| 62 | 
            +
                    @helper.execute(ctx)
         | 
| 63 | 
            +
                  end
         | 
| 64 | 
            +
                end
         | 
| 65 | 
            +
              end
         | 
| 66 | 
            +
            end
         |