devbin 0.0.0 → 0.1.0.pre.alpha.1

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 6122cb01b698481193232726057771f445c1d13e584c96bff5615569d2ce311e
4
- data.tar.gz: 78ad22eb148758a580f6493d4e2af87d038312565f0cf7efb9be5045b02615ab
3
+ metadata.gz: 0c80700e0199f8e9b8b537e2e40f057db7f38484ace56bbf250b7ac4491b8376
4
+ data.tar.gz: 702113519efb5f87fb2ab2b639c916bc5b1b8fa156e840eeb7c56794ab6d4588
5
5
  SHA512:
6
- metadata.gz: 50735ad47756d0616ebf0ae37ad2cacdd04de4c507034914e6c39b0e9673e00fc31728c77ac8a634aba672b51569bdc3ecba5613ef816e7aad547d94a863666c
7
- data.tar.gz: 8dc2487c98e53f1dbde4c33dbff71870537be6dc358af0f54a0610856502b807cab5c89910ff064d0605f92dbcb12c5b92a82bc3d112fed02884b2fe04e269e8
6
+ metadata.gz: 837717f4f788048c95418eea83afeb6ce5f04398a371d4a30e8ece742c3618546f8250cb753b0a5c200d091027d3b1d6e4538b04fd4d48ad7405cb806318b2f3
7
+ data.tar.gz: 0f7fcc426bae6e7082896bff6e2ebbfce8a9372bff11b2cbe16b3ccbe3bb25d4a737cf44ae25830c2aeabb32869c86b59d46e56f2eadc6aebabd9f95e2d66bd3
data/.gitignore CHANGED
@@ -6,6 +6,11 @@
6
6
  /pkg/
7
7
  /spec/reports/
8
8
  /tmp/
