a2km 0.0.1 → 0.0.2

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
  SHA1:
3
- metadata.gz: 3df1210c6b58fc739fde387f9280174885f01e58
4
- data.tar.gz: 9413d30be46d71bf2a5155169f4295543be6dc70
3
+ metadata.gz: 1bd0be9d8cdd24b99dfca16dad1fdaca90ae3eb2
4
+ data.tar.gz: 3e45923484920d0c0849d9a408d0ba7e644257d9
5
5
  SHA512:
6
- metadata.gz: 2feac328e487b78a2dcb4b06001e5371ba71f4f412ef7c025d6a7f4be880002e65fb53f0b2d2e06815749f0361fc8eea057e3edf1b7628ef0e81a77da1cbb88c
7
- data.tar.gz: fc39bc254f3056a4afc6ffa6e84114deaba7c96e06640cafd6af9d126ae48aebc07a3bd878dced14c22825cecc67204327a30d7d4517c7d4e8deb5ddbd3f9566
6
+ metadata.gz: 94d3adad6abb635bc980075c362bf875af5b8a78a9ed8f8d9fefa53b37e8eddcff9f1b0ee996a8dc756836a2e8b88d3b4966ac35bd7757e0ffb402e8a72d9a23
7
+ data.tar.gz: 5194abffa5630161a00d9f938d9ee29319f83bfe668d30cfb0689d3286b2edf6a34d08b7995df704f7277322a78f84125504dcd077f441eafae2adedfa30ba4b
data/.gitignore ADDED
@@ -0,0 +1,35 @@
1
+ *.gem
2
+ *.rbc
3
+ /.config
4
+ /coverage/
5
+ /InstalledFiles
6
+ /pkg/
7
+ /spec/reports/
8
+ /test/tmp/
9
+ /test/version_tmp/
10
+ /tmp/
11
+
12
+ ## Specific to RubyMotion:
13
+ .dat*
14
+ .repl_history
15
+ build/
16
+
17
+ ## Documentation cache and generated files:
18
+ /.yardoc/
19
+ /_yardoc/
20
+ /doc/
21
+ /rdoc/
22
+
23
+ ## Environment normalisation:
24
+ /.bundle/
25
+ /vendor/bundle
26
+ /lib/bundler/man/
27
+
28
+ # for a library or gem, you might want to ignore these files since the code is
29
+ # intended to run in multiple environments; otherwise, check them in:
30
+ # Gemfile.lock
31
+ # .ruby-version
32
+ # .ruby-gemset
33
+
34
+ # unless supporting rvm < 1.11.0 or doing something fancy, ignore this:
35
+ .rvmrc
data/LICENSE ADDED
@@ -0,0 +1,28 @@
1
+ Copyright (c) 2015, Min RK
2
+ All rights reserved.
3
+
4
+ Redistribution and use in source and binary forms, with or without
5
+ modification, are permitted provided that the following conditions are met:
6
+
7
+ * Redistributions of source code must retain the above copyright notice, this
8
+ list of conditions and the following disclaimer.
9
+
10
+ * Redistributions in binary form must reproduce the above copyright notice,
11
+ this list of conditions and the following disclaimer in the documentation
12
+ and/or other materials provided with the distribution.
13
+
14
+ * Neither the name of a2km nor the names of its
15
+ contributors may be used to endorse or promote products derived from
16
+ this software without specific prior written permission.
17
+
18
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
22
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
24
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
25
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
26
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28
+
data/README.md ADDED
@@ -0,0 +1,45 @@
1
+ # Assistant to the Kernel Manager
2
+
3
+ Utility for working with [Jupyter](https://jupyter.org) kernelspecs.
4
+
5
+
6
+ ## Install
7
+
8
+ gem install a2km
9
+
10
+
11
+ ## Examples
12
+
13
+ a2km clone python3 myenvpy3
14
+ a2km set python3-copy display_name "Super cool Python Kernel"
15
+ a2km add-env python3-copy SPARK_HOME=/path/to/spark
16
+ a2km add-argv python3-copy -- --debug
17
+ # <debug some stuff>
18
+ a2km rm-argv python3-copy -- debug
19
+
20
+ ## Kernelspecs for environments
21
+
22
+ a2km has an `env-kernel` subcommand for creating kernelspecs for your conda or virtual environments.
23
+ Just pass a2km the name of the env, and you should be set:
24
+
25
+ conda create -n myenv ipykernel
26
+ a2km env-kernel myenv
27
+
28
+
29
+ ## Commands
30
+
31
+ add-argv Add argument(s) to a kernelspec launch command
32
+ add-env Add environment variables to a kernelspec
33
+ clone Clone a kernelspec
34
+ env-kernel Create a kernel from an env (conda or virtualenv)
35
+ help Display global or [command] help documentation
36
+ locate Print the path of a kernelspec
37
+ rename Rename a kernelspec
38
+ rm Remove a kernelspec
39
+ rm-argv Remove arguments from a kernelspec launch command
40
+ rm-env Remove environment variables from a kernelspec
41
+ set Set a value in the kernelspec
42
+ show Show info about a kernelspec
43
+
44
+
45
+ ![Assistant TO the Kernel Manager](http://i.imgur.com/F0WLaYR.jpg)
data/a2km.gemspec ADDED
@@ -0,0 +1,21 @@
1
+ require File.dirname(__FILE__) + '/lib/a2km/version'
2
+ require 'date'
3
+
4
+ Gem::Specification.new do |s|
5
+ s.require_paths = ["lib"]
6
+ s.name = 'a2km'
7
+ s.version = A2KM::VERSION
8
+ s.date = Date.today.to_s
9
+ s.summary = 'Assistant to the Kernel Manager'
10
+ s.description = 'Working with Juptyer kernels'
11
+ s.authors = ['Min RK']
12
+ s.email = 'benjaminrk@gmail.com'
13
+ s.homepage = 'http://github.com/minrk/a2km'
14
+ s.license = 'BSD'
15
+ s.executables = ['a2km']
16
+ s.files = `git ls-files`.split($/)
17
+ s.require_paths = %w(lib)
18
+ s.add_runtime_dependency 'commander'
19
+ s.add_runtime_dependency 'highline'
20
+ s.add_runtime_dependency 'liquid'
21
+ end
data/bin/a2km CHANGED
@@ -1,286 +1,5 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
- require 'json'
3
+ require File.expand_path('../lib/a2km', __dir__)
4
4
 
5
- require 'rubygems'
6
- require 'commander'
7
- require 'highline'
8
-
9
-
10
- class AssitantToTheKernelManager
11
- include Commander::Methods
12
-
13
- def initialize
14
- @kernels = nil
15
- end
16
-
17
- def kernels
18
- if @kernels.nil?
19
- js = JSON.parse `jupyter kernelspec list --json`
20
- @kernels = js['kernelspecs']
21
- end
22
- @kernels
23
- end
24
-
25
- def kernel_dirs
26
- paths = JSON.parse `jupyter --paths --json`
27
- paths['data'].map do |p|
28
- p + '/' + 'kernels'
29
- end
30
- end
31
-
32
- def user_kernel_dir
33
- kernel_dirs.first
34
- end
35
-
36
- def get_kernel(name)
37
- "Get a kernel by name. Die with message if not found."
38
- if not kernels.has_key? name
39
- STDERR.puts "No such kernel: #{name}"
40
- STDERR.puts "Found kernels: #{kernels.keys.sort.join(' ')}"
41
- exit(-1)
42
- end
43
- kernels[name]
44
- end
45
-
46
- def kernel_json_path(name)
47
- "Return path to a kernel's kernel.json"
48
- kernel = get_kernel(name)
49
- File.join(kernel['resources_dir'], 'kernel.json')
50
- end
51
-
52
- def get_kernel_json(name)
53
- "Return kernel.json contents for a given kernelspec"
54
- File.open(kernel_json_path(name)) do |f|
55
- return JSON.parse f.read
56
- end
57
- end
58
-
59
- def save_kernel_json(name, data)
60
- "save new kernel JSON"
61
- File.open(kernel_json_path(name), 'w') do |f|
62
- f.write JSON.pretty_generate(data)
63
- end
64
- end
65
-
66
- def run
67
- program :name, 'Assistant to the KernelManager'
68
- program :version, '0.0.1'
69
- program :description, 'Work with Jupyter kernelspecs'
70
-
71
- command :rename do |c|
72
- c.syntax = 'a2km rename <from> <to>'
73
- c.summary = 'Rename a kernelspec'
74
- c.description = 'Rename kernelspec FROM to TO'
75
- c.action do |args, options|
76
- from = args.shift
77
- to = args.shift
78
- kernel = get_kernel(from)
79
- src = kernel['resources_dir']
80
-
81
- dst = File.join File.dirname(src), to
82
- if File.exists? dst
83
- STDERR.puts "Destination already exists: #{dst}"
84
- exit(-1)
85
- end
86
-
87
- puts "Moving #{src} → #{dst}"
88
- FileUtils.mv src, dst
89
- end
90
- end
91
-
92
- command :show do |c|
93
- c.syntax = 'a2km show <spec>'
94
- c.description = 'Show info about a kernelspec'
95
- c.action do |args, options|
96
- name = args.first
97
- kernel = get_kernel(name)
98
- spec = kernel['spec']
99
- puts "Kernel: #{name} (#{spec['display_name']})"
100
- puts " path: #{kernel['resources_dir']}"
101
- puts " argv: #{spec['argv'].join(' ')}"
102
- end
103
- end
104
-
105
- command :locate do |c|
106
- c.syntax = 'a2km locate <spec>'
107
- c.description = 'Print the path of a kernelspec'
108
- c.action do |args, options|
109
- puts get_kernel(args.first)['resources_dir']
110
- end
111
- end
112
-
113
- command :"add-argv" do |c|
114
- c.syntax = 'a2km add-argv <spec> <arg1> [arg2] ...'
115
- c.description = 'Add argument(s) to a kernelspec launch command'
116
- c.action do |args, options|
117
- name = args.shift
118
- kernelspec = get_kernel_json(name)
119
- kernelspec['argv'] += args
120
- save_kernel_json(name, kernelspec)
121
- puts "New argv: #{kernelspec['argv'].join(' ')}"
122
- end
123
- end
124
-
125
- command :"rm-argv" do |c|
126
- c.syntax = 'a2km rm-argv <spec> <arg1> [arg2] ...'
127
- c.summary = 'Remove arguments from a kernelspec launch command'
128
- c.description = c.summary + ". To remove args starting with '-'," \
129
- " use '--'."
130
- c.examples = [
131
- "a2km rm-argv myspec x",
132
- "a2km rm-argv myspec -- --debug",
133
- ]
134
- c.action do |args, options|
135
- name = args.shift
136
- to_remove = args
137
- kernelspec = get_kernel_json(name)
138
- argv = kernelspec['argv']
139
- argv.reject! { |arg| to_remove.include? arg }
140
- save_kernel_json(name, kernelspec)
141
- puts "New argv: #{argv.join(' ')}"
142
- end
143
- end
144
-
145
- command :"add-env" do |c|
146
- c.syntax = 'a2km add-env <spec> <key=value> [key=value] ...'
147
- c.summary = 'Add environment variables to a kernelspec'
148
- c.description = 'Add environment variables to a kernelspec.' \
149
- ' If no value is given, the value from the current env is used.'
150
- c.action do |args, options|
151
- name = args.shift
152
- spec = get_kernel_json(name)
153
- if not spec.has_key? 'env'
154
- spec['env'] = {}
155
- end
156
- env = spec['env']
157
- args.each do |arg|
158
- key_value = arg.split('=', 2)
159
- key = key_value.first
160
- if key_value.length == 2
161
- value = key_value[1]
162
- else
163
- value = ENV[key]
164
- end
165
- env[key] = value
166
- end
167
- save_kernel_json(name, spec)
168
- puts "New env: #{env}"
169
- end
170
- end
171
-
172
- command :"rm-env" do |c|
173
- c.syntax = 'a2km rm-env <spec> <key> [key] ...'
174
- c.description = 'Remove environment variables from a kernelspec'
175
- c.action do |args, options|
176
- name = args.shift
177
- spec = get_kernel_json(name)
178
- if not spec.has_key? 'env'
179
- spec['env'] = {}
180
- end
181
- env = spec['env']
182
- args.each do |arg|
183
- env.delete(arg)
184
- end
185
- save_kernel_json(name, spec)
186
- puts "New env: #{env}"
187
- end
188
- end
189
-
190
- command :rm do |c|
191
- c.syntax = 'a2km rm <spec>'
192
- c.description = 'Remove a kernelspec'
193
- c.option '-f', "Force removal (skip confirmation)"
194
- c.action do |args, options|
195
- name = args.shift
196
- if not kernels.has_key? name
197
- STDERR.puts "No such kernel: #{name}"
198
- STDERR.puts "Found kernels: #{kernels.keys.sort.join(' ')}"
199
- exit(-1)
200
- end
201
- path = kernels[name]['resources_dir']
202
- if options.f or not HighLine.agree("Permanently delete #{path}? (yes/no)")
203
- STDERR.puts "Aborting."
204
- exit(-1)
205
- end
206
- puts "Removing #{path}"
207
- FileUtils.rm_r path
208
- end
209
- end
210
-
211
- command :set do |c|
212
- c.syntax = 'a2km set <name> <key> <value>'
213
- c.description = 'Set a value in the kernelspec'
214
- c.examples = [
215
- 'a2km set python3 display_name "My Python 3"'
216
- ]
217
- c.action do |args, options|
218
- name = args.shift
219
- key = args.shift
220
- value = args.shift
221
- if value.nil?
222
- STDERR.puts c.syntax
223
- exit(-1)
224
- end
225
- puts "Setting #{name}.#{key} = '#{value}'"
226
- spec = get_kernel_json(name)
227
- spec[key] = value
228
- save_kernel_json(name, spec)
229
- end
230
- end
231
-
232
- command :clone do |c|
233
- c.syntax = 'a2km clone <from> <to> [display_name]'
234
- c.summary = 'Clone a kernelspec'
235
- c.description = 'Clones kernelspec FROM to TO'
236
- c.option '--user', 'Force clone to be in the user directory' \
237
- ' (default is to use the same directory as FROM)'
238
- c.action do |args, options|
239
- options.default :user => false
240
-
241
- if args.length < 2 or args.length > 3
242
- STDERR.puts "Must specify FROM and TO"
243
- exit(-1)
244
- end
245
- from_name = args.shift
246
- to_name = args.shift
247
- if args.length > 0
248
- display_name = args.shift
249
- else
250
- display_name = to_name
251
- end
252
-
253
- from = get_kernel(from_name)
254
- from = kernels[from_name]
255
- src = from['resources_dir']
256
-
257
- if options.user?
258
- dst_dir = user_kernel_dir
259
- makedirs(dst_dir)
260
- else
261
- dst_dir = File.dirname src
262
- end
263
- dst = File.join dst_dir, to_name
264
- if File.exists? dst
265
- STDERR.puts "Destination already exists: #{dst}"
266
- exit(-1)
267
- end
268
-
269
- puts "Cloning #{src} → #{dst}"
270
- FileUtils.cp_r src, dst
271
- kernel_json = File.join(dst, 'kernel.json')
272
- kernelspec = File.open(kernel_json) do |f|
273
- JSON.parse f.read
274
- end
275
- kernelspec['display_name'] = display_name
276
- File.open(kernel_json, 'w') do |f|
277
- f.write JSON.pretty_generate(kernelspec)
278
- end
279
- end
280
- end
281
-
282
- run!
283
- end
284
- end
285
-
286
- AssitantToTheKernelManager.new.run
5
+ A2KM::run
data/lib/a2km.rb ADDED
@@ -0,0 +1,4 @@
1
+ require __dir__ + '/a2km/version'
2
+ require __dir__ + '/a2km/api'
3
+ require __dir__ + '/a2km/env'
4
+ require __dir__ + '/a2km/command'
data/lib/a2km/api.rb ADDED
@@ -0,0 +1,59 @@
1
+ # Copyright Min RK, License: BSD 3-clause
2
+
3
+ require 'json'
4
+
5
+ module A2KM
6
+
7
+ def initialize
8
+ @kernels = nil
9
+ end
10
+
11
+ def A2KM.kernels
12
+ if @kernels.nil?
13
+ js = JSON.parse `jupyter kernelspec list --json`
14
+ @kernels = js['kernelspecs']
15
+ end
16
+ @kernels
17
+ end
18
+
19
+ def A2KM.kernel_dirs
20
+ paths = JSON.parse `jupyter --paths --json`
21
+ paths['data'].map do |p|
22
+ p + '/' + 'kernels'
23
+ end
24
+ end
25
+
26
+ def A2KM.user_kernel_dir
27
+ kernel_dirs.first
28
+ end
29
+
30
+ def A2KM.get_kernel(name)
31
+ "Get a kernel by name. Die with message if not found."
32
+ if not kernels.has_key? name
33
+ STDERR.puts "No such kernel: #{name}"
34
+ STDERR.puts "Found kernels: #{kernels.keys.sort.join(' ')}"
35
+ exit(-1)
36
+ end
37
+ kernels[name]
38
+ end
39
+
40
+ def A2KM.kernel_json_path(name)
41
+ "Return path to a kernel's kernel.json"
42
+ kernel = get_kernel(name)
43
+ File.join(kernel['resources_dir'], 'kernel.json')
44
+ end
45
+
46
+ def A2KM.get_kernel_json(name)
47
+ "Return kernel.json contents for a given kernelspec"
48
+ File.open(kernel_json_path(name)) do |f|
49
+ return JSON.parse f.read
50
+ end
51
+ end
52
+
53
+ def A2KM.save_kernel_json(name, data)
54
+ "save new kernel JSON"
55
+ File.open(kernel_json_path(name), 'w') do |f|
56
+ f.write JSON.pretty_generate(data)
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,263 @@
1
+ # Copyright Min RK, License: BSD 3-clause
2
+
3
+ require 'json'
4
+
5
+ require 'rubygems'
6
+ require 'commander'
7
+ require 'highline'
8
+
9
+ module A2KM
10
+
11
+ # Start the a2km entrypoint
12
+ def A2KM.run
13
+ CLI.new.run
14
+ end
15
+
16
+ # The A2KM CLI entrypoint
17
+ class CLI
18
+ include Commander::Methods
19
+
20
+ def run
21
+ program :name, 'Assistant to the KernelManager'
22
+ program :version, VERSION
23
+ program :description, 'Work with Jupyter kernelspecs'
24
+
25
+ command :rename do |c|
26
+ c.syntax = 'a2km rename <from> <to>'
27
+ c.summary = 'Rename a kernelspec'
28
+ c.description = 'Rename kernelspec FROM to TO'
29
+ c.action do |args, options|
30
+ from = args.shift
31
+ to = args.shift
32
+ kernel = A2KM.get_kernel(from)
33
+ src = kernel['resources_dir']
34
+
35
+ dst = File.join File.dirname(src), to
36
+ if File.exists? dst
37
+ STDERR.puts "Destination already exists: #{dst}"
38
+ exit(-1)
39
+ end
40
+
41
+ puts "Moving #{src} → #{dst}"
42
+ FileUtils.mv src, dst
43
+ end
44
+ end
45
+
46
+ command :show do |c|
47
+ c.syntax = 'a2km show <spec>'
48
+ c.description = 'Show info about a kernelspec'
49
+ c.action do |args, options|
50
+ name = args.first
51
+ kernel = A2KM.get_kernel(name)
52
+ spec = kernel['spec']
53
+ puts "Kernel: #{name} (#{spec['display_name']})"
54
+ puts " path: #{kernel['resources_dir']}"
55
+ puts " argv: #{spec['argv'].join(' ')}"
56
+ end
57
+ end
58
+
59
+ command :locate do |c|
60
+ c.syntax = 'a2km locate <spec>'
61
+ c.description = 'Print the path of a kernelspec'
62
+ c.action do |args, options|
63
+ puts A2KM.get_kernel(args.first)['resources_dir']
64
+ end
65
+ end
66
+
67
+ command :"add-argv" do |c|
68
+ c.syntax = 'a2km add-argv <spec> <arg1> [arg2] ...'
69
+ c.description = 'Add argument(s) to a kernelspec launch command'
70
+ c.action do |args, options|
71
+ name = args.shift
72
+ kernelspec = A2KM.get_kernel_json(name)
73
+ kernelspec['argv'] += args
74
+ A2KM.save_kernel_json(name, kernelspec)
75
+ puts "New argv: #{kernelspec['argv'].join(' ')}"
76
+ end
77
+ end
78
+
79
+ command :"rm-argv" do |c|
80
+ c.syntax = 'a2km rm-argv <spec> <arg1> [arg2] ...'
81
+ c.summary = 'Remove arguments from a kernelspec launch command'
82
+ c.description = c.summary + ". To remove args starting with '-'," \
83
+ " use '--'."
84
+ c.examples = [
85
+ "a2km rm-argv myspec x",
86
+ "a2km rm-argv myspec -- --debug",
87
+ ]
88
+ c.action do |args, options|
89
+ name = args.shift
90
+ to_remove = args
91
+ kernelspec = A2KM.get_kernel_json(name)
92
+ argv = kernelspec['argv']
93
+ argv.reject! { |arg| to_remove.include? arg }
94
+ A2KM.save_kernel_json(name, kernelspec)
95
+ puts "New argv: #{argv.join(' ')}"
96
+ end
97
+ end
98
+
99
+ command :"add-env" do |c|
100
+ c.syntax = 'a2km add-env <spec> <key=value> [key=value] ...'
101
+ c.summary = 'Add environment variables to a kernelspec'
102
+ c.description = 'Add environment variables to a kernelspec.' \
103
+ ' If no value is given, the value from the current env is used.'
104
+ c.action do |args, options|
105
+ name = args.shift
106
+ spec = A2KM.get_kernel_json(name)
107
+ if not spec.has_key? 'env'
108
+ spec['env'] = {}
109
+ end
110
+ env = spec['env']
111
+ args.each do |arg|
112
+ key_value = arg.split('=', 2)
113
+ key = key_value.first
114
+ if key_value.length == 2
115
+ value = key_value[1]
116
+ else
117
+ value = ENV[key]
118
+ end
119
+ env[key] = value
120
+ end
121
+ A2KM.save_kernel_json(name, spec)
122
+ puts "New env: #{env}"
123
+ end
124
+ end
125
+
126
+ command :"rm-env" do |c|
127
+ c.syntax = 'a2km rm-env <spec> <key> [key] ...'
128
+ c.description = 'Remove environment variables from a kernelspec'
129
+ c.action do |args, options|
130
+ name = args.shift
131
+ spec = A2KM.get_kernel_json(name)
132
+ if not spec.has_key? 'env'
133
+ spec['env'] = {}
134
+ end
135
+ env = spec['env']
136
+ args.each do |arg|
137
+ env.delete(arg)
138
+ end
139
+ A2KM.save_kernel_json(name, spec)
140
+ puts "New env: #{env}"
141
+ end
142
+ end
143
+
144
+ command :rm do |c|
145
+ c.syntax = 'a2km rm <spec>'
146
+ c.description = 'Remove a kernelspec'
147
+ c.option '-f', "Force removal (skip confirmation)"
148
+ c.action do |args, options|
149
+ name = args.shift
150
+ if not A2KM.kernels.has_key? name
151
+ STDERR.puts "No such kernel: #{name}"
152
+ STDERR.puts "Found kernels: #{kernels.keys.sort.join(' ')}"
153
+ exit(-1)
154
+ end
155
+ path = A2KM.kernels[name]['resources_dir']
156
+ if options.f or not HighLine.agree("Permanently delete #{path}? (yes/no)")
157
+ STDERR.puts "Aborting."
158
+ exit(-1)
159
+ end
160
+ puts "Removing #{path}"
161
+ FileUtils.rm_r path
162
+ end
163
+ end
164
+
165
+ command :"env-kernel" do |c|
166
+ c.syntax = 'a2km env-kernel [--venv|--conda] <name> [-e env-name] [--prefix PREFIX] [--user]'
167
+ c.description = 'Create a kernel from an env (conda or virtualenv)'
168
+
169
+ c.option '--conda', "use conda env (default)"
170
+ c.option '--venv', "use virtualenv"
171
+ c.option '-e ENV', "specify the environment name to use (if different from <name>)"
172
+ c.option '--prefix PREFIX', 'specify the prefix for the executable to be installed'
173
+ c.action do |args, options|
174
+ name = args.shift
175
+ options.default :user => false
176
+ options.default :e => name
177
+ options.default :prefix => '~'
178
+ env = options.e
179
+
180
+ kind = 'conda'
181
+ if options.venv
182
+ kind = 'venv'
183
+ end
184
+ puts "Making kernel '#{name}' for #{kind}:#{env}"
185
+ spec = A2KM::make_env_kernel(name, env, kind: kind, prefix: options.prefix)
186
+ end
187
+ end
188
+
189
+ command :set do |c|
190
+ c.syntax = 'a2km set <name> <key> <value>'
191
+ c.description = 'Set a value in the kernelspec'
192
+ c.examples = [
193
+ 'a2km set python3 display_name "My Python 3"'
194
+ ]
195
+ c.action do |args, options|
196
+ name = args.shift
197
+ key = args.shift
198
+ value = args.shift
199
+ if value.nil?
200
+ STDERR.puts c.syntax
201
+ exit(-1)
202
+ end
203
+ puts "Setting #{name}.#{key} = '#{value}'"
204
+ spec = A2KM.get_kernel_json(name)
205
+ spec[key] = value
206
+ A2KM.save_kernel_json(name, spec)
207
+ end
208
+ end
209
+
210
+ command :clone do |c|
211
+ c.syntax = 'a2km clone <from> <to> [display_name]'
212
+ c.summary = 'Clone a kernelspec'
213
+ c.description = 'Clones kernelspec FROM to TO'
214
+ c.option '--user', 'Force clone to be in the user directory' \
215
+ ' (default is to use the same directory as FROM)'
216
+ c.action do |args, options|
217
+ options.default :user => false
218
+
219
+ if args.length < 2 or args.length > 3
220
+ STDERR.puts "Must specify FROM and TO"
221
+ exit(-1)
222
+ end
223
+ from_name = args.shift
224
+ to_name = args.shift
225
+ if args.length > 0
226
+ display_name = args.shift
227
+ else
228
+ display_name = to_name
229
+ end
230
+
231
+ from = A2KM.get_kernel(from_name)
232
+ from = A2KM.kernels[from_name]
233
+ src = from['resources_dir']
234
+
235
+ if options.user?
236
+ dst_dir = A2KM.user_kernel_dir
237
+ makedirs(dst_dir)
238
+ else
239
+ dst_dir = File.dirname src
240
+ end
241
+ dst = File.join dst_dir, to_name
242
+ if File.exists? dst
243
+ STDERR.puts "Destination already exists: #{dst}"
244
+ exit(-1)
245
+ end
246
+
247
+ puts "Cloning #{src} → #{dst}"
248
+ FileUtils.cp_r src, dst
249
+ kernel_json = File.join(dst, 'kernel.json')
250
+ kernelspec = File.open(kernel_json) do |f|
251
+ JSON.parse f.read
252
+ end
253
+ kernelspec['display_name'] = display_name
254
+ File.open(kernel_json, 'w') do |f|
255
+ f.write JSON.pretty_generate(kernelspec)
256
+ end
257
+ end
258
+ end
259
+
260
+ run!
261
+ end
262
+ end
263
+ end
data/lib/a2km/env.rb ADDED
@@ -0,0 +1,104 @@
1
+ # Copyright Min RK, License: BSD 3-clause
2
+
3
+ require 'Open3'
4
+ require 'liquid'
5
+
6
+ class ENVError < StandardError
7
+ end
8
+
9
+ module A2KM
10
+
11
+ module ENV_UTILS
12
+
13
+ ACTIVATE_TPL_S = "{{activate}} {{name}}"
14
+ ACTIVATE_TPL = Liquid::Template.parse ACTIVATE_TPL_S
15
+ ENV_CMD_TPL = Liquid::Template.parse(<<-END
16
+ #!/usr/bin/env bash
17
+ set -e
18
+ #{ACTIVATE_TPL_S}
19
+ exec python -m ipykernel $@
20
+ END
21
+ )
22
+
23
+ CONDA_ACTIVATE = 'source activate'
24
+ VIRTUALENV_ACTIVATE = 'workon'
25
+
26
+ module_function
27
+
28
+ def activate_cmd(kind)
29
+ case kind
30
+ when 'conda'
31
+ return CONDA_ACTIVATE
32
+ when 'venv'
33
+ return VIRTUALENV_ACTIVATE
34
+ else
35
+ throw ArgumentError, "kind must be 'conda' or 'venv', not '#{kind}'"
36
+ end
37
+ end
38
+
39
+ def in_env(env, cmd, kind: 'conda')
40
+ Open3::popen2('bash') do |stdin, stdout, wait_thr|
41
+ stdin.puts 'set -e'
42
+ stdin.puts ACTIVATE_TPL.render('name' => env, 'activate' => activate_cmd(kind))
43
+ stdin.puts cmd
44
+ stdin.close
45
+ status = wait_thr.value
46
+ if status != 0
47
+ raise ENVError.new("Failed to run #{cmd} in #{kind} env: #{env}")
48
+ end
49
+ return stdout.read
50
+ end
51
+ end
52
+
53
+ def kernel_script(name, kind: 'conda')
54
+ # return kernel script as a string
55
+ ENV_CMD_TPL.render('name' => name, 'activate' => activate_cmd(kind))
56
+ end
57
+
58
+ def ipykernel_version(env, kind: 'conda')
59
+ in_env(env, "python -c 'import ipykernel; print(ipykernel.__version__)'", kind: kind)
60
+ end
61
+
62
+ def make_kernel_exe(kernel_name, env_name, kind: 'conda', prefix: '/usr/local')
63
+ cmd = kernel_script(env_name, kind: kind)
64
+ bin = File.join(prefix, 'bin')
65
+ if not File.directory? bin
66
+ FileUtils.mkdir bin
67
+ end
68
+ kernel_exe = File.join(bin, "jupyter-kernel-#{kernel_name}")
69
+ puts "Making executable '#{kernel_exe}'"
70
+
71
+ File.open(kernel_exe, 'w') do |f|
72
+ f.write(cmd)
73
+ end
74
+ File.chmod(0o755, kernel_exe)
75
+ return kernel_exe
76
+ end
77
+
78
+ def get_prefix(name, kind)
79
+ in_env(name, 'python -c "import sys; print(sys.prefix)"', kind: kind)
80
+ end
81
+ end
82
+
83
+ def self.make_env_kernel(kernel_name, env_name, kind: 'conda', prefix: '/usr/local', user: true)
84
+ prefix = File.expand_path(prefix)
85
+ v = ENV_UTILS.ipykernel_version(env_name, kind: kind)
86
+
87
+ puts "Found ipykernel-#{v}"
88
+
89
+ exe = ENV_UTILS.make_kernel_exe(kernel_name, env_name, kind: kind, prefix: prefix)
90
+ if user
91
+ user_arg = '--user'
92
+ else
93
+ user_arg = ''
94
+ end
95
+
96
+ ENV_UTILS.in_env(env_name, "python -m ipykernel.kernelspec --name #{kernel_name} #{user_arg}", kind: kind)
97
+ spec = A2KM.get_kernel_json(kernel_name)
98
+ spec['argv'] = [exe, '-f', '{connection_file}']
99
+ spec['display_name'] = "#{spec['display_name']} (#{kind}:#{env_name})"
100
+ A2KM.save_kernel_json(kernel_name, spec)
101
+
102
+ end
103
+
104
+ end
@@ -0,0 +1,5 @@
1
+ # Copyright Min RK, License: BSD 3-clause
2
+
3
+ module A2KM
4
+ VERSION = '0.0.2'
5
+ end
metadata CHANGED
@@ -1,15 +1,57 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: a2km
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.0.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Min RK
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-08-18 00:00:00.000000000 Z
12
- dependencies: []
11
+ date: 2015-09-09 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: commander
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: highline
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: liquid
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
13
55
  description: Working with Juptyer kernels
14
56
  email: benjaminrk@gmail.com
15
57
  executables:
@@ -17,7 +59,16 @@ executables:
17
59
  extensions: []
18
60
  extra_rdoc_files: []
19
61
  files:
62
+ - ".gitignore"
63
+ - LICENSE
64
+ - README.md
65
+ - a2km.gemspec
20
66
  - bin/a2km
67
+ - lib/a2km.rb
68
+ - lib/a2km/api.rb
69
+ - lib/a2km/command.rb
70
+ - lib/a2km/env.rb
71
+ - lib/a2km/version.rb
21
72
  homepage: http://github.com/minrk/a2km
22
73
  licenses:
23
74
  - BSD
@@ -36,11 +87,9 @@ required_rubygems_version: !ruby/object:Gem::Requirement
36
87
  - - ">="
37
88
  - !ruby/object:Gem::Version
38
89
  version: '0'
39
- requirements:
40
- - commander
41
- - highline
90
+ requirements: []
42
91
  rubyforge_project:
43
- rubygems_version: 2.4.5
92
+ rubygems_version: 2.4.5.1
44
93
  signing_key:
45
94
  specification_version: 4
46
95
  summary: Assistant to the Kernel Manager