superhosting 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (70) hide show
  1. checksums.yaml +15 -0
  2. data/.gitignore +10 -0
  3. data/.rspec +2 -0
  4. data/.travis.yml +11 -0
  5. data/Gemfile +5 -0
  6. data/Gemfile.lock +117 -0
  7. data/LICENSE.txt +22 -0
  8. data/README.md +23 -0
  9. data/Rakefile +6 -0
  10. data/Vagrantfile +10 -0
  11. data/bin/sx +10 -0
  12. data/bootstrap.sh +31 -0
  13. data/lib/superhosting.rb +40 -0
  14. data/lib/superhosting/base.rb +37 -0
  15. data/lib/superhosting/cli/base.rb +227 -0
  16. data/lib/superhosting/cli/cmd/admin_add.rb +11 -0
  17. data/lib/superhosting/cli/cmd/admin_container_add.rb +16 -0
  18. data/lib/superhosting/cli/cmd/admin_container_delete.rb +16 -0
  19. data/lib/superhosting/cli/cmd/admin_container_list.rb +12 -0
  20. data/lib/superhosting/cli/cmd/admin_delete.rb +11 -0
  21. data/lib/superhosting/cli/cmd/admin_passwd.rb +16 -0
  22. data/lib/superhosting/cli/cmd/container_add.rb +21 -0
  23. data/lib/superhosting/cli/cmd/container_admin_add.rb +16 -0
  24. data/lib/superhosting/cli/cmd/container_admin_delete.rb +16 -0
  25. data/lib/superhosting/cli/cmd/container_admin_list.rb +12 -0
  26. data/lib/superhosting/cli/cmd/container_change.rb +21 -0
  27. data/lib/superhosting/cli/cmd/container_delete.rb +11 -0
  28. data/lib/superhosting/cli/cmd/container_list.rb +9 -0
  29. data/lib/superhosting/cli/cmd/container_reconfig.rb +11 -0
  30. data/lib/superhosting/cli/cmd/container_restore.rb +24 -0
  31. data/lib/superhosting/cli/cmd/container_save.rb +14 -0
  32. data/lib/superhosting/cli/cmd/container_update.rb +11 -0
  33. data/lib/superhosting/cli/cmd/mysql_db_add.rb +9 -0
  34. data/lib/superhosting/cli/cmd/mysql_db_delete.rb +9 -0
  35. data/lib/superhosting/cli/cmd/mysql_db_dump.rb +9 -0
  36. data/lib/superhosting/cli/cmd/mysql_db_sql.rb +9 -0
  37. data/lib/superhosting/cli/cmd/mysql_grant.rb +9 -0
  38. data/lib/superhosting/cli/cmd/mysql_user_add.rb +12 -0
  39. data/lib/superhosting/cli/cmd/mysql_user_delete.rb +9 -0
  40. data/lib/superhosting/cli/cmd/site_add.rb +16 -0
  41. data/lib/superhosting/cli/cmd/site_alias_add.rb +16 -0
  42. data/lib/superhosting/cli/cmd/site_alias_delete.rb +16 -0
  43. data/lib/superhosting/cli/cmd/site_delete.rb +11 -0
  44. data/lib/superhosting/cli/cmd/site_rename.rb +16 -0
  45. data/lib/superhosting/cli/cmd/user_add.rb +24 -0
  46. data/lib/superhosting/cli/cmd/user_change.rb +24 -0
  47. data/lib/superhosting/cli/cmd/user_delete.rb +16 -0
  48. data/lib/superhosting/cli/cmd/user_list.rb +9 -0
  49. data/lib/superhosting/cli/cmd/user_passwd.rb +16 -0
  50. data/lib/superhosting/cli/error/ambiguous_command.rb +11 -0
  51. data/lib/superhosting/cli/error/base.rb +8 -0
  52. data/lib/superhosting/cli/error/controller.rb +8 -0
  53. data/lib/superhosting/controller/admin.rb +21 -0
  54. data/lib/superhosting/controller/admin/container.rb +24 -0
  55. data/lib/superhosting/controller/container.rb +174 -0
  56. data/lib/superhosting/controller/container/admin.rb +24 -0
  57. data/lib/superhosting/controller/mysql.rb +17 -0
  58. data/lib/superhosting/controller/mysql/db.rb +23 -0
  59. data/lib/superhosting/controller/mysql/user.rb +15 -0
  60. data/lib/superhosting/controller/site.rb +106 -0
  61. data/lib/superhosting/controller/site/alias.rb +21 -0
  62. data/lib/superhosting/controller/user.rb +25 -0
  63. data/lib/superhosting/docker_api.rb +31 -0
  64. data/lib/superhosting/helpers.rb +30 -0
  65. data/lib/superhosting/script_executor/base.rb +26 -0
  66. data/lib/superhosting/script_executor/container.rb +36 -0
  67. data/lib/superhosting/script_executor/site.rb +13 -0
  68. data/lib/superhosting/version.rb +3 -0
  69. data/superhosting.gemspec +32 -0
  70. metadata +341 -0
