dev-kit 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 9f29c2743d231ff3c8b7485ed1f98e50e6246bad
4
+ data.tar.gz: '0389cdeaabb2b1b3a649f2abc9431e769a44dd94'
5
+ SHA512:
6
+ metadata.gz: 49126e8a61f5ade5609d21e6dd1d7721ab4c36436b5dcd9749718c4d2652eef2500abc4aa6a2e6eaa0b092347aa41dd2dcc868c65f2fd3e47d29aeab7dca7661
7
+ data.tar.gz: 6c612d9fe65a830bd1775ee4fe9eea768f6a7d9d586227e41572c2de434121aa646da6ec1fd8025ed64d082244898ec683d7cef60bd05e2334512a709479a8c8
data/.gitignore ADDED
@@ -0,0 +1,14 @@
1
+ *.gem
2
+ build
3
+ .vagrant
4
+ .DS_Store
5
+ .bundle
6
+
7
+ .starscope.db
8
+ cscope.out
9
+ tags
10
+
11
+ .byebug_history
12
+
13
+ .rubocop-*
14
+ doc
data/.rubocop.yml ADDED
@@ -0,0 +1,23 @@
1
+ inherit_from:
2
+ - http://shopify.github.io/ruby-style-guide/rubocop.yml
3
+
4
+ AllCops:
5
+ Exclude:
6
+ - 'vendor/**/*'
7
+ TargetRubyVersion: 2.0
8
+
9
+ # This doesn't understand that <<~ doesn't exist in 2.0
10
+ Style/IndentHeredoc:
11
+ Enabled: false
12
+
13
+ # This doesn't take into account retrying from an exception
14
+ Lint/HandleExceptions:
15
+ Enabled: false
16
+
17
+ # allow String.new to create mutable strings
18
+ Style/EmptyLiteral:
19
+ Enabled: false
20
+
21
+ # allow the use of globals which makes sense in a CLI app like this
22
+ Style/GlobalVars:
23
+ Enabled: false
data/.travis.yml ADDED
@@ -0,0 +1,5 @@
1
+ sudo: false
2
+ language: ruby
3
+ rvm:
4
+ - 2.3.3
5
+ before_install: gem install bundler -v 1.15.0
data/Gemfile ADDED
@@ -0,0 +1,16 @@
1
+ # NOTE: These are development-only dependencies
2
+ source "https://rubygems.org"
3
+
4
+ gemspec
5
+
6
+ group :development, :test do
7
+ gem 'rubocop'
8
+ gem 'byebug'
9
+ gem 'method_source'
10
+ end
11
+
12
+ group :test do
13
+ gem 'mocha', require: false
14
+ gem 'minitest', '>= 5.0.0', require: false
15
+ gem 'minitest-reporters', require: false
16
+ end
data/Gemfile.lock ADDED
@@ -0,0 +1,57 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ dev-kit (0.1.0)
5
+ dev-ui (>= 0.1.0)
6
+
7
+ GEM
8
+ remote: https://rubygems.org/
9
+ specs:
10
+ ansi (1.5.0)
11
+ ast (2.3.0)
12
+ builder (3.2.3)
13
+ byebug (9.0.6)
14
+ dev-ui (0.1.0)
15
+ metaclass (0.0.4)
16
+ method_source (0.8.2)
17
+ minitest (5.10.2)
18
+ minitest-reporters (1.1.14)
19
+ ansi
20
+ builder
21
+ minitest (>= 5.0)
22
+ ruby-progressbar
23
+ mocha (1.2.1)
24
+ metaclass (~> 0.0.1)
25
+ parallel (1.11.2)
26
+ parser (2.4.0.0)
27
+ ast (~> 2.2)
28
+ powerpack (0.1.1)
29
+ rainbow (2.2.2)
30
+ rake
31
+ rake (10.5.0)
32
+ rubocop (0.49.1)
33
+ parallel (~> 1.10)
34
+ parser (>= 2.3.3.1, < 3.0)
35
+ powerpack (~> 0.1)
36
+ rainbow (>= 1.99.1, < 3.0)
37
+ ruby-progressbar (~> 1.7)
38
+ unicode-display_width (~> 1.0, >= 1.0.1)
39
+ ruby-progressbar (1.8.1)
40
+ unicode-display_width (1.3.0)
41
+
42
+ PLATFORMS
43
+ ruby
44
+
45
+ DEPENDENCIES
46
+ bundler (~> 1.15)
47
+ byebug
48
+ dev-kit!
49
+ method_source
50
+ minitest (>= 5.0.0)
51
+ minitest-reporters
52
+ mocha
53
+ rake (~> 10.0)
54
+ rubocop
55
+
56
+ BUNDLED WITH
57
+ 1.15.0
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2017 Burke Libbey
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,2 @@
1
+ # dev-kit
2
+
data/bin/console ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "dev/kit"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start(__FILE__)
data/bin/testunit ADDED
@@ -0,0 +1,23 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'rubygems'
4
+ require 'bundler/setup'
5
+
6
+ root = File.expand_path('../..', __FILE__)
7
+ DEV_TEST_ROOT = root + '/test'
8
+
9
+ $LOAD_PATH.unshift(DEV_TEST_ROOT)
10
+
11
+ def test_files
12
+ Dir.glob(DEV_TEST_ROOT + "/**/*_test.rb")
13
+ end
14
+
15
+ if ARGV.empty?
16
+ test_files.each { |f| require(f) }
17
+ exit 0
18
+ end
19
+
20
+ # A list of files is presumed to be specified
21
+ ARGV.each do |a|
22
+ require a.sub(%r{^test/}, '')
23
+ end
data/dev-kit.gemspec ADDED
@@ -0,0 +1,29 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path("../lib", __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require "dev/kit/version"
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "dev-kit"
8
+ spec.version = Dev::Kit::VERSION
9
+ spec.authors = ["Burke Libbey", "Julian Nadeau"]
10
+ spec.email = ["burke.libbey@shopify.com", "julian.nadeau@shopify.com"]
11
+
12
+ spec.summary = %q{Terminal UI framework extensions}
13
+ spec.description = %q{Terminal UI framework extensions}
14
+ spec.homepage = "https://github.com/shopify/dev-kit"
15
+ spec.license = "MIT"
16
+
17
+ spec.files = `git ls-files -z`.split("\x0").reject do |f|
18
+ f.match(%r{^(test|spec|features)/})
19
+ end
20
+ spec.bindir = "exe"
21
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
22
+ spec.require_paths = ["lib"]
23
+
24
+ spec.add_runtime_dependency "dev-ui", ">= 0.1.0"
25
+
26
+ spec.add_development_dependency "bundler", "~> 1.15"
27
+ spec.add_development_dependency "rake", "~> 10.0"
28
+ spec.add_development_dependency "minitest", "~> 5.0"
29
+ end
data/dev.yml ADDED
@@ -0,0 +1,8 @@
1
+ up:
2
+ - homebrew:
3
+ - ruby: 2.3.3
4
+ - bundler
5
+
6
+ commands:
7
+ test: bin/testunit
8
+ style: "bundle exec rubocop -D"
data/lib/dev/kit.rb ADDED
@@ -0,0 +1,7 @@
1
+ require 'dev/ui'
2
+
3
+ module Dev
4
+ module Kit
5
+ autoload :System, 'dev/kit/system'
6
+ end
7
+ end
@@ -0,0 +1,179 @@
1
+ require 'dev/kit'
2
+
3
+ require 'open3'
4
+ require 'English'
5
+
6
+ module Dev
7
+ module Kit
8
+ module System
9
+ class << self
10
+ SUDO_PROMPT = Dev::UI.fmt("{{info:(sudo)}} Password: ")
11
+
12
+ # Ask for sudo access with a message explaning the need for it
13
+ # Will make subsequent commands capable of running with sudo for a period of time
14
+ #
15
+ # #### Parameters
16
+ # - `msg`: A message telling the user why sudo is needed
17
+ #
18
+ # #### Usage
19
+ # `ctx.sudo_reason("We need to do a thing")`
20
+ #
21
+ def sudo_reason(msg)
22
+ # See if sudo has a cached password
23
+ `env SUDO_ASKPASS=/usr/bin/false sudo -A true`
24
+ return if $CHILD_STATUS.success?
25
+ Dev::UI.with_frame_color(:blue) do
26
+ puts(Dev::UI.fmt("{{i}} #{msg}"))
27
+ end
28
+ end
29
+
30
+ # Execute a command in the user's environment
31
+ # This is meant to be largely equivalent to backticks, only with the env passed in.
32
+ # Captures the results of the command without output to the console
33
+ #
34
+ # #### Parameters
35
+ # - `*a`: A splat of arguments evaluated as a command. (e.g. `'rm', folder` is equivalent to `rm #{folder}`)
36
+ # - `sudo`: If truthy, run this command with sudo. If String, pass to `sudo_reason`
37
+ # - `env`: process environment with which to execute this command
38
+ #
39
+ # #### Returns
40
+ # - `output`: output (STDOUT) of the command execution
41
+ # - `status`: boolean success status of the command execution
42
+ #
43
+ # #### Usage
44
+ # `out, stat = Dev::Kit::System.capture2('ls', 'a_folder')`
45
+ #
46
+ def capture2(*a, sudo: false, env: ENV)
47
+ delegate_open3(*a, sudo: sudo, env: env, method: :capture2)
48
+ end
49
+
50
+ # Execute a command in the user's environment
51
+ # This is meant to be largely equivalent to backticks, only with the env passed in.
52
+ # Captures the results of the command without output to the console
53
+ #
54
+ # #### Parameters
55
+ # - `*a`: A splat of arguments evaluated as a command. (e.g. `'rm', folder` is equivalent to `rm #{folder}`)
56
+ # - `sudo`: If truthy, run this command with sudo. If String, pass to `sudo_reason`
57
+ # - `env`: process environment with which to execute this command
58
+ #
59
+ # #### Returns
60
+ # - `output`: output (STDOUT merged with STDERR) of the command execution
61
+ # - `status`: boolean success status of the command execution
62
+ #
63
+ # #### Usage
64
+ # `out_and_err, stat = Dev::Kit::System.capture2e('ls', 'a_folder')`
65
+ #
66
+ def capture2e(*a, sudo: false, env: ENV)
67
+ delegate_open3(*a, sudo: sudo, env: env, method: :capture2e)
68
+ end
69
+
70
+ # Execute a command in the user's environment
71
+ # This is meant to be largely equivalent to backticks, only with the env passed in.
72
+ # Captures the results of the command without output to the console
73
+ #
74
+ # #### Parameters
75
+ # - `*a`: A splat of arguments evaluated as a command. (e.g. `'rm', folder` is equivalent to `rm #{folder}`)
76
+ # - `sudo`: If truthy, run this command with sudo. If String, pass to `sudo_reason`
77
+ # - `env`: process environment with which to execute this command
78
+ #
79
+ # #### Returns
80
+ # - `output`: STDOUT of the command execution
81
+ # - `error`: STDERR of the command execution
82
+ # - `status`: boolean success status of the command execution
83
+ #
84
+ # #### Usage
85
+ # `out, err, stat = Dev::Kit::System.capture3('ls', 'a_folder')`
86
+ #
87
+ def capture3(*a, sudo: false, env: ENV)
88
+ delegate_open3(*a, sudo: sudo, env: env, method: :capture3)
89
+ end
90
+
91
+ # Execute a command in the user's environment
92
+ # Outputs result of the command without capturing it
93
+ #
94
+ # #### Parameters
95
+ # - `*a`: A splat of arguments evaluated as a command. (e.g. `'rm', folder` is equivalent to `rm #{folder}`)
96
+ # - `sudo`: If truthy, run this command with sudo. If String, pass to `sudo_reason`
97
+ # - `env`: process environment with which to execute this command
98
+ # - `**kwargs`: additional keyword arguments to pass to Process.spawn
99
+ #
100
+ # #### Returns
101
+ # - `status`: boolean success status of the command execution
102
+ #
103
+ # #### Usage
104
+ # `stat = Dev::Kit::System.system('ls', 'a_folder')`
105
+ #
106
+ def system(*a, sudo: false, env: ENV, **kwargs)
107
+ a = apply_sudo(*a, sudo)
108
+
109
+ out_r, out_w = IO.pipe
110
+ err_r, err_w = IO.pipe
111
+ in_stream = STDIN.closed? ? :close : STDIN
112
+ pid = Process.spawn(env, *resolve_path(a, env), 0 => in_stream, :out => out_w, :err => err_w, **kwargs)
113
+ out_w.close
114
+ err_w.close
115
+
116
+ handlers = if block_given?
117
+ { out_r => ->(data) { yield(data.force_encoding(Encoding::UTF_8), '') },
118
+ err_r => ->(data) { yield('', data.force_encoding(Encoding::UTF_8)) }, }
119
+ else
120
+ { out_r => ->(data) { STDOUT.write(data) },
121
+ err_r => ->(data) { STDOUT.write(data) }, }
122
+ end
123
+
124
+ loop do
125
+ ios = [err_r, out_r].reject(&:closed?)
126
+ break if ios.empty?
127
+
128
+ readers, = IO.select(ios)
129
+ readers.each do |io|
130
+ begin
131
+ handlers[io].call(io.readpartial(4096))
132
+ rescue IOError
133
+ io.close
134
+ end
135
+ end
136
+ end
137
+
138
+ Process.wait(pid)
139
+ $CHILD_STATUS
140
+ end
141
+
142
+ private
143
+
144
+ def apply_sudo(*a, sudo)
145
+ a.unshift('sudo', '-S', '-p', SUDO_PROMPT) if sudo
146
+ sudo_reason(sudo) if sudo.is_a?(String)
147
+ a
148
+ end
149
+
150
+ def delegate_open3(*a, sudo: raise, env: raise, method: raise)
151
+ a = apply_sudo(*a, sudo)
152
+ Open3.send(method, env, *resolve_path(a, env))
153
+ rescue Errno::EINTR
154
+ raise(Errno::EINTR, "command interrupted: #{a.join(' ')}")
155
+ end
156
+
157
+ # Ruby resolves the program to execute using its own PATH, but we want it to
158
+ # use the provided one, so we ensure ruby chooses to spawn a shell, which will
159
+ # parse our command and properly spawn our target using the provided environment.
160
+ #
161
+ # This is important because dev clobbers its own environment such that ruby
162
+ # means /usr/bin/ruby, but we want it to select the ruby targeted by the active
163
+ # project.
164
+ #
165
+ # See https://github.com/Shopify/dev/pull/625 for more details.
166
+ def resolve_path(a, env)
167
+ # If only one argument was provided, make sure it's interpreted by a shell.
168
+ return ["true ; " + a[0]] if a.size == 1
169
+ return a if a.first.include?('/')
170
+ item = env.fetch('PATH', '').split(':').detect do |f|
171
+ File.exist?("#{f}/#{a.first}")
172
+ end
173
+ a[0] = "#{item}/#{a.first}" if item
174
+ a
175
+ end
176
+ end
177
+ end
178
+ end
179
+ end
@@ -0,0 +1,5 @@
1
+ module Dev
2
+ module Kit
3
+ VERSION = "0.1.0"
4
+ end
5
+ end
metadata ADDED
@@ -0,0 +1,116 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: dev-kit
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Burke Libbey
8
+ - Julian Nadeau
9
+ autorequire:
10
+ bindir: exe
11
+ cert_chain: []
12
+ date: 2017-06-21 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: dev-ui
16
+ requirement: !ruby/object:Gem::Requirement
17
+ requirements:
18
+ - - ">="
19
+ - !ruby/object:Gem::Version
20
+ version: 0.1.0
21
+ type: :runtime
22
+ prerelease: false
23
+ version_requirements: !ruby/object:Gem::Requirement
24
+ requirements:
25
+ - - ">="
26
+ - !ruby/object:Gem::Version
27
+ version: 0.1.0
28
+ - !ruby/object:Gem::Dependency
29
+ name: bundler
30
+ requirement: !ruby/object:Gem::Requirement
31
+ requirements:
32
+ - - "~>"
33
+ - !ruby/object:Gem::Version
34
+ version: '1.15'
35
+ type: :development
36
+ prerelease: false
37
+ version_requirements: !ruby/object:Gem::Requirement
38
+ requirements:
39
+ - - "~>"
40
+ - !ruby/object:Gem::Version
41
+ version: '1.15'
42
+ - !ruby/object:Gem::Dependency
43
+ name: rake
44
+ requirement: !ruby/object:Gem::Requirement
45
+ requirements:
46
+ - - "~>"
47
+ - !ruby/object:Gem::Version
48
+ version: '10.0'
49
+ type: :development
50
+ prerelease: false
51
+ version_requirements: !ruby/object:Gem::Requirement
52
+ requirements:
53
+ - - "~>"
54
+ - !ruby/object:Gem::Version
55
+ version: '10.0'
56
+ - !ruby/object:Gem::Dependency
57
+ name: minitest
58
+ requirement: !ruby/object:Gem::Requirement
59
+ requirements:
60
+ - - "~>"
61
+ - !ruby/object:Gem::Version
62
+ version: '5.0'
63
+ type: :development
64
+ prerelease: false
65
+ version_requirements: !ruby/object:Gem::Requirement
66
+ requirements:
67
+ - - "~>"
68
+ - !ruby/object:Gem::Version
69
+ version: '5.0'
70
+ description: Terminal UI framework extensions
71
+ email:
72
+ - burke.libbey@shopify.com
73
+ - julian.nadeau@shopify.com
74
+ executables: []
75
+ extensions: []
76
+ extra_rdoc_files: []
77
+ files:
78
+ - ".gitignore"
79
+ - ".rubocop.yml"
80
+ - ".travis.yml"
81
+ - Gemfile
82
+ - Gemfile.lock
83
+ - LICENSE.txt
84
+ - README.md
85
+ - bin/console
86
+ - bin/testunit
87
+ - dev-kit.gemspec
88
+ - dev.yml
89
+ - lib/dev/kit.rb
90
+ - lib/dev/kit/system.rb
91
+ - lib/dev/kit/version.rb
92
+ homepage: https://github.com/shopify/dev-kit
93
+ licenses:
94
+ - MIT
95
+ metadata: {}
96
+ post_install_message:
97
+ rdoc_options: []
98
+ require_paths:
99
+ - lib
100
+ required_ruby_version: !ruby/object:Gem::Requirement
101
+ requirements:
102
+ - - ">="
103
+ - !ruby/object:Gem::Version
104
+ version: '0'
105
+ required_rubygems_version: !ruby/object:Gem::Requirement
106
+ requirements:
107
+ - - ">="
108
+ - !ruby/object:Gem::Version
109
+ version: '0'
110
+ requirements: []
111
+ rubyforge_project:
112
+ rubygems_version: 2.6.10
113
+ signing_key:
114
+ specification_version: 4
115
+ summary: Terminal UI framework extensions
116
+ test_files: []