learn-open 1.2.20 → 1.2.21

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (40) hide show
  1. checksums.yaml +5 -5
  2. data/.gitignore +4 -0
  3. data/Guardfile +70 -0
  4. data/learn-open.gemspec +7 -1
  5. data/lib/learn_open.rb +66 -0
  6. data/lib/learn_open/adapters/io_adapter.rb +24 -0
  7. data/lib/learn_open/adapters/learn_web_adapter.rb +103 -0
  8. data/lib/learn_open/adapters/system_adapter.rb +30 -0
  9. data/lib/learn_open/environments.rb +35 -0
  10. data/lib/learn_open/environments/base_environment.rb +70 -0
  11. data/lib/learn_open/environments/generic_environment.rb +9 -0
  12. data/lib/learn_open/environments/ide_environment.rb +63 -0
  13. data/lib/learn_open/environments/jupyter_container_environment.rb +28 -0
  14. data/lib/learn_open/environments/linux_environment.rb +17 -0
  15. data/lib/learn_open/environments/mac_environment.rb +75 -0
  16. data/lib/learn_open/lessons.rb +24 -0
  17. data/lib/learn_open/lessons/base_lesson.rb +57 -0
  18. data/lib/learn_open/lessons/ios_lesson.rb +14 -0
  19. data/lib/learn_open/lessons/jupyter_lesson.rb +14 -0
  20. data/lib/learn_open/lessons/lab_lesson.rb +9 -0
  21. data/lib/learn_open/lessons/readme_lesson.rb +13 -0
  22. data/lib/learn_open/opener.rb +26 -469
  23. data/lib/learn_open/services/dependency_installers.rb +19 -0
  24. data/lib/learn_open/services/dependency_installers/base_installer.rb +21 -0
  25. data/lib/learn_open/services/dependency_installers/gem_installer.rb +14 -0
  26. data/lib/learn_open/services/dependency_installers/jupyter_pip_installer.rb +14 -0
  27. data/lib/learn_open/services/dependency_installers/node_package_installer.rb +20 -0
  28. data/lib/learn_open/services/dependency_installers/pip_installer.rb +14 -0
  29. data/lib/learn_open/services/file_backup_starter.rb +20 -0
  30. data/lib/learn_open/services/lesson_downloader.rb +82 -0
  31. data/lib/learn_open/services/logger.rb +23 -0
  32. data/lib/learn_open/version.rb +1 -1
  33. data/spec/fakes/fake_git.rb +20 -0
  34. data/spec/fakes/fake_learn_client.rb +214 -0
  35. data/spec/fixtures/learn-config +3 -0
  36. data/spec/learn_open/environments/ide_environment_spec.rb +62 -0
  37. data/spec/learn_open/opener_spec.rb +789 -14
  38. data/spec/spec_helper.rb +41 -0
  39. metadata +121 -5
  40. data/spec/home_dir/.learn-config +0 -3
