envo 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 54f5c8282f4d3219db6e7a5384316ed1f3fdd3e43d0e99fdfbb6d768436c8445
4
+ data.tar.gz: a9b2e63f76ae3dd5844694365f8dbdff259c3dcb485374583cbc258b3547a94e
5
+ SHA512:
6
+ metadata.gz: 8638df6a7acbd3bd61c7ea2d717308e3369091f96585367c6fcb2c7b3c88724efc9acb93a14d3e82f9b8808a6e82cb263957290a818da64c65b16d7e945f973b
7
+ data.tar.gz: 63e000afd0bf3f69394c02f221b92f910714e7e29e2f53fe2d0973e9fa201b552a514f3f68ca03f84c236db0f89ffb4fc7c8c107d5e709a129bd6f3297e9a037
@@ -0,0 +1,18 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ $LOAD_PATH.unshift File.expand_path("../lib", __dir__) # For use/testing when no gem is installed
4
+ require 'envo'
5
+
6
+ if ARGV.size == 1 && ARGV[0] == '--version'
7
+ puts "installer for envo v#{Envo::VERSION} #{Envo::VERSION_TYPE}"
8
+ exit 0
9
+ end
10
+
11
+ begin
12
+ shell = Envo::HostShell
13
+ installer = shell.installer.new
14
+ exit installer.run(ARGV.dup)
15
+ rescue Envo::Error => e
16
+ STDERR.puts e.message
17
+ exit 1
18
+ end
@@ -0,0 +1,50 @@
1
+ # this is the proper method
2
+ # however we judge envo to be very low risk
3
+ # in terms of clashes, so just do the silly thing
4
+ # require 'securerandom'
5
+ # fname = SecureRandom.uuid
6
+
7
+ # silly thing
8
+ fname = "envo-" + Time.now.to_i.to_s(16) + '-' + rand(1_000_000).to_s(16) + ".bat"
9
+ # yes, simply always add the .bat extension. Linux doesn't care anyway
10
+
11
+ # the ultimate multi-platform temp dir finder
12
+ # again, the proper way would be to require 'rbconfig'
13
+ # find the os, and use OS-specific ways, but we're trying to be fast here
14
+
15
+ def temp_dirs(&block)
16
+ yield 'C:/windows/system32'
17
+ yield '/tmp' # most unixes
18
+ yield ENV['TMP'] # good guess for windows
19
+ yield '/var/tmp'
20
+ yield ENV['TEMP']
21
+ yield ENV['TEMPDIR']
22
+ yield Dir.home
23
+ yield __dir__ # why not
24
+ yield Dir.pwd # last resort
25
+ end
26
+
27
+ def existing_temp_dirs(&block)
28
+ temp_dirs do |dir|
29
+ yield dir if dir && File.exist?(dir)
30
+ end
31
+ end
32
+
33
+ existing_temp_dirs do |dir|
34
+ path = File.join(dir, fname)
35
+
36
+ begin
37
+ File.open(path, 'w') {}
38
+ # on windows fix path in order for 'del' to work
39
+ path.gsub!(File::SEPARATOR, File::ALT_SEPARATOR) if File::ALT_SEPARATOR
40
+ puts path
41
+ exit 0
42
+ rescue
43
+ # just try the next entry
44
+ end
45
+ end
46
+
47
+ STDERR.puts "ERROR: Could not create envo temp file"
48
+ # write something just so the rest can continue up to the point where this file needs to be written
49
+ puts 'error.bat'
50
+ exit 1
@@ -0,0 +1,30 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ if ARGV.size == 1 && ARGV[0] == 'g'
4
+ require_relative 'envo_gen_tmp_helper'
5
+ end
6
+
7
+ argv = ARGV.dup
8
+
9
+ if argv.size < 2 || argv.shift != 'pld'
10
+ STDERR.puts <<~ERR
11
+ envo_run needs to be called from envo
12
+ if you don't have the command 'envo', run 'envo-install'
13
+ ERR
14
+ exit 1
15
+ end
16
+
17
+ payload_path = argv.shift
18
+ payload = File.open(payload_path, 'w')
19
+
20
+ $LOAD_PATH.unshift File.expand_path("../lib", __dir__) # For use/testing when no gem is installed
21
+ require "envo"
22
+
23
+ begin
24
+ host = Envo::Host.new(Envo::HostShell)
25
+ r = Envo::Cli::Runner.new(host, payload)
26
+ exit r.run(argv)
27
+ rescue Envo::Error => e
28
+ STDERR.puts e.message
29
+ exit 1
30
+ end
@@ -0,0 +1,45 @@
1
+ $LOAD_PATH.unshift __dir__ # For use/testing when no gem is installed
2
+
3
+ module Envo
4
+ autoload :VERSION, "envo/version"
5
+ autoload :Error, "envo/error"
6
+ autoload :NoVal, "envo/val/no_val"
7
+ autoload :StringVal, "envo/val/string_val"
8
+ autoload :ListVal, "envo/val/list_val"
9
+ autoload :PathVal, "envo/val/path_val"
10
+ autoload :PathListVal, "envo/val/path_list_val"
11
+ autoload :CmdSet, "envo/cmd_set"
12
+ autoload :CmdReset, "envo/cmd_reset"
13
+ autoload :CmdUnset, "envo/cmd_unset"
14
+ autoload :CmdListAdd, "envo/cmd_list_add"
15
+ autoload :CmdListDel, "envo/cmd_list_del"
16
+ autoload :CmdShow, "envo/cmd_show"
17
+ autoload :CmdSwap, "envo/cmd_swap"
18
+ autoload :CmdRun, "envo/cmd_run"
19
+ autoload :CmdList, "envo/cmd_list"
20
+ autoload :CmdPath, "envo/cmd_path"
21
+ autoload :CmdClean, "envo/cmd_clean"
22
+ autoload :CmdCopy, "envo/cmd_copy"
23
+ autoload :State, "envo/state"
24
+ autoload :ValBuilder, "envo/val/val_builder"
25
+ autoload :Context, "envo/context"
26
+ autoload :ParsedCmd, "envo/parsed_cmd"
27
+ autoload :CliParser, "envo/cli_parser"
28
+ autoload :ScriptParser, "envo/script_parser"
29
+ autoload :HostShell, "envo/host_shell"
30
+ autoload :Host, "envo/host"
31
+ autoload :ParseResult, "envo/parse_result"
32
+ autoload :Logger, "envo/logger"
33
+
34
+ module Shell
35
+ autoload :Bash, 'envo/shell/bash'
36
+ autoload :WinCmd, 'envo/shell/win_cmd'
37
+ end
38
+
39
+ module Cli
40
+ autoload :Runner, 'envo/cli/runner'
41
+ autoload :Help, 'envo/cli/help'
42
+ autoload :InstallerWinCmd, 'envo/cli/installer_win_cmd'
43
+ autoload :InstallerBash, 'envo/cli/installer_bash'
44
+ end
45
+ end
@@ -0,0 +1,11 @@
1
+ @echo off
2
+ :: we can't use `setlocal` here, since we actually WANT to leak
3
+ :: after all, this script is supposed to set env vars
4
+ :: however in order to get the result of `run g` we need to assign it to
5
+ :: a local var... which we must leak :(
6
+ :: so... just choose the a very unlikely duplicate var name
7
+ for /f "delims=" %%A in ('envo_run g') do set _ENVO_PLD=%%A
8
+
9
+ envo_run pld "%_ENVO_PLD%" %*
10
+ call "%_ENVO_PLD%"
11
+ del "%_ENVO_PLD%"
@@ -0,0 +1,6 @@
1
+ envo() {
2
+ local tmpfile=$(envo_run g)
3
+ envo_run pld "${tmpfile}" "$@"
4
+ source "${tmpfile}"
5
+ rm "${tmpfile}"
6
+ }
@@ -0,0 +1,20 @@
1
+ module Envo
2
+ module Cli
3
+ class Help
4
+ def initialize
5
+ @commands = []
6
+ end
7
+ def add_cmd(usage, text)
8
+ @commands << [usage, text]
9
+ end
10
+ def print(stream)
11
+ @commands.each do |cmd|
12
+ stream.puts " * #{cmd[0]}"
13
+ cmd[1].each_line do |line|
14
+ stream.puts " #{line}"
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,131 @@
1
+ # require 'open3'
2
+
3
+ module Envo
4
+ module Cli
5
+ class InstallerBash
6
+ # def detect_installed_envo?()
7
+ # stdout, stderr, code = Open3.capture3("bash -ic 'command -v envo'")
8
+ # code.success?
9
+ # end
10
+
11
+ ENVO_INSTALLATION_BEGIN = '### BEGIN envo installation (don\'t remove line)'
12
+ ENVO_INSTALLATION_END = '### END envo installation (don\'t remove line)'
13
+
14
+ def find_existing_installation_data(dotfile)
15
+ return nil if !File.exist?(dotfile)
16
+
17
+ raise Envo::Error.new "'#{dotfile}' exists but is not a file. You need to choose a file." if !File.file?(dotfile)
18
+
19
+ lines = File.readlines(dotfile)
20
+ first = nil
21
+ last = nil
22
+ lines.each_with_index do |l, i|
23
+ lc = l.chomp
24
+ if lc == ENVO_INSTALLATION_BEGIN
25
+ first = i
26
+ elsif lc == ENVO_INSTALLATION_END
27
+ last = i
28
+ end
29
+ end
30
+
31
+ return nil if !first && !last
32
+
33
+ if !first || !last
34
+ raise Envo::Error.new <<~EOF
35
+ #{dotfile}' contains a broken confy insallation.
36
+ You need to remove it manually
37
+ EOF
38
+ end
39
+
40
+ num = last - first + 1
41
+ return {first: first, num: num, lines: lines}
42
+ end
43
+
44
+ SOURCE_FILE = 'envo.sh'
45
+ def try_install(dotfile)
46
+ install_lines = [
47
+ ENVO_INSTALLATION_BEGIN,
48
+ "### envo #{VERSION}",
49
+ File.read(File.join(__dir__, SOURCE_FILE)),
50
+ ENVO_INSTALLATION_END
51
+ ]
52
+
53
+ found = find_existing_installation_data(dotfile)
54
+
55
+ openmode = 'a'
56
+ if found
57
+ lines = found[:lines]
58
+ lines[found[:first], found[:num]] = install_lines
59
+ install_lines = lines
60
+ openmode = 'w'
61
+ end
62
+
63
+ File.open(dotfile, openmode) { |f| f.puts install_lines }
64
+ puts <<~EOF
65
+ Sucessfully installed confy to '#{dotfile}'
66
+ Source the file, or restart the bash session if the file is auto-sourced.
67
+ EOF
68
+ end
69
+
70
+ def try_uninstall(dotfile)
71
+ found = find_existing_installation_data(dotfile)
72
+ if !found || found[:num] == 0
73
+ raise Envo::Error.new "'#{dotfile}' doesn't seem to contain an envo installation"
74
+ end
75
+
76
+ lines = found[:lines]
77
+ lines[found[:first], found[:num]] = []
78
+ File.open(dotfile, 'w') { |f| f.puts lines }
79
+ puts "Suncessfully uninstalled confy from '#{dotfile}'"
80
+ end
81
+
82
+ DEFAULT_DOTFILE = File.join(Dir.home, '.bashrc')
83
+ USAGE = <<~EOF
84
+ usage: envo-install [u] [--dotfile <path>]
85
+ EOF
86
+ def run(argv)
87
+ if argv.empty?
88
+ try_install(DEFAULT_DOTFILE)
89
+ return 0
90
+ end
91
+
92
+ if argv[0] == '--help' || argv[0] == '-?'
93
+ puts "installer for envo v#{Envo::VERSION} #{Envo::VERSION_TYPE}"
94
+ puts USAGE
95
+ puts
96
+ puts ' u - uninstall envo'
97
+ puts ' --dotfile <file> - install to or uninstall form a specified dotfile'
98
+ return 0
99
+ end
100
+
101
+ if argv[0] == 'u'
102
+ @uninstalling = true
103
+ argv.shift
104
+ end
105
+
106
+ dotfile = DEFAULT_DOTFILE
107
+ if !argv.empty?
108
+ arg = argv.shift
109
+ if arg != '--dotfile'
110
+ STDERR.puts "Unknown argument #{arg}"
111
+ STDERR.puts USAGE
112
+ return 1
113
+ end
114
+ if argv.empty?
115
+ STDERR.puts "Missing dotfile path"
116
+ STDERR.puts USAGE
117
+ return 1
118
+ end
119
+ dotfile = argv.shift
120
+ end
121
+
122
+ # if detect_installed_envo?
123
+ # puts "It seems that you already have envo installed"
124
+ # puts "Do you want to reinstall it? (y/n)"
125
+ # end
126
+ @uninstalling ? try_uninstall(dotfile) : try_install(dotfile)
127
+ return 0
128
+ end
129
+ end
130
+ end
131
+ end
@@ -0,0 +1,96 @@
1
+ module Envo
2
+ module Cli
3
+ class InstallerWinCmd
4
+ def each_path_dir
5
+ ENV["Path"].split(';').each { |p| yield p }
6
+ end
7
+
8
+ ENVO_RUN_CMD = "envo_run"
9
+ INSTALL_FILE = "envo.bat"
10
+ SOURCE_FILE = "envo.bat"
11
+
12
+ def try_install(path)
13
+ if !path
14
+ each_path_dir do |dir|
15
+ if File.file?(File.join(dir, ENVO_RUN_CMD))
16
+ path = dir
17
+ break
18
+ end
19
+ end
20
+ raise Error.new("Couldn't find a good place to install envo. Please use '--path <path>' to provide one") if !path
21
+ end
22
+ raise Error.new("'#{path}' is not an existing directory") if !File.directory?(path)
23
+
24
+ src = File.read(File.join(__dir__, SOURCE_FILE))
25
+ target = File.join(path, INSTALL_FILE)
26
+ File.open(target, 'w') do |f|
27
+ f.puts ":: envo #{VERSION}"
28
+ f.write(src)
29
+ end
30
+ puts "Successfully installed #{target}"
31
+ end
32
+
33
+ def try_uninstall(path)
34
+ if path
35
+ file = File.join(path, INSTALL_FILE)
36
+ raise Error.new "Couldn't find an existing envo installation in #{path}" if !File.file?(file)
37
+ File.delete(file)
38
+ puts "Sucessfully uninstalled #{file}"
39
+ return
40
+ else
41
+ each_path_dir do |dir|
42
+ file = File.join(dir, INSTALL_FILE)
43
+ next if !File.file?(file)
44
+ File.delete(file)
45
+ puts "Sucessfully uninstalled #{file}"
46
+ return
47
+ end
48
+ end
49
+ raise Error.new "Couldn't find an existing envo installation to uninstall"
50
+ end
51
+
52
+ USAGE = <<~EOF
53
+ usage: envo-install [u] [--path <path>]
54
+ EOF
55
+ def run(argv)
56
+ if argv.empty?
57
+ try_install(nil)
58
+ return 0
59
+ end
60
+
61
+ if argv[0] == '--help' || argv[0] == '-?'
62
+ puts "installer for envo v#{Envo::VERSION} #{Envo::VERSION_TYPE}"
63
+ puts USAGE
64
+ puts
65
+ puts ' u - uninstall envo'
66
+ puts ' --path <path> - install to or uninstall form a specified directory'
67
+ return 0
68
+ end
69
+
70
+ if argv[0] == 'u'
71
+ @uninstalling = true
72
+ argv.shift
73
+ end
74
+
75
+ path = nil
76
+ if !argv.empty?
77
+ arg = argv.shift
78
+ if arg != '--path'
79
+ STDERR.puts "Unknown argument #{arg}"
80
+ STDERR.puts USAGE
81
+ return 1
82
+ end
83
+ if argv.empty?
84
+ STDERR.puts "Missing path"
85
+ STDERR.puts USAGE
86
+ return 1
87
+ end
88
+ path = argv.shift
89
+ end
90
+
91
+ @uninstalling ? try_uninstall(path) : try_install(path)
92
+ return 0
93
+ end
94
+ end
95
+ end
96
+ end
@@ -0,0 +1,129 @@
1
+ module Envo
2
+ module Cli
3
+ class Runner
4
+ def initialize(host, payload)
5
+ @host = host
6
+ @payload = payload
7
+ end
8
+ attr_reader :host, :payload
9
+
10
+ VERSION_TEXT = "envo v#{Envo::VERSION} #{Envo::VERSION_TYPE}"
11
+ USAGE = <<~EOF
12
+ usage: envo [--version] [--help] <command> [<args>]
13
+ EOF
14
+
15
+ module Opts
16
+ extend self
17
+ def parse_cli(opt)
18
+ case opt
19
+ when '--force', '-f' then return {interact: :force}
20
+ when '--no-force', '-nf' then return {interact: :noforce}
21
+ when '--interactive' then return {interact: :interact}
22
+ when '--raw', '-r' then return {raw: true}
23
+ else raise Envo::Error.new "unknown command line option: #{opt}"
24
+ end
25
+ end
26
+ def print_arg(log, arg, text)
27
+ log.puts " #{arg.ljust(15)} - #{text}"
28
+ end
29
+ def print_help(log)
30
+ print_arg log, '--force, -f', 'force the execution of the command disregarding checks'
31
+ print_arg log, '--interactive', '(default) ask a question when a check fails'
32
+ print_arg log, '--no-force, -nf', 'produce an error instead of asking questions for checks'
33
+ print_arg log, '--raw, -r', 'don\'t infer types and treat each value as a raw string'
34
+ end
35
+ Defaults = {
36
+ interact: :interact,
37
+ log_level: Logger::INFO
38
+ }
39
+ end
40
+
41
+ Commands = [
42
+ CmdShow,
43
+ CmdSet,
44
+ CmdReset,
45
+ CmdUnset,
46
+ CmdList,
47
+ CmdListAdd,
48
+ CmdListDel,
49
+ CmdClean,
50
+ CmdCopy,
51
+ CmdSwap,
52
+ CmdPath,
53
+ CmdRun,
54
+ ]
55
+
56
+ def print_version
57
+ @log.puts VERSION_TEXT
58
+ end
59
+
60
+ def print_help
61
+ print_version
62
+ @log.puts USAGE
63
+ @log.puts ''
64
+ @log.puts 'Commands:'
65
+ help = Help.new
66
+ Commands.each do |cmd|
67
+ cmd.register_help(help)
68
+ end
69
+ help.print(@log)
70
+ @log.puts ''
71
+ @log.puts 'Common options:'
72
+ Opts.print_help(@log)
73
+ end
74
+
75
+ def check_help_ver(argv)
76
+ raise Error.new USAGE if argv.empty?
77
+ case argv[0]
78
+ when '--help', '-h', '-?'
79
+ print_help
80
+ true
81
+ when '--version'
82
+ print_version
83
+ true
84
+ else
85
+ false
86
+ end
87
+ end
88
+
89
+ def do_run(argv)
90
+ return if check_help_ver(argv)
91
+
92
+ parser = CliParser.new(Opts)
93
+ Commands.each { |cmd| cmd.register_cli_parser(parser) }
94
+ parsed = parser.parse(argv)
95
+
96
+ ctx = Context.new(@host, @log, Opts::Defaults)
97
+ ctx.execute(parsed)
98
+
99
+ patch = ctx.state.diff
100
+
101
+ return if patch.empty?
102
+
103
+ patch.removed.each { |name|
104
+ @payload.puts @host.shell.cmd_unset_env_var(name)
105
+ puts @host.shell.cmd_unset_env_var(name)
106
+ }
107
+ patch.changed.each { |name, val|
108
+ @payload.puts @host.shell.cmd_set_env_var(name, val)
109
+ puts @host.shell.cmd_set_env_var(name, val)
110
+ }
111
+ patch.added.each { |name, val|
112
+ @payload.puts @host.shell.cmd_set_env_var(name, val)
113
+ puts @host.shell.cmd_set_env_var(name, val)
114
+ }
115
+ end
116
+
117
+ def run(argv)
118
+ @log = Logger.new
119
+ begin
120
+ do_run(argv)
121
+ return 0
122
+ rescue Error => e
123
+ @log.error e.message
124
+ return 1
125
+ end
126
+ end
127
+ end
128
+ end
129
+ end