checksums.yaml ADDED
@@ -0,0 +1,15 @@
1
+ ---
2
+ !binary "U0hBMQ==":
3
+ metadata.gz: !binary |-
4
+ N2ZhNTc2Yjg3MjdlM2M5ZTgzYzNiYWYwMmMyNDA5MTZjMDQ4NzQzZA==
5
+ data.tar.gz: !binary |-
6
+ ZDMwZmM4ZTQ1NzhiMWRmNTM2Y2I3MGQ5NjZjNWJkZjM0Yjk3OTA1NA==
7
+ SHA512:
8
+ metadata.gz: !binary |-
9
+ MGUxMWE4ODlkMjJkZDFmNjU3YmVmZjJmZWJkMzNhZmU1MTNhYTY3ZDY0ZDdj
10
+ MjEyNmM1ZTgxOGNmYWZhMzY3YzkxODlkMTkzYjVjMDUzZWExMjUyZTdiYzI5
11
+ MTdjOTY0NzIwMGY0MzNiZDE2OTY3ZDA5MmM3OTBlMmE5ZjQ2ZjU=
12
+ data.tar.gz: !binary |-
13
+ MTdmNDg1NDNiY2RjYjYwOTQzNjQ2N2FiNDk5YzE2OTUyN2NmYmE2MGM1NGNm
14
+ ZWJlNzNlODAwNjM2YTQxN2UxYmUwZWZjYTE3N2M1N2E4OTY5YzA0ZjhhMWYy
15
+ N2ZlNmM2ODM5ZGNiNzRjMWFhNTliZjZjNGM3YzAzYjc5OTNlNjU=
data/.gitignore ADDED
@@ -0,0 +1,10 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /_yardoc/
4
+ /coverage/
5
+ /doc/
6
+ /pkg/
7
+ /spec/reports/
8
+ /tmp/
9
+ .idea
10
+ /.vagrant
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --require spec_helper
data/.travis.yml ADDED
@@ -0,0 +1,11 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.2.1
4
+ deploy:
5
+ provider: rubygems
6
+ api_key:
7
+ secure: zVrSJRx992jsyfOywuEPsi/xJogvspgadByoZX4+2wVrvTtkA/6lNnutm7rKwOeO57GsX4siKsOQ43j1nT0N+gwjb/XKfn0yaev657eAC/1ybvZMu98dZ+J2FjAAouz4qqtfacAczf7mXf0Xi53K+az6GUMeuldxdDDyhm5Xr3ZhPqhueh7eIijNVdSx+vK78qTgRNjZFrXsqvN+SdS8ZT0ZPqvKcI6MarOppdpavCUbYWIyx6bOcKictc3CbS5XdM3n9iPM3ribhj/vqkX+nruRQf9oqq7ZnqU4oan3jdTlo3ZAdaiKWcDhjgzOBJkojUTEEgWGgnBFHZNNaRcdXGo9TADUcvM8fd/59eX71EuB3WL+kHgLKwkWT1/pnTuPk+PVJfR3df46UaEMQkF4b7fxigJ1sXzt+zJ3CJD+X5ejR+c8E4bYCxZXWFxhZhi+UG3sFJQVOIRJE8Hohs2gLdvxBYyjgrCCk+TJaCxgU1gg5CbfuQ05oblpNk12E2GwAa9iPue89X80GVvkO/twTeTN2LAw3lOacuacU+BIyzohly6t7V1YiNQq0p9Sqlvvnnrwkqgp1jAuD56tOeLzjTsEkrHnuGstIJnh+GzbsJLm/BcXCnLcdbdvpKn66Pt9z+RmsRfW01QptWpYx8I2DgJtVjWEYeDKwJCZ8/c0rmc=
8
+ gem: superhosting
9
+ on:
10
+ tags: true
11
+ repo: flant/superhosting
data/Gemfile ADDED
@@ -0,0 +1,5 @@
1
+ source 'https://rubygems.org'
2
+ gemspec
3
+
4
+ gem 'path_mapper', git: 'https://github.com/flant/path_mapper.git'
5
+ gem 'net_status', git: 'https://github.com/flant/net_status.git'
data/Gemfile.lock ADDED
@@ -0,0 +1,117 @@
1
+ GIT
2
+ remote: https://github.com/flant/net_status.git
3
+ revision: 50e9cceac16a288f9ffa396c070b2bbfe5f9d01d
4
+ specs:
5
+ net_status (0.0.2)
6
+
7
+ GIT
8
+ remote: https://github.com/flant/path_mapper.git
9
+ revision: 03d57883e9db7eeb46ef361b3c54002f86b78cd6
10
+ specs:
11
+ path_mapper (0.0.2)
12
+
13
+ PATH
14
+ remote: .
15
+ specs:
16
+ superhosting (0.0.1)
17
+ mixlib-cli (>= 1.5.0, < 2.0)
18
+ mixlib-shellout (>= 2.2.6, < 3.0)
19
+ net_status (>= 0.0.1, < 1.0)
20
+ path_mapper (>= 0.0.1, < 1.0)
21
+
22
+ GEM
23
+ remote: https://rubygems.org/
24
+ specs:
25
+ addressable (2.4.0)
26
+ backports (3.6.8)
27
+ binding_of_caller (0.7.2)
28
+ debug_inspector (>= 0.0.1)
29
+ byebug (8.2.2)
30
+ coderay (1.1.1)
31
+ debug_inspector (0.0.2)
32
+ diff-lcs (1.2.5)
33
+ ethon (0.8.1)
34
+ ffi (>= 1.3.0)
35
+ excon (0.47.0)
36
+ faraday (0.9.2)
37
+ multipart-post (>= 1.2, < 3)
38
+ faraday_middleware (0.10.0)
39
+ faraday (>= 0.7.4, < 0.10)
40
+ ffi (1.9.10)
41
+ gh (0.14.0)
42
+ addressable
43
+ backports
44
+ faraday (~> 0.8)
45
+ multi_json (~> 1.0)
46
+ net-http-persistent (>= 2.7)
47
+ net-http-pipeline
48
+ highline (1.7.8)
49
+ json (1.8.3)
50
+ launchy (2.4.3)
51
+ addressable (~> 2.3)
52
+ method_source (0.8.2)
53
+ mixlib-cli (1.5.0)
54
+ mixlib-shellout (2.2.6)
55
+ multi_json (1.11.2)
56
+ multipart-post (2.0.0)
57
+ net-http-persistent (2.9.4)
58
+ net-http-pipeline (1.0.1)
59
+ pry (0.10.3)
60
+ coderay (~> 1.1.0)
61
+ method_source (~> 0.8.1)
62
+ slop (~> 3.4)
63
+ pry-byebug (3.3.0)
64
+ byebug (~> 8.0)
65
+ pry (~> 0.10)
66
+ pry-stack_explorer (0.4.9.2)
67
+ binding_of_caller (>= 0.7)
68
+ pry (>= 0.9.11)
69
+ pusher-client (0.6.2)
70
+ json
71
+ websocket (~> 1.0)
72
+ rake (10.5.0)
73
+ rspec (3.4.0)
74
+ rspec-core (~> 3.4.0)
75
+ rspec-expectations (~> 3.4.0)
76
+ rspec-mocks (~> 3.4.0)
77
+ rspec-core (3.4.3)
78
+ rspec-support (~> 3.4.0)
79
+ rspec-expectations (3.4.0)
80
+ diff-lcs (>= 1.2.0, < 2.0)
81
+ rspec-support (~> 3.4.0)
82
+ rspec-mocks (3.4.1)
83
+ diff-lcs (>= 1.2.0, < 2.0)
84
+ rspec-support (~> 3.4.0)
85
+ rspec-support (3.4.1)
86
+ slop (3.6.0)
87
+ travis (1.8.2)
88
+ backports
89
+ faraday (~> 0.9)
90
+ faraday_middleware (~> 0.9, >= 0.9.1)
91
+ gh (~> 0.13)
92
+ highline (~> 1.6)
93
+ launchy (~> 2.1)
94
+ pusher-client (~> 0.4)
95
+ typhoeus (~> 0.6, >= 0.6.8)
96
+ typhoeus (0.8.0)
97
+ ethon (>= 0.8.0)
98
+ websocket (1.2.2)
99
+
100
+ PLATFORMS
101
+ ruby
102
+
103
+ DEPENDENCIES
104
+ bundler (~> 1.7)
105
+ excon (>= 0.45.4, < 1.0)
106
+ net_status!
107
+ path_mapper!
108
+ pry (>= 0.10.3, < 1.0)
109
+ pry-byebug (>= 3.3.0, < 4.0)
110
+ pry-stack_explorer (>= 0.4.9.2, < 1.0)
111
+ rake (~> 10.0)
112
+ rspec (~> 3.4, >= 3.4.0)
113
+ superhosting!
114
+ travis (~> 1.8, >= 1.8.2)
115
+
116
+ BUNDLED WITH
117
+ 1.11.2
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2016 Alexey Igrychev
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,23 @@
1
+ # Superhosting
2
+
3
+ TODO
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ ```ruby
10
+ gem 'superhosting'
11
+ ```
12
+
13
+ And then execute:
14
+
15
+ $ bundle
16
+
17
+ Or install it yourself as:
18
+
19
+ $ gem install superhosting
20
+
21
+ ## Usage
22
+
23
+ TODO
data/Rakefile ADDED
@@ -0,0 +1,6 @@
1
+ require 'bundler/gem_tasks'
2
+ require 'rspec/core/rake_task'
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task default: :spec
data/Vagrantfile ADDED
@@ -0,0 +1,10 @@
1
+ # -*- mode: ruby -*-
2
+ # vi: set ft=ruby :
3
+ # vi: set sts=2 ts=2 sw=2 :
4
+
5
+ VAGRANTFILE_API_VERSION = "2"
6
+
7
+ Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
8
+ config.vm.box = "ubuntu/trusty64"
9
+ config.vm.provision :shell, path: "bootstrap.sh"
10
+ end
data/bin/sx ADDED
@@ -0,0 +1,10 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'superhosting'
4
+
5
+ begin
6
+ Superhosting::Cli::Base.start(ARGV)
7
+ rescue Superhosting::Cli::Error::Base => e
8
+ $stderr.puts([e.net_status[:error], e.net_status[:message]].compact.join(': '))
9
+ exit 1
10
+ end
data/bootstrap.sh ADDED
@@ -0,0 +1,31 @@
1
+ #!/usr/bin/env /bin/bash
2
+
3
+ apt-get update
4
+ apt-get install -y build-essential libpam0g-dev apt-transport-https ca-certificates
5
+ apt-key adv --keyserver hkp://p80.pool.sks-keyservers.net:80 --recv-keys 58118E89F3A912897C070ADBF76221572C52609D
6
+ echo 'deb https://apt.dockerproject.org/repo ubuntu-trusty main' > /etc/apt/sources.list.d/docker.list
7
+ apt-get update
8
+ apt-get install -y docker-engine
9
+
10
+ gpasswd -a vagrant docker
11
+ service docker restart
12
+
13
+ cd /tmp
14
+ git clone https://github.com/flant/pam_docker.git
15
+ cd pam_docker
16
+ make
17
+ make install-ubuntu-14.04
18
+
19
+ curl -sSL https://rvm.io/mpapis.asc | gpg --import -
20
+ curl -sSL https://get.rvm.io | sudo bash -s stable
21
+
22
+ echo 'source /etc/profile.d/rvm.sh' >> /etc/bash.bashrc
23
+ source /etc/profile.d/rvm.sh
24
+
25
+ rvm group add rvm vagrant
26
+ rvm install 2.2.1 --quiet-curl
27
+ rvm --default use 2.2.1
28
+ gem install bundler
29
+
30
+ cd /vagrant
31
+ bundle install
@@ -0,0 +1,40 @@
1
+ require 'mixlib/cli'
2
+ require 'mixlib/shellout'
3
+ require 'logger'
4
+ require 'pathname'
5
+ require 'excon'
6
+ require 'json'
7
+ require 'etc'
8
+ require 'erb'
9
+ require 'ostruct'
10
+ require 'pry-byebug'
11
+
12
+ require 'path_mapper'
13
+ require 'net_status'
14
+
15
+ require 'superhosting/version'
16
+ require 'superhosting/helpers'
17
+
18
+ require 'superhosting/base'
19
+ require 'superhosting/controller/admin'
20
+ require 'superhosting/controller/admin/container'
21
+ require 'superhosting/controller/container'
22
+ require 'superhosting/controller/container/admin'
23
+ require 'superhosting/controller/mysql'
24
+ require 'superhosting/controller/mysql/db'
25
+ require 'superhosting/controller/mysql/user'
26
+ require 'superhosting/controller/site'
27
+ require 'superhosting/controller/site/alias'
28
+ require 'superhosting/controller/user'
29
+
30
+ require 'superhosting/script_executor/base'
31
+ require 'superhosting/script_executor/container'
32
+ require 'superhosting/script_executor/site'
33
+
34
+ require 'superhosting/docker_api'
35
+
36
+ require 'superhosting/cli/error/base'
37
+ Dir["#{File.dirname(__FILE__)}/superhosting/cli/error/*.rb"].each{|cmd| require_relative cmd.split('.rb').first}
38
+
39
+ require 'superhosting/cli/base'
40
+ Dir["#{File.dirname(__FILE__)}/superhosting/cli/cmd/*.rb"].each{|cmd| require_relative cmd.split('.rb').first}
@@ -0,0 +1,37 @@
1
+ module Superhosting
2
+ class Base
3
+ include Helpers
4
+
5
+ def initialize(config_path: '/etc/sx', lib_path: '/var/lib/sx', logger: nil, docker_socket: nil)
6
+ @config_path = Pathname.new(config_path)
7
+ @lib_path = Pathname.new(lib_path)
8
+ @config = PathMapper.new(config_path)
9
+ @lib = PathMapper.new(lib_path)
10
+ @logger = logger
11
+
12
+ @docker_api = DockerApi.new(socket: docker_socket)
13
+ end
14
+
15
+ def debug(*a, &b)
16
+ @logger.debug(*a, &b) unless @logger.nil?
17
+ end
18
+
19
+ def command!(*command_args)
20
+ cmd = Mixlib::ShellOut.new(*command_args)
21
+ cmd.run_command
22
+ if cmd.status.success?
23
+ debug([cmd.stdout, cmd.stderr].join("\n"))
24
+ cmd
25
+ else
26
+ raise NetStatus::Exception.new(error: :error, message: [cmd.stdout, cmd.stderr].join("\n"))
27
+ end
28
+ end
29
+
30
+ def command(*command_args)
31
+ cmd = Mixlib::ShellOut.new(*command_args)
32
+ cmd.run_command
33
+ debug([cmd.stdout, cmd.stderr].join("\n"))
34
+ cmd
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,227 @@
1
+ module Superhosting
2
+ module Cli
3
+ module Cmd; end
4
+ class Base
5
+ include Mixlib::CLI
6
+
7
+ COMMANDS_MODULE = Cmd
8
+ CONTROLLERS_MODULE = Superhosting::Controller
9
+ CONTROLLER_BASE_OPTIONS = [:config_path, :lib_path, :docker_socket]
10
+
11
+ banner "#{?= * 50}\n#{?- * 19}SUPERHOSTING#{?- * 19}\n#{?= * 50}\n\n"
12
+
13
+ option :help,
14
+ :short => '-h',
15
+ :long => '--help',
16
+ :on => :tail
17
+
18
+ option :debug,
19
+ :long => '--debug',
20
+ :boolean => true,
21
+ :on => :tail
22
+
23
+ option :config_path,
24
+ :long => '--config-path PATH',
25
+ :on => :tail
26
+
27
+ option :lib_path,
28
+ :long => '--lib-path PATH',
29
+ :on => :tail
30
+
31
+ option :docker_socket,
32
+ :long => '--docker-socket PATH',
33
+ :on => :tail
34
+
35
+ def initialize(argv, node)
36
+ self.class.options.merge!(Base::options)
37
+ super()
38
+
39
+ @pos_args = parse_options(argv)
40
+ @node = node
41
+
42
+ @logger = Logger.new(STDOUT)
43
+ @logger.level = config[:debug] ? Logger::DEBUG : Logger::INFO
44
+ @logger.formatter = proc {|severity, datetime, progname, msg| sprintf("%s\n", msg.to_s.strip) }
45
+
46
+ self.help if config[:help] or self.class == Base
47
+ end
48
+
49
+ def help
50
+ def get_childs_banners(node)
51
+ if node.is_a? Hash
52
+ node.map do |k,v|
53
+ if v.is_a? Hash
54
+ get_childs_banners(node[k])
55
+ else
56
+ v.banner
57
+ end
58
+ end.join("\n")
59
+ else
60
+ node.banner
61
+ end
62
+ end
63
+
64
+ @logger.info("#{opt_parser.to_s}\n#{get_childs_banners(@node) if self.class == Base}")
65
+
66
+ exit 1
67
+ end
68
+
69
+ def run
70
+ begin
71
+ net_status = action
72
+ net_status ||= {}
73
+
74
+ raise Error::Controller, net_status unless net_status[:error].nil?
75
+ @logger.info(net_status[:data]) unless net_status[:data].nil?
76
+ @logger.debug('Done!')
77
+ rescue NetStatus::Exception => e
78
+ raise Error::Controller, e.net_status
79
+ end
80
+ end
81
+
82
+ def action
83
+ method = get_controller
84
+ opts = {}
85
+ method.parameters.each do |req, name|
86
+ if req.to_s.start_with? 'key'
87
+ opt = config[name]
88
+ self.help unless opt = @pos_args.shift if name == :name
89
+ opts.merge!(name => opt)
90
+ end
91
+ end
92
+ self.help unless @pos_args.empty? # only one position argument
93
+
94
+ method.parameters.empty? ? method.call : method.call(**opts)
95
+ end
96
+
97
+ def get_controller
98
+ def get_subcontroller_option
99
+ key = :"#{self.class.get_split_class_name.first}_name"
100
+ config[key] unless config[key].nil?
101
+ end
102
+
103
+ node = CONTROLLERS_MODULE
104
+ names = self.class.get_split_class_name
105
+
106
+ names.each do |n|
107
+ c_name = n.capitalize.to_sym
108
+ m_name = n.to_sym
109
+
110
+ if node.respond_to? :constants and node.constants.include? c_name
111
+ node = node.const_get(c_name)
112
+ elsif node.respond_to? :instance_methods and node.instance_methods(false).include? m_name
113
+ params = node.instance_method(:initialize).parameters
114
+
115
+ opts = {}
116
+ params.each do |req, name|
117
+ if req.to_s.start_with? 'key'
118
+ if name == :name
119
+ opt = get_subcontroller_option
120
+ elsif config.key? name
121
+ opt = config[name]
122
+ end
123
+ opts.merge!(name => opt) unless opt.nil?
124
+ end
125
+ end
126
+
127
+ CONTROLLER_BASE_OPTIONS.each {|opt| opts.merge!(opt => config[opt]) unless config[opt].nil? }
128
+ opts.merge!(logger: @logger)
129
+ return node.new(**opts).method(m_name)
130
+ end
131
+ end
132
+ raise Error::Base.new('Method doesn\'t found')
133
+ end
134
+
135
+ class << self
136
+ def start(args)
137
+ def clear_args(args, cmd)
138
+ split_toggle_case_name(cmd).length.times{ args.shift }
139
+ args
140
+ end
141
+
142
+ prepend
143
+ cmd, node = get_cmd_and_node(args)
144
+ args = clear_args(args, cmd)
145
+ cmd.new(args, node).run
146
+ end
147
+
148
+ def prepend
149
+ set_commands_hierarchy
150
+ set_banners
151
+ end
152
+
153
+ def set_banners(node=@@commands_hierarchy, path=[])
154
+ node.each do |k,v|
155
+ path_ = path.dup
156
+ path_ << k
157
+ if v.is_a? Hash
158
+ set_banners(v, path_)
159
+ else
160
+ v.banner("sx #{path_.join(' ')}#{" <#{path.last}>" if v.has_required_param?}#{' (options)' unless v.options.empty?}")
161
+ end
162
+ end
163
+ end
164
+
165
+ def has_required_param?
166
+ false
167
+ end
168
+
169
+ def set_commands_hierarchy
170
+ def get_commands
171
+ COMMANDS_MODULE.constants.select {|c| Class === COMMANDS_MODULE.const_get(c) }.sort
172
+ end
173
+
174
+ @@commands_hierarchy = get_commands.inject({}) do |h,k|
175
+ node = h
176
+ parts = split_toggle_case_name(k)
177
+ parts.each do |cmd|
178
+ node = (node[cmd] ||= (cmd == parts.last) ? COMMANDS_MODULE.const_get(k) : {})
179
+ end
180
+ h
181
+ end
182
+ end
183
+
184
+ def get_split_class_name
185
+ self.split_toggle_case_name(self.name.split('::').last)
186
+ end
187
+
188
+ def split_toggle_case_name(klass)
189
+ klass.to_s.gsub(/([[:lower:]])([[:upper:]])/, '\1 \2').split(' ').map(&:downcase)
190
+ end
191
+
192
+ def get_cmd_and_node(args)
193
+ def positional_arguments(args)
194
+ args.select { |arg| arg =~ /^([[:alnum:]\_\-]+)$/ }
195
+ end
196
+
197
+ args = positional_arguments(args)
198
+ node = @@commands_hierarchy
199
+ path = []
200
+ key = ''
201
+ cmd = nil
202
+ while arg = args.shift and cmd.nil?
203
+ res = node.keys.select { |k| k.start_with? arg }
204
+
205
+ case res.count
206
+ when 1
207
+ key = res.first
208
+ cmd = node[key] if node[key].is_a? Class
209
+ when 0
210
+ break
211
+ else
212
+ raise Error::AmbiguousCommand.new(path: path, commands: res)
213
+ end
214
+
215
+ path << key
216
+ node = node[key]
217
+ end
218
+
219
+ cmd ||= self
220
+ node = { key => node }
221
+
222
+ [cmd, node]
223
+ end
224
+ end
225
+ end
226
+ end
227
+ end