@@ -0,0 +1,9 @@
1
+ module LearnOpen
2
+ module Environments
3
+ class GenericEnvironment < BaseEnvironment
4
+ def open_readme(_lesson)
5
+ io.puts "It looks like this lesson is a Readme. Please open it in your browser."
6
+ end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,63 @@
1
+ module LearnOpen
2
+ module Environments
3
+ class IDEEnvironment < BaseEnvironment
4
+ def open_readme(lesson)
5
+ when_valid(lesson) do
6
+ warn_if_necessary(lesson)
7
+ io.puts "Opening readme..."
8
+ run_custom_command(:browser_open, {url: lesson.to_url})
9
+ end
10
+ end
11
+
12
+ def open_jupyter_lab(lesson, location, editor)
13
+ when_valid(lesson) do
14
+ warn_if_necessary(lesson)
15
+ io.puts "Opening Jupyter Lesson..."
16
+ run_custom_command(:browser_open, {url: lesson.to_url})
17
+ end
18
+ end
19
+
20
+ def open_lab(lesson, location, editor)
21
+ when_valid(lesson) do
22
+ warn_if_necessary(lesson)
23
+ case lesson
24
+ when LearnOpen::Lessons::IosLesson
25
+ super
26
+ when -> (l) { valid?(l) }
27
+ download_lesson(lesson, location)
28
+ open_editor(lesson, location, editor)
29
+ start_file_backup(lesson, location)
30
+ install_dependencies(lesson, location)
31
+ notify_of_completion
32
+ open_shell
33
+ end
34
+ end
35
+ end
36
+
37
+ def when_valid(lesson, &block)
38
+ if valid?(lesson)
39
+ block.call
40
+ else
41
+ on_invalid(lesson)
42
+ end
43
+ end
44
+
45
+ def valid?(lesson)
46
+ lesson.name == environment_vars['LAB_NAME']
47
+ end
48
+
49
+ def on_invalid(lesson)
50
+ io.puts "Opening new window"
51
+ run_custom_command(:open_lab, {lab_name: lesson.name})
52
+ end
53
+
54
+ def run_custom_command(command, message)
55
+ home_dir = "/home/#{environment_vars['CREATED_USER']}"
56
+ custom_commands_log = "#{home_dir}/.custom_commands.log"
57
+ File.open(custom_commands_log, "a") do |f|
58
+ f.puts({:command => command}.merge(message).to_json)
59
+ end
60
+ end
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,28 @@
1
+ module LearnOpen
2
+ module Environments
3
+ class JupyterContainerEnvironment < BaseEnvironment
4
+ def open_jupyter_lab(lesson, location, editor)
5
+ download_lesson(lesson, location)
6
+ open_editor(lesson, location, editor)
7
+ start_file_backup(lesson, location)
8
+ install_jupyter_dependencies(lesson, location)
9
+ notify_of_completion
10
+ open_shell
11
+ end
12
+
13
+ def open_editor(lesson, location, editor)
14
+ io.puts "Opening lesson..."
15
+ system_adapter.change_context_directory(lesson.to_path)
16
+ system_adapter.open_editor(editor, path: ".")
17
+ end
18
+
19
+ def install_jupyter_dependencies(lesson, location)
20
+ LearnOpen::DependencyInstallers::JupyterPipInstall.call(lesson, location, self, options)
21
+ end
22
+
23
+ def open_shell
24
+ system_adapter.open_login_shell(environment_vars['SHELL'])
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,17 @@
1
+ module LearnOpen
2
+ module Environments
3
+ class LinuxEnvironment < BaseEnvironment
4
+ def open_readme(lesson)
5
+ warn_if_necessary(lesson)
6
+ io.puts "Opening readme..."
7
+ system_adapter.run_command("xdg-open #{lesson.to_url}")
8
+ end
9
+
10
+ def open_jupyter_lab(lesson, location, editor)
11
+ warn_if_necessary(lesson)
12
+ io.puts "Opening Jupyter Lesson..."
13
+ system_adapter.run_command("xdg-open #{lesson.to_url}")
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,75 @@
1
+ module LearnOpen
2
+ module Environments
3
+ class MacEnvironment < BaseEnvironment
4
+ def self.classify(options)
5
+ if chrome_installed?
6
+ MacWithChromeEnvironment.new(options)
7
+ else
8
+ self.new(options)
9
+ end
10
+ end
11
+
12
+ def self.chrome_installed?
13
+ File.exists?('/Applications/Google Chrome.app')
14
+ end
15
+
16
+ def open_readme(lesson)
17
+ warn_if_necessary(lesson)
18
+ io.puts "Opening readme..."
19
+ system_adapter.run_command("open -a Safari #{lesson.to_url}")
20
+ end
21
+
22
+ def open_lab(lesson, location, editor)
23
+ warn_if_necessary(lesson)
24
+ case lesson
25
+ when LearnOpen::Lessons::IosLesson
26
+ download_lesson(lesson, location)
27
+ open_xcode(lesson)
28
+ notify_of_completion
29
+ open_shell
30
+ else
31
+ super
32
+ end
33
+ end
34
+
35
+ def open_jupyter_lab(lesson, location, editor)
36
+ warn_if_necessary(lesson)
37
+ io.puts "Opening Jupyter Lesson..."
38
+ system_adapter.run_command("open -a Safari #{lesson.to_url}")
39
+ end
40
+
41
+ def xcodeproj_file?(lesson)
42
+ Dir.glob("#{lesson.to_path}/*.xcodeproj").any?
43
+ end
44
+
45
+ def xcworkspace_file?(lesson)
46
+ Dir.glob("#{lesson.to_path}/*.xcworkspace").any?
47
+ end
48
+
49
+ def open_xcode(lesson)
50
+ io.puts "Opening lesson..."
51
+ system_adapter.change_context_directory("#{lesson.to_path}")
52
+ if xcworkspace_file?(lesson)
53
+ system_adapter.run_command("cd #{lesson.to_path} && open *.xcworkspace")
54
+ elsif xcodeproj_file?(lesson)
55
+ system_adapter.run_command("cd #{lesson.to_path} && open *.xcodeproj")
56
+ end
57
+ end
58
+ end
59
+
60
+ class MacWithChromeEnvironment < MacEnvironment
61
+ def open_readme(lesson)
62
+ warn_if_necessary(lesson)
63
+ io.puts "Opening readme..."
64
+ system_adapter.run_command("open -a 'Google Chrome' #{lesson.to_url}")
65
+ end
66
+
67
+ def open_jupyter_lab(lesson, location, editor)
68
+ warn_if_necessary(lesson)
69
+ io.puts "Opening Jupyter Lesson..."
70
+ system_adapter.run_command("open -a 'Google Chrome' #{lesson.to_url}")
71
+ end
72
+
73
+ end
74
+ end
75
+ end
@@ -0,0 +1,24 @@
1
+ module LearnOpen
2
+ module Lessons
3
+
4
+ def self.default
5
+ LabLesson
6
+ end
7
+
8
+ def self.lesson_types
9
+ [
10
+ JupyterLesson,
11
+ ReadmeLesson,
12
+ IosLesson,
13
+ ]
14
+ end
15
+
16
+ def self.classify(lesson_data, options = {})
17
+ lesson = lesson_data[:lesson]
18
+ default = method(:default)
19
+ lesson_types.find(default) do |type|
20
+ type.detect(lesson)
21
+ end.new(lesson_data, options)
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,57 @@
1
+ module LearnOpen
2
+ module Lessons
3
+ class BaseLesson
4
+ attr_reader :repo_path,
5
+ :organization,
6
+ :name,
7
+ :id,
8
+ :dot_learn,
9
+ :git_server,
10
+ :later_lesson,
11
+ :options,
12
+ :io,
13
+ :system_adapter,
14
+ :platform,
15
+ :environment_vars,
16
+ :logger,
17
+ :location
18
+
19
+ def initialize(lesson_data, options = {})
20
+ lesson = lesson_data[:lesson]
21
+
22
+ @repo_path = lesson.clone_repo
23
+ @organization, @name = repo_path.split('/')
24
+
25
+ @git_server = lesson.git_server
26
+ @dot_learn = lesson.dot_learn
27
+ @is_lab = lesson.lab
28
+ @later_lesson = lesson_data[:later_lesson]
29
+ @id = lesson_data[:id]
30
+
31
+ @logger = options.fetch(:logger, LearnOpen.logger)
32
+ @io = options.fetch(:io, LearnOpen.default_io)
33
+ @system_adapter = options.fetch(:system_adapter, LearnOpen.system_adapter)
34
+ @platform = options.fetch(:platform, LearnOpen.platform)
35
+ @environment_vars = options.fetch(:environment_vars, LearnOpen.environment_vars)
36
+ @location = options.fetch(:lessons_directory) {LearnOpen.lessons_directory}
37
+ @options = options
38
+ end
39
+
40
+ def lab?
41
+ @is_lab
42
+ end
43
+
44
+ def readme?
45
+ !lab?
46
+ end
47
+
48
+ def to_path
49
+ "#{location}/#{name}"
50
+ end
51
+
52
+ def to_url
53
+ "https://learn.co/lessons/#{id}"
54
+ end
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,14 @@
1
+ module LearnOpen
2
+ module Lessons
3
+ class IosLesson < BaseLesson
4
+ def self.detect(lesson)
5
+ languages = Hash(lesson.dot_learn)[:languages]
6
+ (languages & ["swift", "objc"]).any?
7
+ end
8
+
9
+ def open(environment, editor)
10
+ environment.open_lab(self, location, editor)
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,14 @@
1
+ module LearnOpen
2
+ module Lessons
3
+ class JupyterLesson < BaseLesson
4
+ def self.detect(lesson)
5
+ dot_learn = Hash(lesson.dot_learn)
6
+ !!dot_learn[:jupyter_notebook]
7
+ end
8
+
9
+ def open(environment, editor)
10
+ environment.open_jupyter_lab(self, location, editor)
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,9 @@
1
+ module LearnOpen
2
+ module Lessons
3
+ class LabLesson < BaseLesson
4
+ def open(environment, editor)
5
+ environment.open_lab(self, location, editor)
6
+ end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,13 @@
1
+ module LearnOpen
2
+ module Lessons
3
+ class ReadmeLesson < BaseLesson
4
+ def self.detect(lesson)
5
+ !lesson.lab
6
+ end
7
+
8
+ def open(environment, _editor)
9
+ environment.open_readme(self)
10
+ end
11
+ end
12
+ end
13
+ end
@@ -1,484 +1,41 @@
1
1
  module LearnOpen
