terraspace-bundler 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.
Files changed (52) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +17 -0
  3. data/.rspec +3 -0
  4. data/CHANGELOG.md +7 -0
  5. data/Gemfile +4 -0
  6. data/Guardfile +19 -0
  7. data/LICENSE.txt +201 -0
  8. data/README.md +82 -0
  9. data/Rakefile +6 -0
  10. data/exe/terraform-bundler +14 -0
  11. data/lib/terraspace-bundler.rb +1 -0
  12. data/lib/terraspace_bundler.rb +23 -0
  13. data/lib/terraspace_bundler/autoloader.rb +22 -0
  14. data/lib/terraspace_bundler/cli.rb +24 -0
  15. data/lib/terraspace_bundler/cli/base.rb +9 -0
  16. data/lib/terraspace_bundler/cli/bundle.rb +27 -0
  17. data/lib/terraspace_bundler/cli/clean.rb +11 -0
  18. data/lib/terraspace_bundler/cli/help.rb +9 -0
  19. data/lib/terraspace_bundler/cli/help/bundle/install.md +3 -0
  20. data/lib/terraspace_bundler/cli/help/completion.md +20 -0
  21. data/lib/terraspace_bundler/cli/help/completion_script.md +3 -0
  22. data/lib/terraspace_bundler/cli/install.rb +7 -0
  23. data/lib/terraspace_bundler/cli/update.rb +7 -0
  24. data/lib/terraspace_bundler/command.rb +89 -0
  25. data/lib/terraspace_bundler/completer.rb +159 -0
  26. data/lib/terraspace_bundler/completer/script.rb +6 -0
  27. data/lib/terraspace_bundler/completer/script.sh +10 -0
  28. data/lib/terraspace_bundler/config.rb +15 -0
  29. data/lib/terraspace_bundler/core.rb +21 -0
  30. data/lib/terraspace_bundler/dsl.rb +18 -0
  31. data/lib/terraspace_bundler/dsl/syntax.rb +20 -0
  32. data/lib/terraspace_bundler/helper/git.rb +21 -0
  33. data/lib/terraspace_bundler/installer.rb +45 -0
  34. data/lib/terraspace_bundler/logger.rb +26 -0
  35. data/lib/terraspace_bundler/logging.rb +7 -0
  36. data/lib/terraspace_bundler/mod.rb +85 -0
  37. data/lib/terraspace_bundler/mod/export.rb +23 -0
  38. data/lib/terraspace_bundler/mod/locked.rb +48 -0
  39. data/lib/terraspace_bundler/mod/registry.rb +72 -0
  40. data/lib/terraspace_bundler/mod/sync.rb +53 -0
  41. data/lib/terraspace_bundler/mod/tmp_paths.rb +28 -0
  42. data/lib/terraspace_bundler/setup.rb +20 -0
  43. data/lib/terraspace_bundler/syncer.rb +13 -0
  44. data/lib/terraspace_bundler/updater.rb +49 -0
  45. data/lib/terraspace_bundler/updater/lockfile.rb +48 -0
  46. data/lib/terraspace_bundler/util/registry.rb +24 -0
  47. data/lib/terraspace_bundler/version.rb +3 -0
  48. data/spec/fixtures/Terrafile +6 -0
  49. data/spec/spec_helper.rb +29 -0
  50. data/spec/terraform_bundler/installer_spec.rb +16 -0
  51. data/terraspace-bundler.gemspec +32 -0
  52. metadata +237 -0