9
+ # Ignore any further changes in samples folder. Use git add -f samples to force
10
+ # update its content when necessary
11
+ /samples/*
9
12
 
10
13
  # rspec failure tracking
11
14
  .rspec_status
15
+ *.log
16
+ *.pid
data/Gemfile CHANGED
@@ -7,6 +7,8 @@ gemspec
7
7
 
8
8
 
9
9
  group :development do
10
+ gem "benchmark-ips", require: false
11
+ gem "pry"
10
12
  gem "rubocop-github", require: false
11
13
  gem "rubocop-rspec", require: false
12
14
  end
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- devbin (0.0.0)
4
+ devbin (0.1.0.pre.alpha.1)
5
5
  docker-sync
6
6
  pastel (~> 0.7.2)
7
7
  thor (~> 0.20.0)
@@ -30,6 +30,8 @@ GEM
30
30
  specs:
31
31
  ast (2.4.0)
32
32
  backticks (1.0.2)
33
+ benchmark-ips (2.7.2)
34
+ coderay (1.1.2)
33
35
  daemons (1.3.1)
34
36
  diff-lcs (1.3)
35
37
  docker-compose (1.1.10)
@@ -47,6 +49,7 @@ GEM
47
49
  gem_update_checker (0.2.0)
48
50
  jaro_winkler (1.5.2)
49
51
  kramdown (1.16.2)
52
+ method_source (0.9.2)
50
53
  necromancer (0.4.0)
51
54
  os (1.0.0)
52
55
  parallel (1.12.1)
@@ -56,6 +59,9 @@ GEM
56
59
  equatable (~> 0.5.0)
57
60
  tty-color (~> 0.4.0)
58
61
  powerpack (0.1.2)
62
+ pry (0.12.2)
63
+ coderay (~> 1.1.0)
64
+ method_source (~> 0.9.0)
59
65
  rainbow (3.0.0)
60
66
  rake (10.5.0)
61
67
  rouge (3.3.0)
@@ -159,8 +165,10 @@ PLATFORMS
159
165
  ruby
160
166
 
161
167
  DEPENDENCIES
168
+ benchmark-ips
162
169
  bundler (~> 1.17)
163
170
  devbin!
171
+ pry
164
172
  rake (~> 10.0)
165
173
  rspec (~> 3.0)
166
174
  rubocop-github
data/README.md CHANGED
@@ -1,21 +1,52 @@
1
1
  # devbin
2
2
 
3
3
  Working in multiple containerized environment seamlessly. Within the application folder, type one command, give the name of other application, then it should work.
4
+ - Up and running in minute
5
+ [![asciicast](https://asciinema.org/a/e9nIt1Vmk1ePEeGQXTAtRdzk3.svg)](https://asciinema.org/a/e9nIt1Vmk1ePEeGQXTAtRdzk3)
6
+ - Seamlessly control the stack
7
+ [![asciicast](https://asciinema.org/a/EzYWzB9L7m8NSdEKpnqKozhnU.svg)](https://asciinema.org/a/EzYWzB9L7m8NSdEKpnqKozhnU)
4
8
 
9
+ *P/S: this tool is under active development, commands might be changed until it reached v0.1.0*
5
10
  ## Motivation
6
- When working in a multiple containerized environment, it gets boring to repeatedly make `cd` back and forth between application's folders to execute some commands.
7
- The Convention-Over-Configuration pattern is quite popular this day, we all name our containers, arrange folders base on some predictable rules, then make some command alias for faster integrate with other containers. **devbin** will help us to bootstrapping + managing our environment seamlessly. The idea is: just remember the application name + the command you want to execute, **devbin** do all other boring things.
11
+ When working in a multiple containerized environment, it gets boring to repeatedly make `cd` back and forth between application's folders to execute some commands.
12
+ The Convention-Over-Configuration pattern is quite popular this day, we all name our containers, arrange folders base on some predictable rules, then make some command alias for faster integrate with other containers. **devbin** will help us to bootstrapping + managing our environment seamlessly.
13
+
14
+ The idea is: just remember the application name + the command you want to execute, **devbin** do all other boring things.
15
+
16
+ ```text
17
+ samples
18
+ ├── app-one
19
+ │ ├── Gemfile
20
+ │ ├── Gemfile.lock
21
+ │ └── app.rb
22
+ ├── app-two
23
+ │ ├── Gemfile
24
+ │ ├── Gemfile.lock
25
+ │ └── app.rb
26
+ ├── docker
27
+ │ └── docker-compose.yml
28
+ └── docker-sync.yml
29
+ ```
30
+
31
+ With **devbin**, you can stay at `samples/app-one` or `samples` and control the stack seamlessly:
32
+ ```sh
33
+ $ devbin start app-one --detach
34
+ $ devbin start app-two
35
+ ```
8
36
 
9
37
  ## Installation
10
38
 
11
39
  Install gem as as:
12
-
13
- $ gem install devbin
40
+ ```sh
41
+ $ gem install devbin
42
+ ```
14
43
 
15
44
  ## Usage
16
45
  TL; DR;
17
46
 
18
- $ devbin help
47
+ ```sh
48
+ $ devbin help
49
+ ```
19
50
 
20
51
 
21
52
  ## Development
@@ -34,4 +65,4 @@ Everyone interacting in the Devbin project’s codebases, issue trackers, chat r
34
65
 
35
66
  ## Copyright
36
67
 
37
- Copyright (c) 2019 Phuong 'J' Le H. See [MIT License](LICENSE.txt) for further details.
68
+ Copyright (c) 2019 Phuong 'J' Le H. See [MIT License](LICENSE.txt) for further details.
@@ -7,8 +7,8 @@ require "devbin"
7
7
  # with your gem easier. You can also use a different console, if you like.
8
8
 
9
9
  # (If you use this, don't forget to add pry to your Gemfile!)
10
- # require "pry"
11
- # Pry.start
10
+ require "pry"
11
+ Pry.start
12
12
 
13
- require "irb"
14
- IRB.start(__FILE__)
13
+ # require "irb"
14
+ # IRB.start(__FILE__)
@@ -30,7 +30,9 @@ Gem::Specification.new do |spec|
30
30
  # Specify which files should be added to the gem when it is released.
31
31
  # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
32
32
  spec.files = Dir.chdir(File.expand_path("..", __FILE__)) do
33
- `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
33
+ `git ls-files -z`.split("\x0").reject do |f|
34
+ f.match(%r{^(test|spec|features|samples|docs)/})
35
+ end
34
36
  end
35
37
  spec.bindir = "exe"
36
38
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
@@ -11,6 +11,9 @@ module Devbin
11
11
  # Error raised by this runner
12
12
  Error = Class.new(StandardError)
13
13
 
14
+ class_option :help, aliases: "-h", type: :boolean,
15
+ desc: "Display usage information"
16
+
14
17
  desc "version", "devbin version"
15
18
  def version
16
19
  require_relative "version"
@@ -18,7 +21,108 @@ module Devbin
18
21
  end
19
22
  map %w(--version -v) => :version
20
23
 
24
+ desc "up [APP_NAME]", "Start the application"
25
+ method_option :detach, aliases: "-d", type: :boolean, required: false, default: false,
26
+ desc: "Start the application with detached mode"
27
+ method_option :sync, aliases: "-s", type: :boolean, default: true,
28
+ desc: "Start the docker-sync also"
29
+ def up(app_name)
30
+ if options[:help]
31
+ invoke :help, ["up"]
32
+ else
33
+ require_relative "commands/up"
34
+ Devbin::Commands::Up.new(app_name, options).execute
35
+ end
36
+ end
37
+
38
+ desc "attach APP_NAME", "Attach to the application"
39
+ def attach(app_name)
40
+ if options[:help]
41
+ invoke :help, ["attach"]
42
+ else
43
+ require_relative "commands/attach"
44
+ Devbin::Commands::Attach.new(app_name, options).execute
45
+ end
46
+ end
47
+
48
+ desc "start [APP_NAME]", "Start the application"
49
+ method_option :sync, aliases: "-s", type: :boolean, default: true,
50
+ desc: "Start the docker-sync also"
51
+ def start(app_name)
52
+ if options[:help]
53
+ invoke :help, ["start"]
54
+ else
55
+ require_relative "commands/start"
56
+ Devbin::Commands::Start.new(app_name, options).execute
57
+ end
58
+ end
59
+
60
+ desc "stop APP_NAME", "Stop the rails application"
61
+ method_option :all, aliases: "-a", type: :boolean, default: false,
62
+ desc: "Stop all applications"
63
+ method_option :sync, aliases: "-s", type: :boolean, default: true,
64
+ desc: "Stop the docker-sync also"
65
+ def stop(app_name = "")
66
+ if options[:help]
67
+ invoke :help, ["stop"]
68
+ else
69
+ require_relative "commands/stop"
70
+ Devbin::Commands::Stop.new(app_name, options).execute
71
+ end
72
+ end
73
+
74
+ desc "restart APP_NAME", "Restart the application"
75
+ # method_option :all, aliases: "-a", type: :boolean, default: false,
76
+ # desc: "Restart all applications"
77
+ method_option :sync, aliases: "-s", type: :boolean, default: true,
78
+ desc: "Restart the docker-sync also"
79
+ def restart(app_name)
80
+ if options[:help]
81
+ invoke :help, ["restart"]
82
+ else
83
+ require_relative "commands/restart"
84
+ Devbin::Commands::Restart.new(app_name, options).execute
85
+ end
86
+ end
87
+
88
+ desc "bash APP_NAME", "Attach to bash for the given app"
89
+ def bash(app_name)
90
+ if options[:help]
91
+ invoke :help, ["bash"]
92
+ else
93
+ require_relative "commands/bash"
94
+ Devbin::Commands::Bash.new(app_name, options).execute
95
+ end
96
+ end
97
+ map %w(sh) => :bash
98
+
99
+ desc "off", "Close all active containers and go home"
100
+ method_option :yes, aliases: "-y", type: :boolean, default: false,
101
+ desc: "No ask, just off"
102
+ def off(*_args)
103
+ if options[:help]
104
+ invoke :help, ["off"]
105
+ else
106
+ require_relative "commands/off"
107
+ Devbin::Commands::Off.new(:all, options).execute
108
+ end
109
+ end
110
+
111
+ desc "navigate APP_NAME", "Quick navigate to the main folder of the app"
112
+ def navigate(app_name)
113
+ if options[:help]
114
+ invoke :help, ["off"]
115
+ else
116
+ require_relative "commands/navigate"
117
+ Devbin::Commands::Navigate.new(:all, options).execute
118
+ end
119
+ end
120
+ map %w(cd) => :navigate
121
+
21
122
  require_relative "commands/rails"
22
123
  register Devbin::Commands::Rails, "rails", "rails [SUBCOMMAND]", "Control the Rails application"
124
+
125
+ require_relative "commands/configure"
126
+ register Devbin::Commands::Configure, "configure", "configure [SUBCOMMAND]", "Configure the workspace"
23
127
  end
24
128
  end
@@ -127,31 +127,61 @@ module Devbin
127
127
  end
128
128
 
129
129
  def find_pwd(file_or_directory_name)
130
- path = [".", file_or_directory_name]
131
- file = nil
132
- results = Dir[path.join("/")]
133
- file = results[0]
134
- return path[0..-2] unless results.empty?
135
- 3.times do
130
+ current_path = Dir.pwd
131
+ path = ["."]
132
+ while Dir.pwd != "/"
133
+ results = Dir[file_or_directory_name]
134
+ unless results.empty?
135
+ Dir.chdir current_path
136
+ return path
137
+ end
136
138
  path.unshift("..")
137
- results = Dir[path.join("/")]
138
- file = results[0]
139
- return path[0..-2] unless results.empty?
139
+ Dir.chdir ".." # Up one level
140
140
  end
141
+ Dir.chdir current_path
141
142
  []
142
143
  end
143
144
 
144
- def docker_sync_pwd
145
- @docker_sync_pwd ||=
146
- begin
147
- path = find_pwd("docker-sync.yml")
148
- if path.empty?
149
- fail "Cannot find the `docker-sync.yml' file"
150
- end
151
- path.join("/")
145
+ def docker_sync_file
146
+ return @docker_sync_file if @docker_sync_file
147
+ find_docker_files()
148
+ @docker_sync_file
149
+ end
150
+
151
+ def docker_compose_file
152
+ return @docker_compose_file if @docker_compose_file
153
+ find_docker_files()
154
+ @docker_compose_file
155
+ end
156
+
157
+ def root
158
+ return @root if @root
159
+ find_docker_files()
160
+ @root
161
+ end
162
+
163
+ def find_docker_files
164
+ current_path = Dir.pwd
165
+ matched_root = ""
166
+ matched_docker_sync_pwd = ""
167
+ matched_docker_compose_pwd = ""
168
+ (config["workspaces"] || {}).each_pair do |_workspace_name, value|
169
+ root = value["root"]
170
+ if current_path.start_with?(root) && root.length >= matched_root.length
171
+ matched_root = root
172
+ matched_docker_sync_pwd = value["docker-sync"]
173
+ matched_docker_compose_pwd = value["docker-compose"]
152
174
  end
175
+ end
176
+ if matched_docker_sync_pwd.empty? || matched_docker_compose_pwd.empty?
177
+ fail "Cannot find the workspace for #{current_path}"
178
+ end
179
+ @root = matched_root
180
+ @docker_sync_file = matched_docker_sync_pwd.gsub(matched_root, ".")
181
+ @docker_compose_file = matched_docker_compose_pwd.gsub(matched_root, ".")
153
182
  end
154
183
 
184
+ # @deprecated
155
185
  def docker_pwd
156
186
  @docker_pwd ||=
157
187
  begin
@@ -162,5 +192,15 @@ module Devbin
162
192
  path.push("docker").join("/")
163
193
  end
164
194
  end
195
+
196
+ def config_file_path
197
+ @config_file_path ||= "#{Dir.home}/.config/devbin/config.yml"
198
+ end
199
+
200
+ def config
201
+ return @config if @config
202
+ require "yaml"
203
+ @config = YAML.load_file config_file_path
204
+ end
165
205
  end
166
206
  end
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "../command"
4
+
5
+ module Devbin
6
+ module Commands
7
+ class Attach < Devbin::Command
8
+ def initialize(app_name, options)
9
+ @app_name = app_name
10
+ @options = options
11
+ end
12
+
13
+ def execute(input: $stdin, output: $stdout)
14
+ container_id, _err = run "docker-compose -f #{docker_compose_file} ps -q #{@app_name}", chdir: root
15
+ output.puts pastel.green(
16
+ "Remember to use ",
17
+ pastel.yellow.on_bright_black.bold("Ctrl + C"),
18
+ " to detach from container ( Overrided Ctrl + P Ctrl + Q to work with VSCode )"
19
+ )
20
+ pid = Process.fork {
21
+ exec "docker attach #{container_id.strip} --detach-keys='ctrl-c'"
22
+ }
23
+ Process.wait pid
24
+ output.puts pastel.yellow.bold("OK")
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "../command"
4
+
5
+ module Devbin
6
+ module Commands
7
+ class Bash < Devbin::Command
8
+ def initialize(app_name, options)
9
+ @app_name = app_name
10
+ @options = options
11
+ end
12
+
13
+ def execute(input: $stdin, output: $stdout)
14
+ Dir.chdir root do
15
+ pid = Process.fork {
16
+ exec "docker-compose -f #{docker_compose_file} exec #{@app_name} bash"
17
+ }
18
+ Process.wait pid
19
+ output.puts pastel.yellow.bold("OK")
20
+ exit 0
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "thor"
4
+
5
+ module Devbin
6
+ module Commands
7
+ class Configure < Thor
8
+
9
+ Error = Class.new(StandardError)
10
+
11
+ namespace :configure
12
+
13
+ class_option :help, aliases: "-h", type: :boolean,
14
+ desc: "Display usage information"
15
+
16
+ desc "add APP_NAME", "Add application to the current workspace"
17
+ def add(app_name)
18
+ if options[:help]
19
+ invoke :help, ["add"]
20
+ else
21
+ require_relative "configure/add"
22
+ Devbin::Commands::Configure::Add.new(app_name, options).execute
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,224 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../../command'
4
+ require "yaml"
5
+
6
+ module Devbin
7
+ module Commands
8
+ class Configure
9
+ class Add < Devbin::Command
10
+ require "yaml"
11
+ require "erb"
12
+ require "tty-file"
13
+ require "ostruct"
14
+
15
+ def initialize(app_name, options)
16
+ @app_name = app_name
17
+ @options = options
18
+ end
19
+
20
+ def execute(input: $stdin, output: $stdout)
21
+ check_or_create_config_files()
22
+ root_dir = ask_for_root()
23
+ docker_sync_file = ask_for_docker_sync_file()
24
+ docker_compose_file = ask_for_docker_compose_file()
25
+ add_new_config(
26
+ root_dir: root_dir,
27
+ docker_sync_file: docker_sync_file,
28
+ docker_compose_file: docker_compose_file
29
+ )
30
+ add_new_docker_sync(root_dir: root_dir, docker_sync_file: docker_sync_file)
31
+ add_new_docker_compose(docker_compose_file: docker_compose_file)
32
+
33
+ output.puts pastel.yellow.bold("OK")
34
+ end
35
+
36
+ private
37
+
38
+ def check_or_create_config_files
39
+ unless File.exist? config_file_path
40
+ tree = {
41
+ ".config" => [
42
+ "devbin" => []
43
+ ]
44
+ }
45
+ TTY::File.create_dir tree, Dir.home
46
+ TTY::File.copy_file config_origin_path, config_file_path
47
+ end
48
+ end
49
+
50
+ def ask_for_root(output: $stdout)
51
+ msg = pastel.yellow "Is `", pastel.bold(Dir.pwd), "' the root dir of workspace?"
52
+ if prompt.yes? msg
53
+ Dir.pwd
54
+ else
55
+ output.puts pastel.red "Please navigate to the workspace's root dir and try again"
56
+ exit 1
57
+ end
58
+ end
59
+
60
+ def ask_for_docker_sync_file(output: $stdout)
61
+ default_path = "#{Dir.pwd}/docker-sync.yml"
62
+
63
+ if File.exist? default_path
64
+ output.puts pastel.green(
65
+ "Detected the docker-sync configuration file at ",
66
+ pastel.bold(default_path),
67
+ ". Good to go"
68
+ )
69
+ return default_path
70
+ end
71
+
72
+ msg = pastel.yellow "./docker-sync.yml not found"
73
+ choices = [
74
+ { key: "1", name: "Create new file ./docker-sync.yml", value: :new },
75
+ { key: "2", name: "I will give you a path", value: :input },
76
+ { key: "3", name: "Abort", value: :stop },
77
+ ]
78
+ select_value = prompt.select msg, choices
79
+ case select_value
80
+ when :new
81
+ variables = OpenStruct.new
82
+ variables[:app_name] = @app_name
83
+ TTY::File.copy_file docker_sync_template_path, default_path, context: variables
84
+ default_path
85
+ when :input
86
+ output.puts pastel.red "Implementing: ask for docker-sync.yml path"
87
+ output.puts pastel.green(
88
+ "Wanna contribute? I'm glad to hear that.",
89
+ "\nPlease visit ",
90
+ pastel.bold.on_bright_black("https://github.com/yeuem1vannam/devbin/issues/16")
91
+ )
92
+ when :stop
93
+ output.puts pastel.red "Abort"
94
+ exit 1
95
+ else
96
+ fail "Un-handled select option"
97
+ end
98
+ end
99
+
100
+ def ask_for_docker_compose_file(output: $stdout)
101
+ default_path = "#{Dir.pwd}/docker-compose.yml"
102
+
103
+ if File.exist? default_path
104
+ output.puts pastel.green(
105
+ "Detected the docker-sync configuration file at ",
106
+ pastel.bold(default_path),
107
+ ". Good to go"
108
+ )
109
+ return default_path
110
+ end
111
+
112
+ msg = pastel.yellow "./docker-compose.yml not found"
113
+ choices = [
114
+ { key: "1", name: "Create new file ./docker-compose.yml", value: :new },
115
+ { key: "2", name: "I will give you a path", value: :input },
116
+ { key: "3", name: "Abort", value: :stop },
117
+ ]
118
+ select_value = prompt.select msg, choices
119
+ case select_value
120
+ when :new
121
+ variables = OpenStruct.new
122
+ variables[:app_name] = @app_name
123
+ TTY::File.copy_file docker_compose_template_path, default_path, context: variables
124
+ default_path
125
+ when :input
126
+ output.puts pastel.red "Implementing: ask for docker-compose.yml path"
127
+ output.puts pastel.green(
128
+ "Wanna contribute? I'm glad to hear that.",
129
+ "\nPlease visit ",
130
+ pastel.bold.on_bright_black("https://github.com/yeuem1vannam/devbin/issues/16")
131
+ )
132
+ when :stop
133
+ output.puts pastel.red "Abort"
134
+ exit 1
135
+ else
136
+ fail "Un-handled select option"
137
+ end
138
+ end
139
+
140
+ # @example
141
+ # add_new_config(
142
+ # root_dir: "/Users/yeuem1vannam/awesome-project",
143
+ # docker_sync_file: "./docker-sync.yml",
144
+ # docker_compose_file: "./docker-compose.yml"
145
+ # )
146
+ # # =>
147
+ # # ~/.config/devbin/config.yml
148
+ # # workspaces:
149
+ # # awesome-project:
150
+ # # root: /Users/yeuem1vannam/awesome-project
151
+ # # docker-sync: ./docker-sync.yml
152
+ # # docker-compose: ./docker-compose.yml
153
+ # # services:
154
+ # # app-one: ./app-one
155
+ def add_new_config(root_dir:, docker_sync_file:, docker_compose_file:)
156
+ workspace_name = Dir.pwd.split("/").last
157
+ app_name = @app_name
158
+ yaml_string = ERB.new(File.read(config_template_path)).result binding
159
+ new_config = YAML.load(yaml_string)
160
+
161
+ service_config_path = ["workspaces", workspace_name, "services"]
162
+
163
+ config = YAML.load_file config_file_path
164
+ services_config = config.dig(*service_config_path) || {}
165
+ services_config.merge! new_config.dig(*service_config_path)
166
+ new_config["workspaces"][workspace_name]["services"] = services_config
167
+ config["workspaces"] ||= {}
168
+ config["workspaces"][workspace_name] = new_config["workspaces"][workspace_name]
169
+
170
+ File.open(config_file_path, "w") do |f|
171
+ f.write config.to_yaml
172
+ end
173
+ end
174
+
175
+ # Add new section to docker-sync.yml file
176
+ def add_new_docker_sync(root_dir:, docker_sync_file:)
177
+ file_path = File.join(docker_sync_file)
178
+ config = YAML.load_file file_path
179
+ src_dir = "#{root_dir}/#{@app_name}".gsub Dir.pwd, "."
180
+ config["syncs"]["#{@app_name}-sync"] = {
181
+ "src" => src_dir,
182
+ "sync_excludes" => [".git", "node_modules"]
183
+ }
184
+ File.open(file_path, "w") do |f|
185
+ f.write config.to_yaml
186
+ end
187
+ end
188
+
189
+ # Add new section to docker-compose.yml file
190
+ def add_new_docker_compose(docker_compose_file:)
191
+ file_path = File.join(docker_compose_file)
192
+
193
+ app_name = @app_name
194
+ yaml_string = ERB.new(File.read(docker_compose_template_path)).result binding
195
+ app_config = YAML.load(yaml_string)
196
+
197
+ config = YAML.load_file file_path
198
+ config["services"].merge! app_config["services"]
199
+ config["volumes"].merge! app_config["volumes"]
200
+
201
+ File.open(file_path, "w") do |f|
202
+ f.write config.to_yaml
203
+ end
204
+ end
205
+
206
+ def config_origin_path
207
+ File.expand_path("../../templates/configure/add/config.yml", __dir__)
208
+ end
209
+
210
+ def config_template_path
211
+ File.expand_path("../../templates/configure/add/config.yml.erb", __dir__)
212
+ end
213
+
214
+ def docker_sync_template_path
215
+ File.expand_path("../../templates/configure/add/docker-sync.yml.erb", __dir__)
216
+ end
217
+
218
+ def docker_compose_template_path
219
+ File.expand_path("../../templates/configure/add/docker-compose.yml.erb", __dir__)
220
+ end
221
+ end
222
+ end
223
+ end
224
+ end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "../command"
4
+
5
+ module Devbin
6
+ module Commands
7
+ class Navigate < Devbin::Command
8
+ def initialize(app_name, options)
9
+ @app_name = app_name
10
+ @options = options
11
+ end
12
+
13
+ def execute(input: $stdin, output: $stdout)
14
+ output.puts pastel.yellow(
15
+ "Trying to navigate to application #{@app_name}",
16
+ "\n",
17
+ "Will be implemeted after `configure'"
18
+ )
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "../command"
4
+
5
+ module Devbin
6
+ module Commands
7
+ class Off < Devbin::Command
8
+ def initialize(app_name, options)
9
+ @app_name = app_name
10
+ @options = options
11
+ end
12
+
13
+ def execute(input: $stdin, output: $stdout)
14
+ if will_stop?
15
+ stop()
16
+ output.puts pastel.green.on_bright_black.bold("Remember to `git push' before go home")
17
+ else
18
+ output.puts pastel.red.on_bright_black.bold("Keep working...")
19
+ end
20
+ end
21
+
22
+ private
23
+
24
+ def will_stop?
25
+ return true if @options[:yes]
26
+ !prompt.no?(pastel.yellow.bold "Turn off the workspace?")
27
+ end
28
+
29
+ def stop
30
+ require_relative "stop"
31
+ stop_options = { all: true, sync: true }
32
+ Devbin::Commands::Stop.new(:all, stop_options).execute
33
+ end
34
+ end
35
+ end
36
+ end
@@ -17,6 +17,8 @@ module Devbin
17
17
  desc: "Display usage information"
18
18
  method_option :detach, aliases: "-d", type: :boolean, required: false, default: false,
19
19
  desc: "Start the server with detached mode"
20
+ method_option :sync, aliases: "-s", type: :boolean, default: true,
21
+ desc: "Start the docker-sync also"
20
22
  def server(app_name)
21
23
  if options[:help]
22
24
  invoke :help, ["server"]
@@ -53,8 +55,10 @@ module Devbin
53
55
  desc "stop APP_NAME", "Stop the rails application"
54
56
  method_option :help, aliases: "-h", type: :boolean,
55
57
  desc: "Display usage information"
56
- method_option :all, aliases: "-a", type: :boolean, required: false, default: false,
58
+ method_option :all, aliases: "-a", type: :boolean, default: false,
57
59
  desc: "Stop all applications"
60
+ method_option :sync, aliases: "-s", type: :boolean, default: true,
61
+ desc: "Stop the docker-sync also"
58
62
  def stop(app_name = "")
59
63
  if options[:help]
60
64
  invoke :help, ["stop"]
@@ -64,11 +68,13 @@ module Devbin
64
68
  end
65
69
  end
66
70
 
67
- desc "restart APP_NAME", "Restart docker-sync stack and the application"
71
+ desc "restart APP_NAME", "Restart the application"
68
72
  method_option :help, aliases: "-h", type: :boolean,
69
73
  desc: "Display usage information"
70
- method_option :detach, aliases: "-d", type: :boolean, required: false, default: false,
74
+ method_option :detach, aliases: "-d", type: :boolean, default: false,
71
75
  desc: "Restart the server with detached mode"
76
+ method_option :sync, aliases: "-s", type: :boolean, default: false,
77
+ desc: "Restart the docker-sync also"
72
78
  def restart(app_name)
73
79
  if options[:help]
74
80
  invoke :help, ["restart"]
@@ -13,7 +13,7 @@ module Devbin
13
13
 
14
14
  def execute(input: $stdin, output: $stdout)
15
15
  container_id, _err = run "docker-compose ps -q #{@app_name}", chdir: docker_pwd
16
- puts pastel.green(
16
+ output.puts pastel.green(
17
17
  "Remember to use ",
18
18
  pastel.yellow.on_bright_black.bold("Ctrl + C"),
19
19
  " to detach from container ( Overrided Ctrl + P Ctrl + Q to work with VSCode )"
@@ -22,8 +22,7 @@ module Devbin
22
22
  exec "docker attach #{container_id.strip} --detach-keys='ctrl-c'"
23
23
  }
24
24
  Process.wait pid
25
- output.puts "OK"
26
- exit 0
25
+ output.puts pastel.yellow.bold("OK")
27
26
  end
28
27
  end
29
28
  end
@@ -17,7 +17,7 @@ module Devbin
17
17
  exec "docker-compose exec #{@app_name} bundle exec rails c"
18
18
  }
19
19
  Process.wait pid
20
- output.puts "OK"
20
+ output.puts pastel.yellow.bold("OK")
21
21
  exit 0
22
22
  end
23
23
  end
@@ -12,8 +12,8 @@ module Devbin
12
12
 
13
13
  def execute(input: $stdin, output: $stdout)
14
14
  require_relative "stop"
15
- Devbin::Commands::Rails::Stop.new(@app_name, {all: true}).execute
16
- output.puts "OK"
15
+ Devbin::Commands::Rails::Stop.new(@app_name, {all: true, sync: true}).execute
16
+ output.puts pastel.green.on_bright_black.bold("Remember to `git push' before go home")
17
17
  end
18
18
  end
19
19
  end
@@ -8,16 +8,22 @@ module Devbin
8
8
  class Restart < Devbin::Command
9
9
  def initialize(app_name, options)
10
10
  @app_name = app_name
11
- @options = options
11
+ @options = options || {}
12
12
  end
13
13
 
14
14
  def execute(input: $stdin, output: $stdout)
15
15
  require_relative "stop"
16
- Devbin::Commands::Rails::Stop.new(@app_name, {all: false}).execute
17
- run "docker-sync start", chdir: docker_sync_pwd
16
+ Devbin::Commands::Rails::Stop.new(
17
+ @app_name,
18
+ {all: false, sync: @options[:sync]}
19
+ ).execute
20
+
18
21
  require_relative "server"
19
- Devbin::Commands::Rails::Server.new(@app_name, {detach: @optons && @options[:detach]}).execute
20
- output.puts "OK"
22
+ Devbin::Commands::Rails::Server.new(
23
+ @app_name,
24
+ @options.slice(:detach, :sync)
25
+ ).execute
26
+ output.puts pastel.yellow.bold("OK")
21
27
  end
22
28
  end
23
29
  end
@@ -12,12 +12,14 @@ module Devbin
12
12
  end
13
13
 
14
14
  def execute(input: $stdin, output: $stdout)
15
- # Command logic goes here ...
16
- begin
17
- run "docker-sync start", chdir: docker_sync_pwd
18
- rescue TTY::Command::ExitError => e
19
- unless e.message =~ /warning\s+docker-sync\salready\sstarted\sfor\sthis\sconfiguration/
20
- raise e
15
+ require "tty-command"
16
+ if @options[:sync]
17
+ begin
18
+ run "docker-sync start", chdir: docker_sync_pwd
19
+ rescue TTY::Command::ExitError => e
20
+ unless e.message =~ /warning\s+docker-sync\salready\sstarted\sfor\sthis\sconfiguration/
21
+ raise e
22
+ end
21
23
  end
22
24
  end
23
25
  run "docker-compose up -d #{@app_name}", chdir: docker_pwd
@@ -25,7 +27,7 @@ module Devbin
25
27
  require_relative "attach"
26
28
  Devbin::Commands::Rails::Attach.new(@app_name, {}).execute
27
29
  end
28
- output.puts "OK"
30
+ output.puts pastel.yellow.bold("OK")
29
31
  end
30
32
  end
31
33
  end
@@ -12,13 +12,15 @@ module Devbin
12
12
  end
13
13
 
14
14
  def execute(input: $stdin, output: $stdout)
15
- run "docker-sync stop", chdir: docker_sync_pwd
15
+ if @options[:sync]
16
+ run "docker-sync stop", chdir: docker_sync_pwd
17
+ end
16
18
  if @options[:all]
17
19
  run "docker-compose stop", chdir: docker_pwd
18
20
  else
19
21
  run "docker-compose stop #{@app_name}", chdir: docker_pwd
20
22
  end
21
- output.puts "OK"
23
+ output.puts pastel.yellow.bold("OK")
22
24
  end
23
25
  end
24
26
  end
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "../command"
4
+
5
+ module Devbin
6
+ module Commands
7
+ class Restart < Devbin::Command
8
+ def initialize(app_name, options)
9
+ @app_name = app_name
10
+ @options = options
11
+ end
12
+
13
+ def execute(input: $stdin, output: $stdout)
14
+ stop()
15
+ start()
16
+
17
+ output.puts pastel.yellow.bold("OK")
18
+ end
19
+
20
+ private
21
+
22
+ def stop
23
+ require_relative "stop"
24
+ stop_options = { sync: @options[:sync] }
25
+ Devbin::Commands::Stop.new(@app_name, stop_options).execute
26
+ end
27
+
28
+ def start
29
+ require_relative "start"
30
+ start_options = { sync: @options[:sync] }
31
+ Devbin::Commands::Start.new(@app_name, start_options).execute
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "../command"
4
+
5
+ module Devbin
6
+ module Commands
7
+ class Start < Devbin::Command
8
+ def initialize(app_name, options)
9
+ @app_name = app_name
10
+ @options = options
11
+ end
12
+
13
+ def execute(input: $stdin, output: $stdout)
14
+ require "tty-command"
15
+ if @options[:sync]
16
+ begin
17
+ run "docker-sync start -c #{docker_sync_file}", chdir: root
18
+ rescue TTY::Command::ExitError => e
19
+ unless e.message =~ /warning\s+docker-sync\salready\sstarted\sfor\sthis\sconfiguration/
20
+ raise e
21
+ end
22
+ end
23
+ end
24
+ run "docker-compose -f #{docker_compose_file} up -d #{@app_name}", chdir: root
25
+ output.puts pastel.yellow.bold("OK")
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "../command"
4
+
5
+ module Devbin
6
+ module Commands
7
+ class Stop < Devbin::Command
8
+ def initialize(app_name, options)
9
+ @app_name = app_name
10
+ @options = options
11
+ end
12
+
13
+ def execute(input: $stdin, output: $stdout)
14
+ if @options[:sync]
15
+ run "docker-sync stop -c #{docker_sync_file}", chdir: root
16
+ end
17
+ if @options[:all]
18
+ run "docker-compose -f #{docker_compose_file} stop", chdir: root
19
+ else
20
+ run "docker-compose -f #{docker_compose_file} stop #{@app_name}", chdir: root
21
+ end
22
+ output.puts pastel.yellow.bold("OK")
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "../command"
4
+
5
+ module Devbin
6
+ module Commands
7
+ class Up < Devbin::Command
8
+ def initialize(app_name, options)
9
+ @app_name = app_name
10
+ @options = options
11
+ end
12
+
13
+ def execute(input: $stdin, output: $stdout)
14
+ require_relative "start"
15
+ start_options = { sync: @options[:sync] }
16
+ Devbin::Commands::Start.new(@app_name, start_options).execute
17
+ unless @options[:detach]
18
+ require_relative "attach"
19
+ attach_options = {}
20
+ Devbin::Commands::Attach.new(@app_name, attach_options).execute
21
+ end
22
+ output.puts pastel.yellow.bold("OK")
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,4 @@
1
+ ---
2
+ global:
3
+ verbose: true
4
+ workspaces:
@@ -0,0 +1,10 @@
1
+ ---
2
+ global:
3
+ verbose: true
4
+ workspaces:
5
+ <%= workspace_name %>:
6
+ root: <%= root_dir %>
7
+ docker-sync: <%= docker_sync_file %>
8
+ docker-compose: <%= docker_compose_file %>
9
+ services:
10
+ <%= app_name %>: "./<%= app_name %>"
@@ -0,0 +1,25 @@
1
+ ---
2
+ version: "3.5"
3
+
4
+ services:
5
+ <%= app_name %>:
6
+ image: ruby:2.6
7
+ working_dir: /workspace
8
+ volumes:
9
+ - <%= app_name %>-sync:/workspace
10
+ - <%= app_name %>-bundle-box:/usr/local/bundle
11
+ ports:
12
+ - 4567:4567
13
+ command:
14
+ - /bin/sh
15
+ - -c
16
+ - |
17
+ set -ex
18
+ bundle check || bundle install
19
+ ruby app.rb
20
+
21
+ volumes:
22
+ <%= app_name %>-sync:
23
+ external: true
24
+ <%= app_name %>-bundle-box:
25
+ driver: local
@@ -0,0 +1,7 @@
1
+ version: "2"
2
+ options:
3
+ verbose: true
4
+ syncs:
5
+ <%= app_name %>-sync:
6
+ src: "./<%= app_name %>"
7
+ sync_excludes: [".git", "node_modules"]
@@ -1,3 +1,3 @@
1
1
  module Devbin
2
- VERSION = "0.0.0"
2
+ VERSION = "0.1.0-alpha.1"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: devbin
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.0
4
+ version: 0.1.0.pre.alpha.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Phuong 'J' Le H.
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2019-01-16 00:00:00.000000000 Z
11
+ date: 2019-01-18 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: tty-box
@@ -387,7 +387,12 @@ files:
387
387
  - lib/devbin/cli.rb
388
388
  - lib/devbin/command.rb
389
389
  - lib/devbin/commands/.gitkeep
390
- - lib/devbin/commands/base.rb
390
+ - lib/devbin/commands/attach.rb
391
+ - lib/devbin/commands/bash.rb
392
+ - lib/devbin/commands/configure.rb
393
+ - lib/devbin/commands/configure/add.rb
394
+ - lib/devbin/commands/navigate.rb
395
+ - lib/devbin/commands/off.rb
391
396
  - lib/devbin/commands/rails.rb
392
397
  - lib/devbin/commands/rails/attach.rb
393
398
  - lib/devbin/commands/rails/console.rb
@@ -395,7 +400,16 @@ files:
395
400
  - lib/devbin/commands/rails/restart.rb
396
401
  - lib/devbin/commands/rails/server.rb
397
402
  - lib/devbin/commands/rails/stop.rb
403
+ - lib/devbin/commands/restart.rb
404
+ - lib/devbin/commands/start.rb
405
+ - lib/devbin/commands/stop.rb
406
+ - lib/devbin/commands/up.rb
398
407
  - lib/devbin/templates/.gitkeep
408
+ - lib/devbin/templates/configure/add/.gitkeep
409
+ - lib/devbin/templates/configure/add/config.yml
410
+ - lib/devbin/templates/configure/add/config.yml.erb
411
+ - lib/devbin/templates/configure/add/docker-compose.yml.erb
412
+ - lib/devbin/templates/configure/add/docker-sync.yml.erb
399
413
  - lib/devbin/templates/rails/attach/.gitkeep
400
414
  - lib/devbin/templates/rails/console/.gitkeep
401
415
  - lib/devbin/templates/rails/off/.gitkeep
@@ -421,9 +435,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
421
435
  version: '0'
422
436
  required_rubygems_version: !ruby/object:Gem::Requirement
423
437
  requirements:
424
- - - ">="
438
+ - - ">"
425
439
  - !ruby/object:Gem::Version
426
- version: '0'
440
+ version: 1.3.1
427
441
  requirements: []
428
442
  rubygems_version: 3.0.1
429
443
  signing_key:
File without changes