2
2
  class Opener
3
- HOME_DIR = File.expand_path("~")
4
- attr_reader :editor, :client, :lessons_dir, :file_path, :get_next_lesson, :token
5
- attr_accessor :lesson, :repo_dir, :lesson_is_lab, :lesson_id, :later_lesson, :dot_learn
3
+ attr_reader :editor,
4
+ :target_lesson,
5
+ :get_next_lesson,
6
+ :io,
7
+ :logger,
8
+ :options
6
9
 
7
10
  def self.run(lesson:, editor_specified:, get_next_lesson:)
8
11
  new(lesson, editor_specified, get_next_lesson).run
9
12
  end
10
13
 
11
- def initialize(lesson, editor, get_next_lesson)
12
- _login, @token = Netrc.read['learn-config']
13
- @client = LearnWeb::Client.new(token: @token)
14
-
15
- @lesson = lesson
16
- @editor = editor
14
+ def initialize(target_lesson, editor, get_next_lesson, options = {})
15
+ @target_lesson = target_lesson
16
+ @editor = editor
17
17
  @get_next_lesson = get_next_lesson
18
- @lessons_dir = YAML.load(File.read("#{HOME_DIR}/.learn-config"))[:learn_directory]
19
- @file_path = "#{HOME_DIR}/.learn-open-tmp"
20
- end
21
-
22
- def run
23
- setup_tmp_file
24
-
25
- set_lesson
26
-
27
- if ide_version_3?
28
- if self.repo_dir != ENV['LAB_NAME']
29
- home_dir = "/home/#{ENV['CREATED_USER']}"
30
- File.open("#{home_dir}/.custom_commands.log", "a") do |f|
31
- f.puts %Q{{"command": "open_lab", "lab_name": "#{self.repo_dir}"}}
32
- end
33
- exit
34
- end
35
- end
36
-
37
- puts "Looking for lesson..."
38
-
39
- if jupyter_notebook_environment?
40
- git_tasks
41
- file_tasks
42
- restore_files
43
- watch_for_changes
44
- jupyter_pip_install
45
- completion_tasks
46
- else
47
- warn_if_necessary
48
- if lesson_is_readme?
49
- open_readme
50
- else
51
- git_tasks
52
- file_tasks
53
- setup_backup_if_needed
54
- dependency_tasks
55
- completion_tasks
56
- end
57
- end
58
-
59
- end
60
-
61
- def repo_exists?
62
- File.exists?("#{lessons_dir}/#{repo_dir}/.git")
63
- end
64
-
65
- private
66
-
67
- def setup_backup_if_needed
68
- if ide_environment? && ide_git_wip_enabled?
69
- restore_files
70
- watch_for_changes
71
- end
72
- end
73
-
74
- def ping_fork_completion(retries=3)
75
- begin
76
- Timeout::timeout(15) do
77
- client.submit_event(
78
- event: 'fork',
79
- learn_oauth_token: token,
80
- repo_name: repo_dir,
81
- base_org_name: lesson.split('/')[0],
82
- forkee: { full_name: nil }
83
- )
84
- end
85
- rescue Timeout::Error
86
- if retries > 0
87
- puts "There was a problem forking and cloning this lesson. Retrying..."
88
- ping_fork_completion(retries-1)
89
- else
90
- puts "There is an issue connecting to Learn. Please try again."
91
- File.write(file_path, 'ERROR: Error connecting to Learn')
92
- exit
93
- end
94
- end
95
- end
96
-
97
- def warn_if_necessary
98
- temp_args = nil
99
-
100
- if self.later_lesson
101
- puts 'WARNING: You are attempting to open a lesson that is beyond your current lesson.'
102
- print 'Are you sure you want to continue? [Yn]: '
103
-
104
- if ARGV.any?
105
- temp_args = ARGV
106
- ARGV.clear
107
- end
108
-
109
- warn_response = gets.chomp.downcase
110
-
111
- if !warn_response.empty? && !['yes', 'y'].include?(warn_response)
112
- exit
113
- end
114
- end
115
-
116
- if temp_args
117
- temp_args.each do |arg|
118
- ARGV << arg
119
- end
120
- end
121
- end
122
-
123
- def setup_tmp_file
124
- FileUtils.touch(file_path)
125
- File.write(file_path, '')
126
- end
127
-
128
- def cleanup_tmp_file
129
- File.write(file_path, 'Done.')
130
- end
131
18
 