@@ -0,0 +1,9 @@
1
+ class TerraspaceBundler::CLI
2
+ class Base
3
+ include TB::Logging
4
+
5
+ def initialize(options={})
6
+ @options = options
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,27 @@
1
+ class TerraspaceBundler::CLI
2
+ class Bundle < TerraspaceBundler::Command
3
+ terrafile_option = Proc.new {
4
+ option :terrafile, default: "Terrafile", desc: "Terrafile to use"
5
+ }
6
+
7
+ desc "install", "install"
8
+ long_desc Help.text("bundle/install")
9
+ terrafile_option.call
10
+ def install
11
+ Install.new(options).run
12
+ end
13
+
14
+ desc "update", "update"
15
+ long_desc Help.text("bundle/install")
16
+ terrafile_option.call
17
+ def update(mod=nil)
18
+ Update.new(options.merge(mod: mod)).run
19
+ end
20
+
21
+ desc "clean", "clean"
22
+ long_desc Help.text("bundle/clean")
23
+ def clean
24
+ Clean.new(options).run
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,11 @@
1
+ class TerraspaceBundler::CLI
2
+ class Clean < Base
3
+ include TB::Mod::TmpPaths
4
+ include TB::Logging
5
+
6
+ def run
7
+ FileUtils.rm_rf(tmp_root)
8
+ logger.info "Removed #{tmp_root}"
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,9 @@
1
+ module TerraspaceBundler::CLI::Help
2
+ class << self
3
+ def text(namespaced_command)
4
+ path = namespaced_command.to_s.gsub(':','/')
5
+ path = File.expand_path("../help/#{path}.md", __FILE__)
6
+ IO.read(path) if File.exist?(path)
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,3 @@
1
+ ## Examples
2
+
3
+ terraspace-bundler bundle install
@@ -0,0 +1,20 @@
1
+ ## Examples
2
+
3
+ terraspace-bundler completion
4
+
5
+ Prints words for TAB auto-completion.
6
+
7
+ terraspace-bundler completion
8
+ terraspace-bundler completion hello
9
+ terraspace-bundler completion hello name
10
+
11
+ To enable, TAB auto-completion add the following to your profile:
12
+
13
+ eval $(terraspace-bundler completion_script)
14
+
15
+ Auto-completion example usage:
16
+
17
+ terraspace-bundler [TAB]
18
+ terraspace-bundler hello [TAB]
19
+ terraspace-bundler hello name [TAB]
20
+ terraspace-bundler hello name --[TAB]
@@ -0,0 +1,3 @@
1
+ To use, add the following to your `~/.bashrc` or `~/.profile`
2
+
3
+ eval $(terraspace-bundler completion_script)
@@ -0,0 +1,7 @@
1
+ class TerraspaceBundler::CLI
2
+ class Install < Base
3
+ def run
4
+ TB::Installer.new(@options).run
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,7 @@
1
+ class TerraspaceBundler::CLI
2
+ class Update < Base
3
+ def run
4
+ TB::Updater.new(@options).run
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,89 @@
1
+ require "thor"
2
+
3
+ # Override thor's long_desc identation behavior
4
+ # https://github.com/erikhuda/thor/issues/398
5
+ class Thor
6
+ module Shell
7
+ class Basic
8
+ def print_wrapped(message, options = {})
9
+ message = "\n#{message}" unless message[0] == "\n"
10
+ stdout.puts message
11
+ end
12
+ end
13
+ end
14
+ end
15
+
16
+ module TerraspaceBundler
17
+ class Command < Thor
18
+ class << self
19
+ def dispatch(m, args, options, config)
20
+ # Allow calling for help via:
21
+ # terraspace-bundler command help
22
+ # terraspace-bundler command -h
23
+ # terraspace-bundler command --help
24
+ # terraspace-bundler command -D
25
+ #
26
+ # as well thor's normal way:
27
+ #
28
+ # terraspace-bundler help command
29
+ help_flags = Thor::HELP_MAPPINGS + ["help"]
30
+ if args.length > 1 && !(args & help_flags).empty?
31
+ args -= help_flags
32
+ args.insert(-2, "help")
33
+ end
34
+
35
+ # terraspace-bundler version
36
+ # terraspace-bundler --version
37
+ # terraspace-bundler -v
38
+ version_flags = ["--version", "-v"]
39
+ if args.length == 1 && !(args & version_flags).empty?
40
+ args = ["version"]
41
+ end
42
+
43
+ super
44
+ end
45
+
46
+ # Override command_help to include the description at the top of the
47
+ # long_description.
48
+ def command_help(shell, command_name)
49
+ meth = normalize_command_name(command_name)
50
+ command = all_commands[meth]
51
+ alter_command_description(command)
52
+ super
53
+ end
54
+
55
+ def alter_command_description(command)
56
+ return unless command
57
+
58
+ # Add description to beginning of long_description
59
+ long_desc = if command.long_description
60
+ "#{command.description}\n\n#{command.long_description}"
61
+ else
62
+ command.description
63
+ end
64
+
65
+ # add reference url to end of the long_description
66
+ unless website.empty?
67
+ full_command = [command.ancestor_name, command.name].compact.join('-')
68
+ url = "#{website}/reference/terraspace-bundler-#{full_command}"
69
+ long_desc += "\n\nHelp also available at: #{url}"
70
+ end
71
+
72
+ command.long_description = long_desc
73
+ end
74
+ private :alter_command_description
75
+
76
+ # meant to be overriden
77
+ def website
78
+ ""
79
+ end
80
+
81
+ # https://github.com/erikhuda/thor/issues/244
82
+ # Deprecation warning: Thor exit with status 0 on errors. To keep this behavior, you must define `exit_on_failure?` in `Lono::CLI`
83
+ # You can silence deprecations warning by setting the environment variable THOR_SILENCE_DEPRECATION.
84
+ def exit_on_failure?
85
+ true
86
+ end
87
+ end
88
+ end
89
+ end
@@ -0,0 +1,159 @@
1
+ =begin
2
+ Code Explanation:
3
+
4
+ There are 3 types of things to auto-complete:
5
+
6
+ 1. command: the command itself
7
+ 2. parameters: command parameters.
8
+ 3. options: command options
9
+
10
+ Here's an example:
11
+
12
+ mycli hello name --from me
13
+
14
+ * command: hello
15
+ * parameters: name
16
+ * option: --from
17
+
18
+ When command parameters are done processing, the remaining completion words will be options. We can tell that the command params are completed based on the method arity.
19
+
20
+ ## Arity
21
+
22
+ For example, say you had a method for a CLI command with the following form:
23
+
24
+ ufo scale service count --cluster development
25
+
26
+ It's equivalent ruby method:
27
+
28
+ scale(service, count) = has an arity of 2
29
+
30
+ So typing:
31
+
32
+ ufo scale service count [TAB] # there are 3 parameters including the "scale" command according to Thor's CLI processing.
33
+
34
+ So the completion should only show options, something like this:
35
+
36
+ --noop --verbose --cluster
37
+
38
+ ## Splat Arguments
39
+
40
+ When the ruby method has a splat argument, it's arity is negative. Here are some example methods and their arities.
41
+
42
+ ship(service) = 1
43
+ scale(service, count) = 2
44
+ ships(*services) = -1
45
+ foo(example, *rest) = -2
46
+
47
+ Fortunately, negative and positive arity values are processed the same way. So we take simply take the absolute value of the arity and process it the same.
48
+
49
+ Here are some test cases, hit TAB after typing the command:
50
+
51
+ terraspace-bundler completion
52
+ terraspace-bundler completion hello
53
+ terraspace-bundler completion hello name
54
+ terraspace-bundler completion hello name --
55
+ terraspace-bundler completion hello name --noop
56
+
57
+ terraspace-bundler completion
58
+ terraspace-bundler completion sub:goodbye
59
+ terraspace-bundler completion sub:goodbye name
60
+
61
+ ## Subcommands and Thor::Group Registered Commands
62
+
63
+ Sometimes the commands are not simple thor commands but are subcommands or Thor::Group commands. A good specific example is the ufo tool.
64
+
65
+ * regular command: ufo ship
66
+ * subcommand: ufo docker
67
+ * Thor::Group command: ufo init
68
+
69
+ Auto-completion accounts for each of these type of commands.
70
+ =end
71
+ module TerraspaceBundler
72
+ class Completer
73
+ def initialize(command_class, *params)
74
+ @params = params
75
+ @current_command = @params[0]
76
+ @command_class = command_class # CLI initiall
77
+ end
78
+
79
+ def run
80
+ if subcommand?(@current_command)
81
+ subcommand_class = @command_class.subcommand_classes[@current_command]
82
+ @params.shift # destructive
83
+ Completer.new(subcommand_class, *@params).run # recursively use subcommand
84
+ return
85
+ end
86
+
87
+ # full command has been found!
88
+ unless found?(@current_command)
89
+ puts all_commands
90
+ return
91
+ end
92
+
93
+ # will only get to here if command aws found (above)
94
+ arity = @command_class.instance_method(@current_command).arity.abs
95
+ if @params.size > arity or thor_group_command?
96
+ puts options_completion
97
+ else
98
+ puts params_completion
99
+ end
100
+ end
101
+
102
+ def subcommand?(command)
103
+ @command_class.subcommands.include?(command)
104
+ end
105
+
106
+ # hacky way to detect that command is a registered Thor::Group command
107
+ def thor_group_command?
108
+ command_params(raw=true) == [[:rest, :args]]
109
+ end
110
+
111
+ def found?(command)
112
+ public_methods = @command_class.public_instance_methods(false)
113
+ command && public_methods.include?(command.to_sym)
114
+ end
115
+
116
+ # all top-level commands
117
+ def all_commands
118
+ commands = @command_class.all_commands.reject do |k,v|
119
+ v.is_a?(Thor::HiddenCommand)
120
+ end
121
+ commands.keys
122
+ end
123
+
124
+ def command_params(raw=false)
125
+ params = @command_class.instance_method(@current_command).parameters
126
+ # Example:
127
+ # >> Sub.instance_method(:goodbye).parameters
128
+ # => [[:req, :name]]
129
+ # >>
130
+ raw ? params : params.map!(&:last)
131
+ end
132
+
133
+ def params_completion
134
+ offset = @params.size - 1
135
+ offset_params = command_params[offset..-1]
136
+ command_params[offset..-1].first
137
+ end
138
+
139
+ def options_completion
140
+ used = ARGV.select { |a| a.include?('--') } # so we can remove used options
141
+
142
+ method_options = @command_class.all_commands[@current_command].options.keys
143
+ class_options = @command_class.class_options.keys
144
+
145
+ all_options = method_options + class_options + ['help']
146
+
147
+ all_options.map! { |o| "--#{o.to_s.gsub('_','-')}" }
148
+ filtered_options = all_options - used
149
+ filtered_options.uniq
150
+ end
151
+
152
+ # Useful for debugging. Using puts messes up completion.
153
+ def log(msg)
154
+ File.open("/tmp/complete.log", "a") do |file|
155
+ file.puts(msg)
156
+ end
157
+ end
158
+ end
159
+ end
@@ -0,0 +1,6 @@
1
+ class TerraspaceBundler::Completer::Script
2
+ def self.generate
3
+ bash_script = File.expand_path("script.sh", File.dirname(__FILE__))
4
+ puts "source #{bash_script}"
5
+ end
6
+ end
@@ -0,0 +1,10 @@
1
+ _terraspace-bundler() {
2
+ COMPREPLY=()
3
+ local word="${COMP_WORDS[COMP_CWORD]}"
4
+ local words=("${COMP_WORDS[@]}")
5
+ unset words[0]
6
+ local completion=$(terraspace-bundler completion ${words[@]})
7
+ COMPREPLY=( $(compgen -W "$completion" -- "$word") )
8
+ }
9
+
10
+ complete -F _terraspace-bundler terraspace-bundler
@@ -0,0 +1,15 @@
1
+ module TerraspaceBundler
2
+ class Config
3
+ extend Memoist
4
+ include Singleton
5
+
6
+ def config
7
+ config = ActiveSupport::OrderedOptions.new
8
+ config.export_path = "vendor/modules"
9
+ config.terrafile = "Terrafile"
10
+ config.lockfile = "#{config.terrafile}.lock"
11
+ config
12
+ end
13
+ memoize :config
14
+ end
15
+ end
@@ -0,0 +1,21 @@
1
+ module TerraspaceBundler
2
+ module Core
3
+ extend Memoist
4
+
5
+ @@logger = nil
6
+ def logger
7
+ return @@logger if @@logger
8
+ @@logger = Logger.new($stdout)
9
+ @@logger.level = ENV['TB_LOG_LEVEL'] || 'info'
10
+ @@logger
11
+ end
12
+
13
+ def logger=(v)
14
+ @@logger = v
15
+ end
16
+
17
+ def config
18
+ Config.instance.config
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,18 @@
1
+ module TerraspaceBundler
2
+ class Dsl
3
+ include DslEvaluator
4
+ include Syntax
5
+
6
+ class_attribute :meta
7
+ self.meta = {global: {}, mods: []}
8
+
9
+ def run
10
+ evaluate_file(TB.config.terrafile)
11
+ self.class.meta
12
+ end
13
+
14
+ def meta
15
+ self.class.meta
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,20 @@
1
+ class TerraspaceBundler::Dsl
2
+ module Syntax
3
+ def org(url)
4
+ global[:org] = url
5
+ end
6
+ alias_method :user, :org
7
+
8
+ def export_path(path)
9
+ global[:export_path] = path
10
+ end
11
+
12
+ def mod(*args, **options)
13
+ meta[:mods] << {args: args, options: options}
14
+ end
15
+
16
+ def global
17
+ meta[:global]
18
+ end
19
+ end
20
+ end