sct 0.1.14 → 0.1.19

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 (63) hide show
  1. checksums.yaml +4 -4
  2. data/bin/sct +3 -4
  3. data/{.DS_Store → cluster/lib/.DS_Store} +0 -0
  4. data/cluster/lib/cluster.rb +6 -0
  5. data/cluster/lib/cluster/commands_generator.rb +95 -0
  6. data/cluster/lib/cluster/module.rb +7 -0
  7. data/cluster/lib/cluster/runner.rb +239 -0
  8. data/{lib → sct/lib}/.DS_Store +0 -0
  9. data/sct/lib/sct.rb +17 -0
  10. data/sct/lib/sct/.DS_Store +0 -0
  11. data/sct/lib/sct/cli_tools_distributor.rb +46 -0
  12. data/{lib → sct/lib}/sct/command.rb +0 -0
  13. data/sct/lib/sct/commands/hostfile.rb +68 -0
  14. data/sct/lib/sct/commands/init.rb +37 -0
  15. data/sct/lib/sct/commands/mysqlproxy.rb +20 -0
  16. data/sct/lib/sct/commands_generator.rb +56 -0
  17. data/sct/lib/sct/tools.rb +12 -0
  18. data/sct/lib/sct/version.rb +3 -0
  19. data/sct_core/lib/.DS_Store +0 -0
  20. data/sct_core/lib/sct_core.rb +13 -0
  21. data/{lib/sct → sct_core/lib/sct_core}/.DS_Store +0 -0
  22. data/sct_core/lib/sct_core/command_executor.rb +104 -0
  23. data/{lib/sct → sct_core/lib/sct_core}/config.rb +3 -3
  24. data/sct_core/lib/sct_core/core_ext/string.rb +9 -0
  25. data/{lib/sct/setup/helpers.rb → sct_core/lib/sct_core/helper.rb} +2 -2
  26. data/sct_core/lib/sct_core/module.rb +0 -0
  27. data/sct_core/lib/sct_core/sct_pty.rb +53 -0
  28. data/sct_core/lib/sct_core/ui/implementations/shell.rb +129 -0
  29. data/sct_core/lib/sct_core/ui/interface.rb +120 -0
  30. data/sct_core/lib/sct_core/ui/ui.rb +26 -0
  31. data/shell/README.md +0 -0
  32. data/shell/lib/shell.rb +3 -0
  33. data/{lib/sct → shell/lib/shell}/ClassLevelInheritableAttributes.rb +0 -0
  34. data/shell/lib/shell/commands_generator.rb +14 -0
  35. data/{lib/sct → shell/lib/shell}/docker/composer.rb +4 -3
  36. data/{lib/sct → shell/lib/shell}/docker/docker.rb +7 -10
  37. data/{lib/sct → shell/lib/shell}/docker/php.rb +3 -2
  38. data/{lib/sct → shell/lib/shell}/docker/yarn.rb +4 -3
  39. data/shell/lib/shell/module.rb +9 -0
  40. data/shell/lib/shell/runner.rb +34 -0
  41. data/shell/lib/shell/tools.rb +7 -0
  42. metadata +92 -54
  43. data/.gitignore +0 -12
  44. data/.rspec +0 -3
  45. data/.travis.yml +0 -7
  46. data/CODE_OF_CONDUCT.md +0 -74
  47. data/Gemfile +0 -4
  48. data/Gemfile.lock +0 -48
  49. data/LICENSE.txt +0 -21
  50. data/README.md +0 -134
  51. data/Rakefile +0 -6
  52. data/lib/sct.rb +0 -61
  53. data/lib/sct/command_interface.rb +0 -18
  54. data/lib/sct/command_option.rb +0 -14
  55. data/lib/sct/commands/cluster.rb +0 -121
  56. data/lib/sct/commands/composer.rb +0 -29
  57. data/lib/sct/commands/hostfile.rb +0 -125
  58. data/lib/sct/commands/init.rb +0 -51
  59. data/lib/sct/commands/mysqlproxy.rb +0 -38
  60. data/lib/sct/commands/php.rb +0 -37
  61. data/lib/sct/commands/yarn.rb +0 -26
  62. data/lib/sct/version.rb +0 -3
  63. data/sct.gemspec +0 -40