132
- def set_lesson
133
- File.write(file_path, 'Getting lesson...')
134
-
135
- if !lesson && !get_next_lesson
136
- self.lesson = get_current_lesson_forked_repo
137
- self.lesson_is_lab = current_lesson.lab
138
- self.lesson_id = current_lesson.id
139
- self.later_lesson = false
140
- self.dot_learn = current_lesson.dot_learn
141
- elsif !lesson && get_next_lesson
142
- self.lesson = get_next_lesson_forked_repo
143
- self.lesson_is_lab = next_lesson.lab
144
- self.lesson_id = next_lesson.id
145
- self.later_lesson = false
146
- self.dot_learn = next_lesson.dot_learn
147
- else
148
- self.lesson = ensure_correct_lesson.clone_repo
149
- self.lesson_is_lab = correct_lesson.lab
150
- self.lesson_id = correct_lesson.lesson_id
151
- self.later_lesson = correct_lesson.later_lesson
152
- self.dot_learn = correct_lesson.dot_learn
153
- end
154
-
155
- self.repo_dir = lesson.split('/').last
156
- end
157
-
158
- def current_lesson
159
- @current_lesson ||= client.current_lesson
160
- end
161
-
162
- def next_lesson
163
- @next_lesson ||= client.next_lesson
164
- end
165
-
166
- def get_current_lesson_forked_repo(retries=3)
167
- begin
168
- Timeout::timeout(15) do
169
- current_lesson.clone_repo
170
- end
171
- rescue Timeout::Error
172
- if retries > 0
173
- puts "There was a problem getting your lesson from Learn. Retrying..."
174
- get_current_lesson_forked_repo(retries-1)
175
- else
176
- puts "There seems to be a problem connecting to Learn. Please try again."
177
- File.write(file_path, 'ERROR: Error connecting to Learn')
178
- exit
179
- end
180
- end
181
- end
182
-
183
- def get_next_lesson_forked_repo(retries=3)
184
- begin
185
- Timeout::timeout(15) do
186
- next_lesson.clone_repo
187
- end
188
- rescue Timeout::Error
189
- if retries > 0
190
- puts "There was a problem getting your next lesson from Learn. Retrying..."
191
- get_next_lesson_forked_repo(retries-1)
192
- else
193
- puts "There seems to be a problem connecting to Learn. Please try again."
194
- File.write(file_path, 'ERROR: Error connecting to Learn')
195
- exit
196
- end
197
- end
198
- end
199
-
200
- def ensure_correct_lesson
201
- correct_lesson
202
- end
203
-
204
- def correct_lesson(retries=3)
205
- @correct_lesson ||= begin
206
- Timeout::timeout(15) do
207
- client.validate_repo_slug(repo_slug: lesson)
208
- end
209
- rescue Timeout::Error
210
- if retries > 0
211
- puts "There was a problem connecting to Learn. Retrying..."
212
- correct_lesson(retries-1)
213
- else
214
- puts "Cannot connect to Learn right now. Please try again."
215
- File.write(file_path, 'ERROR: Error connecting to Learn')
216
- exit
217
- end
218
- end
219
- end
220
-
221
- def fork_repo(retries=3)
222
- if !repo_exists?
223
- File.write(file_path, 'Forking repository...')
224
- puts "Forking lesson..."
225
-
226
- if !github_disabled?
227
- begin
228
- Timeout::timeout(15) do
229
- client.fork_repo(repo_name: repo_dir)
230
- end
231
- rescue Timeout::Error
232
- if retries > 0
233
- puts "There was a problem forking this lesson. Retrying..."
234
- fork_repo(retries-1)
235
- else
236
- puts "There is an issue connecting to Learn. Please try again."
237
- File.write(file_path, 'ERROR: Error connecting to Learn')
238
- exit
239
- end
240
- end
241
- end
242
- end
243
- end
244
-
245
- def clone_repo(retries=3)
246
- if !repo_exists?
247
- File.write(file_path, 'Cloning to your machine...')
248
- puts "Cloning lesson..."
249
- begin
250
- Timeout::timeout(15) do
251
- Git.clone("git@github.com:#{lesson}.git", repo_dir, path: lessons_dir)
252
- end
253
- rescue Git::GitExecuteError
254
- if retries > 0
255
- puts "There was a problem cloning this lesson. Retrying..." if retries > 1
256
- sleep(1)
257
- clone_repo(retries-1)
258
- else
259
- puts "Cannot clone this lesson right now. Please try again."
260
- File.write(file_path, 'ERROR: Error cloning. Try again.')
261
- exit
262
- end
263
- rescue Timeout::Error
264
- if retries > 0
265
- puts "There was a problem cloning this lesson. Retrying..."
266
- clone_repo(retries-1)
267
- else
268
- puts "Cannot clone this lesson right now. Please try again."
269
- File.write(file_path, 'ERROR: Error cloning. Try again.')
270
- exit
271
- end
272
- end
273
- end
274
-
275
- if github_disabled?
276
- ping_fork_completion
277
- end
278
- end
279
-
280
- def open_with_editor
281
- if ios_lesson?
282
- open_ios_lesson
283
- elsif editor
284
- system("#{editor} .")
285
- end
286
- end
287
-
288
- def ios_lesson?
289
- begin
290
- languages = YAML.load(File.read("#{lessons_dir}/#{repo_dir}/.learn"))['languages']
291
- ios_lang = languages.any? {|l| ['objc', 'swift'].include?(l)}
292
-
293
- ios_lang || xcodeproj_file? || xcworkspace_file?
294
- rescue Psych::SyntaxError
295
- if xcodeproj_file? || xcworkspace_file?
296
- true
297
- else
298
- puts "Sorry, there seems to be a problem with this lesson. Please submit a bug report to bugs@learn.co and try again later."
299
- puts "If you'd like to work on your next lesson now, type: learn next"
300
- File.write(file_path, 'ERROR: Problem parsing lesson data. Try again.')
301
- exit
302
- end
303
- rescue NoMethodError, Errno::ENOENT => e
304
- if xcodeproj_file? || xcworkspace_file?
305
- true
306
- elsif e.message.match(/for false:FalseClass/) || e.message.match(/No such file or directory/)
307
- false
308
- else
309
- puts "Sorry, there seems to be a problem with this lesson. Please submit a bug report to bugs@learn.co and try again later."
310
- puts "If you'd like to work on your next lesson now, type: learn next"
311
- File.write(file_path, 'ERROR: Problem parsing lesson data. Try again.')
312
- exit
313
- end
314
- end
315
- end
316
-
317
- def open_ios_lesson
318
- if can_open_ios_lesson?
319
- open_xcode
320
- else
321
- puts "You need to be on a Mac to work on iOS lessons."
322
- exit
323
- end
324
- end
19
+ @io = options.fetch(:io, LearnOpen.default_io)
20
+ @logger = options.fetch(:logger, LearnOpen.logger)
325
21
 