File without changes
@@ -0,0 +1,68 @@
1
+ module Sct
2
+ class HostfileCommand
3
+
4
+ def execute(args, options)
5
+ return UI.error("SCT has not been initialized. Run 'sct init' first.") unless SctCore::Config.exists
6
+
7
+ return UI.error("This command needs to be run with sudo.") unless SctCore::Helper.isSudo
8
+
9
+ return unless SctCore::Helper.ingressAddress
10
+
11
+ ingressAddress = SctCore::Helper.ingressAddress
12
+
13
+ entries = [
14
+ {
15
+ host: "spend.cloud.local",
16
+ comment: "The spend cloud ingress url"
17
+ },
18
+ {
19
+ host: "mail.spend.cloud.local",
20
+ comment: "The spend cloud mail url"
21
+ },
22
+ {
23
+ host: "config.spend.cloud.local",
24
+ comment: "The spend cloud config url"
25
+ },
26
+ {
27
+ host: "spend-cloud.spend.cloud.local",
28
+ comment: "The spend cloud web app url"
29
+ },
30
+ {
31
+ host: "docs.spend.cloud.local",
32
+ comment: "The spend cloud documentation url"
33
+ }
34
+ ]
35
+
36
+ if options.path
37
+ hosts_paths = [options.path]
38
+ else
39
+ hosts_paths = ["/etc/hosts"]
40
+
41
+ if SctCore::Helper.operatingSystem == SctCore::Helper::WINDOWS
42
+ hosts_paths << "/mnt/c/Windows/System32/drivers/etc/hosts"
43
+ end
44
+ end
45
+
46
+ hosts_paths.each do |hosts_path|
47
+ line_ending = hosts_path == "/mnt/c/Windows/System32/drivers/etc/hosts" ? "\r\n" : "\n"
48
+
49
+ lines = File.readlines hosts_path
50
+
51
+ # select the lines that do not include any entry
52
+ lines = lines.select { |line| ! entries.any? { |entry| line.include? entry[:host] } }
53
+
54
+ # add entries
55
+ entries.each do |entry|
56
+ lines << "#{ingressAddress} #{entry[:host]} # #{entry[:comment]}#{line_ending}"
57
+ end
58
+
59
+ File.write hosts_path, lines.join
60
+
61
+ UI.success("Patched #{hosts_path} with #{ingressAddress}")
62
+ end
63
+
64
+ end
65
+
66
+ end
67
+
68
+ end
@@ -0,0 +1,37 @@
1
+ require 'sct_core/ui/ui'
2
+ require 'sct_core/config'
3
+
4
+ module Sct
5
+
6
+ class InitCommand
7
+
8
+ def execute(args, options)
9
+
10
+ dir = SctCore::Config.dir
11
+
12
+ cli = HighLine.new
13
+
14
+ email = cli.ask("What is your email address?") { |q|
15
+ q.validate = URI::MailTo::EMAIL_REGEXP
16
+ }
17
+
18
+ cloud_proxy_path = cli.ask("What is the path of your cloud proxy json credentials?") { |q|
19
+ q.default = "~/.config/gcloud/application_default_credentials.json"
20
+ }
21
+
22
+ contents = ""
23
+ contents << "email=#{email}\n"
24
+ contents << "cloud-proxy-path=#{File.expand_path(cloud_proxy_path)}\n"
25
+
26
+ if !File.directory?(dir)
27
+ FileUtils.mkdir_p(dir)
28
+ end
29
+
30
+ File.write(SctCore::Config.path, contents)
31
+
32
+ puts "Generated config file at #{SctCore::Config.path}"
33
+ end
34
+
35
+ end
36
+
37
+ end
@@ -0,0 +1,20 @@
1
+ module Sct
2
+ class MysqlproxyCommand
3
+
4
+ DEFAULT_SECRET_NAME = "gcloud-credentials"
5
+
6
+ def execute(args, options)
7
+
8
+ return UI.error("SCT has not been initialized. Run 'sct init' first.") unless SctCore::Config.exists
9
+
10
+ path = SctCore::Config.get('cloud-proxy-path')
11
+
12
+ system("kubectl delete secret gcloud-credentials")
13
+ system("kubectl create secret generic gcloud-credentials --from-file=#{path}")
14
+
15
+ UI.success("Authenticated with secret-name: '#{DEFAULT_SECRET_NAME}'")
16
+ end
17
+
18
+ end
19
+
20
+ end
@@ -0,0 +1,56 @@
1
+ require 'commander'
2
+ require 'sct/command'
3
+
4
+ module Sct
5
+ class CommandsGenerator
6
+ include Commander::Methods
7
+
8
+ def self.start
9
+ self.new.run
10
+ end
11
+
12
+ def run
13
+ program :name, 'sct'
14
+ program :version, Sct::VERSION
15
+ program :summary, 'CLI helper tool for local SCT development'
16
+ program :description, 'SCT is a CLI tool for developers using the Visma Continuous Deployment Model in conjunction with the Google Cloud Platform (GCP). It provides multiple command to set up and maintain a kubernetes cluster on a machine for local development'
17
+
18
+ global_option('--verbose') { $verbose = true }
19
+
20
+ command :init do |c|
21
+ c.syntax = 'sct init'
22
+ c.description = 'setup sct'
23
+
24
+ c.action do |args, options|
25
+ UI.important("setting up sct")
26
+ Sct::InitCommand.new.execute(args, options)
27
+ end
28
+ end
29
+
30
+ command :hostfile do |c|
31
+
32
+ c.syntax = 'sct hostfile'
33
+ c.description = 'patch hostfile with kubernetes ip'
34
+
35
+ c.action do |args, options|
36
+ UI.important("Trying to patch hostfile")
37
+ Sct::HostfileCommand.new.execute(args, options)
38
+ end
39
+ end
40
+
41
+ command :'mysql proxy' do |c|
42
+
43
+ c.syntax = 'sct mysql proxy'
44
+ c.description = 'setup google mysql proxy'
45
+
46
+ c.action do |args, options|
47
+ UI.important("Trying to setup mysql proxy")
48
+ Sct::MysqlproxyCommand.new.execute(args, options)
49
+ end
50
+
51
+ end
52
+
53
+ run!
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,12 @@
1
+ module Sct
2
+ TOOLS = [
3
+ :sct,
4
+ :shell,
5
+ :cluster
6
+ ]
7
+
8
+ # a list of all the config files we currently expect
9
+ TOOL_CONFIG_FILES = [
10
+
11
+ ]
12
+ end
@@ -0,0 +1,3 @@
1
+ module Sct
2
+ VERSION = "0.1.19"
3
+ end
Binary file
@@ -0,0 +1,13 @@
1
+ require_relative 'sct_core/core_ext/string'
2
+ require_relative 'sct_core/config'
3
+ require_relative 'sct_core/helper'
4
+ require_relative 'sct_core/command_executor'
5
+ require_relative 'sct_core/ui/ui'
6
+ require_relative 'sct_core/sct_pty'
7
+
8
+ # third party code
9
+ require 'colored'
10
+ require 'commander'
11
+
12
+ # these need to be imported after commander
13
+ require_relative 'sct_core/module'
@@ -0,0 +1,104 @@
1
+ require_relative 'ui/ui'
2
+ require_relative 'sct_pty'
3
+
4
+ module SctCore
5
+ # Executes commands and takes care of error handling and more
6
+ class CommandExecutor
7
+ class << self
8
+ # Cross-platform way of finding an executable in the $PATH. Respects the $PATHEXT, which lists
9
+ # valid file extensions for executables on Windows.
10
+ #
11
+ # which('ruby') #=> /usr/bin/ruby
12
+ #
13
+ # Derived from https://stackoverflow.com/a/5471032/3005
14
+ def which(cmd)
15
+ # PATHEXT contains the list of file extensions that Windows considers executable, semicolon separated.
16
+ # e.g. ".COM;.EXE;.BAT;.CMD"
17
+ exts = ENV['PATHEXT'] ? ENV['PATHEXT'].split(';') : []
18
+ exts << '' # Always have an empty string (= no file extension)
19
+
20
+ ENV['PATH'].split(File::PATH_SEPARATOR).each do |path|
21
+ exts.each do |ext|
22
+ cmd_path = File.join(path, "#{cmd}#{ext}")
23
+ return cmd_path if Helper.executable?(cmd_path)
24
+ end
25
+ end
26
+
27
+ return nil
28
+ end
29
+
30
+ # @param command [String] The command to be executed
31
+ # @param print_all [Boolean] Do we want to print out the command output while running?
32
+ # @param print_command [Boolean] Should we print the command that's being executed
33
+ # @param error [Block] A block that's called if an error occurs
34
+ # @param prefix [Array] An array containing a prefix + block which might get applied to the output
35
+ # @param loading [String] A loading string that is shown before the first output
36
+ # @param suppress_output [Boolean] Should we print the command's output?
37
+ # @return [String] All the output as string
38
+ def execute(command: nil, print_all: false, print_command: true, error: nil, prefix: nil, loading: nil, suppress_output: false)
39
+ print_all = true if $verbose
40
+ prefix ||= {}
41
+
42
+ output = []
43
+ command = command.join(" ") if command.kind_of?(Array)
44
+ command = self.escape_characters_in_string(command)
45
+ UI.command(command) if print_command
46
+
47
+ if print_all && loading # this is only used to show the "Loading text"...
48
+ UI.command_output(loading)
49
+ end
50
+
51
+ begin
52
+ status = SctCore::SctPty.spawn(command) do |command_stdout, command_stdin, pid|
53
+ command_stdout.each do |l|
54
+ line = l.chomp
55
+ output << line
56
+
57
+ next unless print_all
58
+
59
+ # Prefix the current line with a string
60
+ prefix.each do |element|
61
+ line = element[:prefix] + line if element[:block] && element[:block].call(line)
62
+ end
63
+
64
+ UI.command_output(line) unless suppress_output
65
+ end
66
+ end
67
+ rescue => ex
68
+ # SctPty adds exit_status on to StandardError so every error will have a status code
69
+ status = ex.exit_status
70
+
71
+ # This could happen when the environment is wrong:
72
+ # > invalid byte sequence in US-ASCII (ArgumentError)
73
+ output << ex.to_s
74
+ o = output.join("\n")
75
+ puts(o)
76
+ if error
77
+ error.call(o, nil)
78
+ else
79
+ raise ex
80
+ end
81
+ end
82
+
83
+ # Exit status for build command, should be 0 if build succeeded
84
+ if status != 0
85
+ o = output.join("\n")
86
+ puts(o) unless suppress_output # the user has the right to see the raw output
87
+ UI.error("Exit status: #{status}")
88
+ if error
89
+ error.call(o, status)
90
+ else
91
+ UI.user_error!("Exit status: #{status}")
92
+ end
93
+ end
94
+
95
+ return output.join("\n")
96
+ end
97
+
98
+ def escape_characters_in_string(string)
99
+ pattern = /(\'|\"|\.|\*|\/|\-|\\|\)|\$|\+|\(|\^|\?|\!|\~|\`)/
100
+ string.gsub(pattern){|match|"\\" + match}
101
+ end
102
+ end
103
+ end
104
+ end
@@ -1,8 +1,8 @@
1
- module Sct
1
+ module SctCore
2
2
  class Config
3
3
 
4
4
  def self.dir
5
- return "#{Sct::Helpers.homePath}/.config/sct"
5
+ return "#{SctCore::Helper.homePath}/.config/sct"
6
6
  end
7
7
 
8
8
  def self.path
@@ -30,7 +30,7 @@ module Sct
30
30
 
31
31
  contents = File.read(self.path)
32
32
 
33
- return Sct::Helpers.to_hash(contents)
33
+ return SctCore::Helper.to_hash(contents)
34
34
  end
35
35
  end
36
36
  end
@@ -0,0 +1,9 @@
1
+ class String
2
+ def sct_class
3
+ split('_').collect!(&:capitalize).join
4
+ end
5
+
6
+ def sct_module
7
+ self.sct_class
8
+ end
9
+ end
@@ -1,5 +1,5 @@
1
- module Sct
2
- class Helpers
1
+ module SctCore
2
+ class Helper
3
3
 
4
4
  WINDOWS = "Windows"
5
5
  MAC_OS = "MacOS"
File without changes
@@ -0,0 +1,53 @@
1
+ class StandardError
2
+ def exit_status
3
+ return -1
4
+ end
5
+ end
6
+
7
+ module SctCore
8
+ class SctPtyError < StandardError
9
+ attr_reader :exit_status
10
+ def initialize(e, exit_status)
11
+ super(e)
12
+ set_backtrace(e.backtrace) if e
13
+ @exit_status = exit_status
14
+ end
15
+ end
16
+
17
+ class SctPty
18
+ def self.spawn(command)
19
+ require 'pty'
20
+ PTY.spawn(command) do |command_stdout, command_stdin, pid|
21
+ begin
22
+ yield(command_stdout, command_stdin, pid)
23
+ rescue Errno::EIO
24
+ # Exception ignored intentionally.
25
+ # https://stackoverflow.com/questions/10238298/ruby-on-linux-pty-goes-away-without-eof-raises-errnoeio
26
+ # This is expected on some linux systems, that indicates that the subcommand finished
27
+ # and we kept trying to read, ignore it
28
+ ensure
29
+ begin
30
+ Process.wait(pid)
31
+ rescue Errno::ECHILD, PTY::ChildExited
32
+ # The process might have exited.
33
+ end
34
+ end
35
+ end
36
+ $?.exitstatus
37
+ rescue LoadError
38
+ require 'open3'
39
+ Open3.popen2e(command) do |command_stdin, command_stdout, p| # note the inversion
40
+ yield(command_stdout, command_stdin, p.value.pid)
41
+
42
+ command_stdin.close
43
+ command_stdout.close
44
+ p.value.exitstatus
45
+ end
46
+ rescue StandardError => e
47
+ # Wrapping any error in SctPtyError to allow
48
+ # callers to see and use $?.exitstatus that
49
+ # would usually get returned
50
+ raise SctPtyError.new(e, $?.exitstatus)
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,129 @@
1
+ require_relative '../interface'
2
+
3
+ module SctCore
4
+ # Shell is the terminal output of things
5
+ # For documentation for each of the methods open `interface.rb`
6
+ class Shell < Interface
7
+ require 'tty-screen'
8
+
9
+ def log
10
+ $stdout.sync = true
11
+ end
12
+
13
+ def writeToUser(message)
14
+ puts message
15
+ end
16
+
17
+ def error(message)
18
+ writeToUser(message.to_s.red)
19
+ end
20
+
21
+ def important(message)
22
+ writeToUser(message.to_s.yellow)
23
+ end
24
+
25
+ def success(message)
26
+ writeToUser(message.to_s.green)
27
+ end
28
+
29
+ def message(message)
30
+ writeToUser(message.to_s)
31
+ end
32
+
33
+ def deprecated(message)
34
+ writeToUser(message.to_s.deprecated)
35
+ end
36
+
37
+ def command(message)
38
+ writeToUser("$ #{message}".cyan)
39
+ end
40
+
41
+ def command_output(message)
42
+ actual = (message.split("\r").last || "") # as clearing the line will remove the `>` and the time stamp
43
+ actual.split("\n").each do |msg|
44
+ # prefix = msg.include?("▸") ? "" : "▸ "
45
+ prefix = ""
46
+ writeToUser(prefix + "" + msg.magenta)
47
+ end
48
+ end
49
+
50
+ def verbose(message)
51
+ message.to_s if $verbose
52
+ end
53
+
54
+ def header(message)
55
+ format = format_string
56
+ if message.length + 8 < TTY::Screen.width - format.length
57
+ message = "--- #{message} ---"
58
+ i = message.length
59
+ else
60
+ i = TTY::Screen.width - format.length
61
+ end
62
+ success("-" * i)
63
+ success(message)
64
+ success("-" * i)
65
+ end
66
+
67
+ def content_error(content, error_line)
68
+ error_line = error_line.to_i
69
+ return unless error_line > 0
70
+
71
+ contents = content.split(/\r?\n/).map(&:chomp)
72
+
73
+ start_line = error_line - 2 < 1 ? 1 : error_line - 2
74
+ end_line = error_line + 2 < contents.length ? error_line + 2 : contents.length
75
+
76
+ Range.new(start_line, end_line).each do |line|
77
+ str = line == error_line ? " => " : " "
78
+ str << line.to_s.rjust(Math.log10(end_line) + 1)
79
+ str << ":\t#{contents[line - 1]}"
80
+ error(str)
81
+ end
82
+ end
83
+
84
+ #####################################################
85
+ # @!group Errors: Inputs
86
+ #####################################################
87
+
88
+ def interactive?
89
+ interactive = true
90
+ interactive = false if $stdout.isatty == false
91
+ return interactive
92
+ end
93
+
94
+ def input(message)
95
+ verify_interactive!(message)
96
+ ask("#{format_string}#{message.to_s.yellow}").to_s.strip
97
+ end
98
+
99
+ def confirm(message)
100
+ verify_interactive!(message)
101
+ agree("#{format_string}#{message.to_s.yellow} (y/n)", true)
102
+ end
103
+
104
+ def select(message, options)
105
+ verify_interactive!(message)
106
+
107
+ important(message)
108
+ choose(*options)
109
+ end
110
+
111
+ def password(message)
112
+ verify_interactive!(message)
113
+
114
+ ask("#{format_string}#{message.to_s.yellow}") { |q| q.echo = "*" }
115
+ end
116
+
117
+ def user_error!(error_message, options = {})
118
+ writeToUser(error_message.yellow)
119
+ end
120
+
121
+ private
122
+
123
+ def verify_interactive!(message)
124
+ return if interactive?
125
+ important(message)
126
+ crash!("Could not retrieve response as sct runs in non-interactive mode")
127
+ end
128
+ end
129
+ end