326
- def can_open_ios_lesson?
327
- on_mac?
22
+ @options = options
328
23
  end
329
24
 
330
- def open_xcode
331
- if xcworkspace_file?
332
- system("cd #{lessons_dir}/#{repo_dir} && open *.xcworkspace")
333
- elsif xcodeproj_file?
334
- system("cd #{lessons_dir}/#{repo_dir} && open *.xcodeproj")
335
- end
336
- end
337
-
338
- def xcodeproj_file?
339
- Dir.glob("#{lessons_dir}/#{repo_dir}/*.xcodeproj").any?
340
- end
341
-
342
- def xcworkspace_file?
343
- Dir.glob("#{lessons_dir}/#{repo_dir}/*.xcworkspace").any?
344
- end
345
-
346
- def cd_to_lesson
347
- puts "Opening lesson..."
348
- Dir.chdir("#{lessons_dir}/#{repo_dir}")
349
- end
350
-
351
- def pip_install
352
- if !ios_lesson? && File.exists?("#{lessons_dir}/#{repo_dir}/requirements.txt")
353
- puts "Installing pip dependencies..."
354
- system("python -m pip install -r requirements.txt")
355
- end
356
- end
357
-
358
- def jupyter_pip_install
359
- if !ios_lesson? && File.exists?("#{lessons_dir}/#{repo_dir}/requirements.txt")
360
- puts "Installing pip dependencies..."
361
- system("/opt/conda/bin/python -m pip install -r requirements.txt")
362
- end
363
- end
364
-
365
- def bundle_install
366
- if !ios_lesson? && File.exists?("#{lessons_dir}/#{repo_dir}/Gemfile")
367
- puts "Bundling..."
368
- system("bundle install")
369
- end
370
- end
371
-
372
- def npm_install
373
- if !ios_lesson? && File.exists?("#{lessons_dir}/#{repo_dir}/package.json")
374
- puts 'Installing npm dependencies...'
375
-
376
- if ide_environment?
377
- system("yarn install --no-lockfile")
378
- else
379
- system("npm install")
380
- end
381
- end
382
- end
383
-
384
- def lesson_is_readme?
385
- !lesson_is_lab
386
- end
387
-
388
- def open_readme
389
- if ide_environment?
390
- puts "Opening readme..."
391
- File.open(".custom_commands.log", "a") do |f|
392
- f.puts %Q{{"command": "browser_open", "url": "https://learn.co/lessons/#{lesson_id}"}}
393
- end
394
- elsif can_open_readme?
395
- puts "Opening readme..."
396
- launch_browser
397
- else
398
- puts "It looks like this lesson is a Readme. Please open it in your browser."
399
- exit
400
- end
401
- end
402
-
403
- def launch_browser
404
- if chrome_installed?
405
- open_chrome
406
- else
407
- open_safari
408
- end
409
- end
410
-
411
- def chrome_installed?
412
- File.exists?('/Applications/Google Chrome.app')
413
- end
414
-
415
- def open_chrome
416
- system("open -a 'Google Chrome' https://learn.co/lessons/#{lesson_id}")
417
- end
418
-
419
- def open_safari
420
- system("open -a Safari https://learn.co/lessons/#{lesson_id}")
421
- end
422
-
423
- def can_open_readme?
424
- on_mac?
425
- end
426
-
427
- def on_mac?
428
- !!RUBY_PLATFORM.match(/darwin/)
429
- end
430
-
431
- def github_disabled?
432
- !dot_learn.nil? && dot_learn[:github] == false
433
- end
434
-
435
- def ide_environment?
436
- ENV['IDE_CONTAINER'] == "true"
437
- end
438
-
439
- def ide_git_wip_enabled?
440
- return false if github_disabled?
441
-
442
- ENV['IDE_GIT_WIP'] == "true"
443
- end
444
-
445
- def ide_version_3?
446
- ENV['IDE_VERSION'] == "3"
447
- end
448
-
449
- def jupyter_notebook_environment?
450
- ENV['JUPYTER_CONTAINER'] == "true"
451
- end
452
-
453
- def git_tasks
454
- fork_repo
455
- clone_repo
456
- end
457
-
458
- def file_tasks
459
- cd_to_lesson
460
- open_with_editor
461
- end
462
-
463
- def dependency_tasks
464
- bundle_install
465
- npm_install
466
- pip_install
467
- end
468
-
469
- def restore_files
470
- pid = Process.spawn("restore-lab", [:out, :err] => File::NULL)
471
- Process.waitpid(pid)
472
- end
473
-
474
- def watch_for_changes
475
- Process.spawn("while inotifywait -e close_write,create,moved_to -r #{lessons_dir}/#{repo_dir}; do backup-lab; done", [:out, :err] => File::NULL)
476
- end
477
-
478
- def completion_tasks
479
- cleanup_tmp_file
480
- puts "Done."
481
- exec("#{ENV['SHELL']} -l")
25
+ def run
26
+ logger.log('Getting lesson...')
27
+ io.puts "Looking for lesson..."
28
+
29
+ lesson_data = LearnOpen::Adapters::LearnWebAdapter
30
+ .new(options)
31
+ .fetch_lesson_data(
32
+ target_lesson: target_lesson,
33
+ fetch_next_lesson: get_next_lesson
34
+ )
35
+
36
+ lesson = Lessons.classify(lesson_data, options)
37
+ environment = LearnOpen::Environments.classify(options)
38
+ lesson.open(environment, editor)
482
39
  end
483
40
  end
484
41
  end