gitdocs 0.4.15 → 0.5.0.pre1

Sign up to get free protection for your applications and to get access to all the features.
@@ -2,12 +2,12 @@ class CreateShares < ActiveRecord::Migration
2
2
  def self.up
3
3
  create_table :shares do |t|
4
4
  t.column :path, :string
5
- t.column :polling_interval, :double, :default => 15
6
- t.column :notification, :boolean, :default => true
5
+ t.column :polling_interval, :double, default: 15
6
+ t.column :notification, :boolean, default: true
7
7
  end
8
8
  end
9
9
 
10
10
  def self.down
11
- raise
11
+ fail
12
12
  end
13
13
  end
@@ -1,10 +1,10 @@
1
1
  class AddRemoteBranch < ActiveRecord::Migration
2
2
  def self.up
3
- add_column :shares, :remote_name, :string, :default => 'origin'
4
- add_column :shares, :branch_name, :string, :default => 'master'
3
+ add_column :shares, :remote_name, :string, default: 'origin'
4
+ add_column :shares, :branch_name, :string, default: 'master'
5
5
  end
6
6
 
7
7
  def self.down
8
- raise
8
+ fail
9
9
  end
10
10
  end
@@ -1,11 +1,11 @@
1
1
  class CreateConfigs < ActiveRecord::Migration
2
2
  def self.up
3
3
  create_table :configs do |t|
4
- t.column :load_browser_on_startup, :boolean, :default => true
4
+ t.column :load_browser_on_startup, :boolean, default: true
5
5
  end
6
6
  end
7
7
 
8
8
  def self.down
9
- raise
9
+ fail
10
10
  end
11
- end
11
+ end
@@ -1,10 +1,10 @@
1
1
  class AddIndexForPath < ActiveRecord::Migration
2
2
  def self.up
3
- shares = Gitdocs::Configuration::Share.all.inject(Hash.new{|h,k| h[k] = []}) {|h, s| h[s.path] << s; h}
3
+ shares = Gitdocs::Configuration::Share.all.reduce(Hash.new { |h, k| h[k] = [] }) { |h, s| h[s.path] << s; h }
4
4
  shares.each do |path, shares|
5
5
  shares.shift
6
6
  shares.each(&:destroy) unless shares.empty?
7
7
  end
8
- add_index :shares, :path, :unique => true
8
+ add_index :shares, :path, unique: true
9
9
  end
10
- end
10
+ end
@@ -1,9 +1,9 @@
1
1
  class AddStartWebFrontend < ActiveRecord::Migration
2
2
  def self.up
3
- add_column :configs, :start_web_frontend, :boolean, :default => true
3
+ add_column :configs, :start_web_frontend, :boolean, default: true
4
4
  end
5
5
 
6
6
  def self.down
7
- raise
7
+ fail
8
8
  end
9
9
  end
@@ -1,9 +1,9 @@
1
1
  class AddWebPortToConfig < ActiveRecord::Migration
2
2
  def self.up
3
- add_column :configs, :web_frontend_port, :integer, :default => 8888
3
+ add_column :configs, :web_frontend_port, :integer, default: 8888
4
4
  end
5
5
 
6
6
  def self.down
7
- raise
7
+ fail
8
8
  end
9
9
  end
@@ -20,4 +20,4 @@ class RedcarpetCompat
20
20
  @text = @text.force_encoding('utf-8') if @text.respond_to?(:force_encoding)
21
21
  @markdown.render(@text)
22
22
  end
23
- end
23
+ end
@@ -4,11 +4,17 @@ module Gitdocs
4
4
 
5
5
  attr_reader :root, :listener
6
6
 
7
+ def self.start_all(shares)
8
+ runners = shares.map { |share| Runner.new(share) }
9
+ runners.each(&:run)
10
+ runners
11
+ end
12
+
7
13
  def initialize(share)
8
14
  @share = share
9
- @root = share.path.sub(%r{/+$},'') if share.path
15
+ @root = share.path.sub(%r{/+$}, '') if share.path
10
16
  @polling_interval = share.polling_interval
11
- @icon = File.expand_path("../../img/icon.png", __FILE__)
17
+ @icon = File.expand_path('../../img/icon.png', __FILE__)
12
18
  end
13
19
 
14
20
  SearchResult = Struct.new(:file, :context)
@@ -17,7 +23,7 @@ module Gitdocs
17
23
 
18
24
  results = []
19
25
  if result_test = sh_string("git grep -i #{ShellTools.escape(term)}")
20
- result_test.scan(/(.*?):([^\n]*)/) do |(file, context)|
26
+ result_test.scan(/(.*?):([^\n]*)/) do |(file, context)|
21
27
  if result = results.find { |s| s.file == file }
22
28
  result.context += ' ... ' + context
23
29
  else
@@ -34,41 +40,41 @@ module Gitdocs
34
40
  @show_notifications = @share.notification
35
41
  @current_remote = @share.remote_name
36
42
  @current_branch = @share.branch_name
37
- @current_revision = sh_string("git rev-parse HEAD")
43
+ @current_revision = sh_string('git rev-parse HEAD')
38
44
  Guard::Notifier.turn_on if @show_notifications
39
45
 
40
46
  mutex = Mutex.new
41
47
 
42
- info("Running gitdocs!", "Running gitdocs in `#{@root}'")
48
+ info('Running gitdocs!', "Running gitdocs in `#{@root}'")
43
49
 
44
50
  # Pull changes from remote repository
45
51
  syncer = proc do
46
52
  EM.defer(proc do
47
53
  mutex.synchronize { sync_changes }
48
54
  end, proc do
49
- EM.add_timer(@polling_interval) {
55
+ EM.add_timer(@polling_interval) do
50
56
  syncer.call
51
- }
57
+ end
52
58
  end)
53
59
  end
54
60
  syncer.call
55
61
  # Listen for changes in local repository
56
62
 
57
- EM.defer(proc{
58
- listener = Guard::Listener.select_and_init(@root, :watch_all_modifications => true)
59
- listener.on_change { |directories|
63
+ EM.defer(proc do
64
+ listener = Guard::Listener.select_and_init(@root, watch_all_modifications: true)
65
+ listener.on_change do |directories|
60
66
  directories.uniq!
61
- directories.delete_if {|d| d =~ /\/\.git/}
67
+ directories.delete_if { |d| d =~ /\/\.git/ }
62
68
  unless directories.empty?
63
69
  EM.next_tick do
64
- EM.defer(proc {
70
+ EM.defer(proc do
65
71
  mutex.synchronize { push_changes }
66
- }, proc {} )
72
+ end, proc {})
67
73
  end
68
74
  end
69
- }
75
+ end
70
76
  listener.start
71
- }, proc{EM.stop_reactor})
77
+ end, proc { EM.stop_reactor })
72
78
  end
73
79
 
74
80
  def clear_state
@@ -80,36 +86,36 @@ module Gitdocs
80
86
  if status.success?
81
87
  changes = get_latest_changes
82
88
  unless changes.empty?
83
- author_list = changes.inject(Hash.new{|h, k| h[k] = 0}) {|h, c| h[c['author']] += 1; h}.to_a.sort{|a,b| b[1] <=> a[1]}.map{|(name, count)| "* #{name} (#{count} change#{count == 1 ? '' : 's'})"}.join("\n")
89
+ author_list = changes.reduce(Hash.new { |h, k| h[k] = 0 }) { |h, c| h[c['author']] += 1; h }.to_a.sort { |a, b| b[1] <=> a[1] }.map { |(name, count)| "* #{name} (#{count} change#{count == 1 ? '' : 's'})" }.join("\n")
84
90
  info("Updated with #{changes.size} change#{changes.size == 1 ? '' : 's'}", "In `#{@root}':\n#{author_list}")
85
91
  end
86
92
  push_changes
87
93
  elsif out[/CONFLICT/]
88
- conflicted_files = sh("git ls-files -u --full-name -z").split("\0").
89
- inject(Hash.new{|h, k| h[k] = []}) {|h, line|
94
+ conflicted_files = sh('git ls-files -u --full-name -z').split("\0")
95
+ .reduce(Hash.new { |h, k| h[k] = [] }) do|h, line|
90
96
  parts = line.split(/\t/)
91
97
  h[parts.last] << parts.first.split(/ /)
92
98
  h
93
- }
94
- warn("There were some conflicts", "#{conflicted_files.keys.map{|f| "* #{f}"}.join("\n")}")
99
+ end
100
+ warn('There were some conflicts', "#{conflicted_files.keys.map { |f| "* #{f}" }.join("\n")}")
95
101
  conflicted_files.each do |conflict, ids|
96
102
  conflict_start, conflict_end = conflict.scan(/(.*?)(|\.[^\.]+)$/).first
97
103
  ids.each do |(mode, sha, id)|
98
- author = " original" if id == "1"
104
+ author = ' original' if id == '1'
99
105
  system("cd #{@root} && git show :#{id}:#{conflict} > '#{conflict_start} (#{sha[0..6]}#{author})#{conflict_end}'")
100
106
  end
101
- system("cd #{@root} && git rm #{conflict}") or raise
107
+ system("cd #{@root} && git rm #{conflict}") || fail
102
108
  end
103
109
  push_changes
104
- elsif sh_string("git remote").nil? # no remote to pull from
110
+ elsif sh_string('git remote').nil? # no remote to pull from
105
111
  # Do nothing, no remote repo yet
106
112
  else
107
- error("There was a problem synchronizing this gitdoc", "A problem occurred in #{@root}:\n#{out}")
113
+ error('There was a problem synchronizing this gitdoc', "A problem occurred in #{@root}:\n#{out}")
108
114
  end
109
115
  end
110
116
 
111
117
  def push_changes
112
- message_file = File.expand_path(".gitmessage~", @root)
118
+ message_file = File.expand_path('.gitmessage~', @root)
113
119
  if File.exist? message_file
114
120
  message = File.read message_file
115
121
  File.delete message_file
@@ -118,7 +124,7 @@ module Gitdocs
118
124
  end
119
125
  sh 'find . -type d -regex ``./[^.].*'' -empty -exec touch \'{}/.gitignore\' \;'
120
126
  sh 'git add .'
121
- sh "git commit -a -m #{ShellTools.escape(message)}" unless sh("git status -s").strip.empty?
127
+ sh "git commit -a -m #{ShellTools.escape(message)}" unless sh('git status -s').strip.empty?
122
128
  if @current_revision.nil? || sh('git status')[/branch is ahead/]
123
129
  out, code = sh_with_code("git push #{@current_remote} #{@current_branch}")
124
130
  if code.success?
@@ -127,12 +133,19 @@ module Gitdocs
127
133
  elsif @current_revision.nil?
128
134
  # ignorable
129
135
  elsif out[/\[rejected\]/]
130
- warn("There was a conflict in #{@root}, retrying", "")
136
+ warn("There was a conflict in #{@root}, retrying", '')
131
137
  else
132
138
  error("BAD Could not push changes in #{@root}", out)
133
- exit
139
+ # TODO: need to add a status on shares so that the push problem can be
140
+ # displayed.
134
141
  end
135
142
  end
143
+ rescue
144
+ # Rescue any standard exceptions which come from the push related
145
+ # commands. This will prevent problems on a single share from killing
146
+ # the entire daemon.
147
+ error("Unexpected error pushing changes in #{@root}")
148
+ # TODO: get logging and/or put the error message into a status field in the database
136
149
  end
137
150
 
138
151
  def get_latest_changes
@@ -145,7 +158,7 @@ module Gitdocs
145
158
  Yajl::Parser.new.parse(out) do |obj|
146
159
  lines << obj
147
160
  end
148
- @current_revision = sh("git rev-parse HEAD").strip
161
+ @current_revision = sh('git rev-parse HEAD').strip
149
162
  lines
150
163
  end
151
164
  else
@@ -157,30 +170,28 @@ module Gitdocs
157
170
  # Returns the list of files in a given directory
158
171
  # dir_files("some/dir") => [<Docfile>, <Docfile>]
159
172
  def dir_files(dir_path)
160
- Dir[File.join(dir_path, "*")].to_a.map { |path| Docfile.new(path) }
173
+ Dir[File.join(dir_path, '*')].to_a.map { |path| Docfile.new(path) }
161
174
  end
162
175
 
163
176
  # Returns file meta data based on relative file path
164
177
  # file_meta("path/to/file")
165
178
  # => { :author => "Nick", :size => 1000, :modified => ... }
166
179
  def file_meta(file)
167
- result = {}
168
180
  file = file.gsub(%r{^/}, '')
169
181
  full_path = File.expand_path(file, @root)
170
182
  log_result = sh_string("git log --format='%aN|%ai' -n1 #{ShellTools.escape(file)}")
171
- result = {} unless File.exist?(full_path) && log_result
172
- author, modified = log_result.split("|")
183
+ author, modified = log_result.split('|')
173
184
  modified = Time.parse(modified.sub(' ', 'T')).utc.iso8601
174
185
  size = if File.directory?(full_path)
175
- Dir[File.join(full_path, '**', '*')].inject(0) do |size, file|
176
- File.symlink?(file) ? size : size += File.size(file)
177
- end
178
- else
179
- File.symlink?(full_path) ? 0 : File.size(full_path)
180
- end
186
+ Dir[File.join(full_path, '**', '*')].reduce(0) do |size, file|
187
+ File.symlink?(file) ? size : size += File.size(file)
188
+ end
189
+ else
190
+ File.symlink?(full_path) ? 0 : File.size(full_path)
191
+ end
181
192
  size = -1 if size == 0 # A value of 0 breaks the table sort for some reason
182
- result = { :author => author, :size => size, :modified => modified }
183
- result
193
+
194
+ { author: author, size: size, modified: modified }
184
195
  end
185
196
 
186
197
  # Returns the revisions available for a particular file
@@ -189,9 +200,9 @@ module Gitdocs
189
200
  file = file.gsub(%r{^/}, '')
190
201
  output = sh_string("git log --format='%h|%s|%aN|%ai' -n100 #{ShellTools.escape(file)}")
191
202
  output.to_s.split("\n").map do |log_result|
192
- commit, subject, author, date = log_result.split("|")
203
+ commit, subject, author, date = log_result.split('|')
193
204
  date = Time.parse(date.sub(' ', 'T')).utc.iso8601
194
- { :commit => commit, :subject => subject, :author => author, :date => date }
205
+ { commit: commit, subject: subject, author: author, date: date }
195
206
  end
196
207
  end
197
208
 
@@ -207,7 +218,7 @@ module Gitdocs
207
218
 
208
219
  # Revert a file to a particular revision
209
220
  def file_revert(file, ref)
210
- if file_revisions(file).map {|r| r[:commit]}.include? ref
221
+ if file_revisions(file).map { |r| r[:commit] }.include? ref
211
222
  file = file.gsub(%r{^/}, '')
212
223
  full_path = File.expand_path(file, @root)
213
224
  content = File.read(file_revision_at(file, ref))
@@ -216,38 +227,41 @@ module Gitdocs
216
227
  end
217
228
 
218
229
  def valid?
219
- out, status = sh_with_code "git status"
230
+ out, status = sh_with_code 'git status'
220
231
  @root.present? && status.success?
221
232
  end
222
233
 
223
234
  def warn(title, msg)
224
235
  if @show_notifications
225
- Guard::Notifier.notify(msg, :title => title)
236
+ Guard::Notifier.notify(msg, title: title)
226
237
  else
227
238
  Kernel.warn("#{title}: #{msg}")
228
239
  end
240
+ rescue # Prevent StandardErrors from stopping the daemon.
229
241
  end
230
242
 
231
243
  def info(title, msg)
232
244
  if @show_notifications
233
- Guard::Notifier.notify(msg, :title => title, :image => @icon)
245
+ Guard::Notifier.notify(msg, title: title, image: @icon)
234
246
  else
235
247
  puts("#{title}: #{msg}")
236
248
  end
249
+ rescue # Prevent StandardErrors from stopping the daemon.
237
250
  end
238
251
 
239
252
  def error(title, msg)
240
253
  if @show_notifications
241
- Guard::Notifier.notify(msg, :title => title, :image => :failure)
254
+ Guard::Notifier.notify(msg, title: title, image: :failure)
242
255
  else
243
256
  Kernel.warn("#{title}: #{msg}")
244
257
  end
258
+ rescue # Prevent StandardErrors from stopping the daemon.
245
259
  end
246
260
 
247
261
  # sh_string("git config branch.`git branch | grep '^\*' | sed -e 's/\* //'`.remote", "origin")
248
- def sh_string(cmd, default=nil)
262
+ def sh_string(cmd, default = nil)
249
263
  val = sh(cmd).strip rescue nil
250
- (val.nil? || val.empty?) ? default : val
264
+ val.nil? || val.empty? ? default : val
251
265
  end
252
266
 
253
267
  # Run in shell, return both status and output
@@ -4,31 +4,33 @@ require 'coderay'
4
4
  require 'uri'
5
5
  require 'haml'
6
6
  require 'mimetype_fu'
7
+ require 'launchy'
7
8
 
8
9
  module Gitdocs
9
10
  class Server
10
- def initialize(manager, *gitdocs)
11
+ def initialize(manager, port = 8888, *gitdocs)
11
12
  @manager = manager
13
+ @port = port.to_i
12
14
  @gitdocs = gitdocs
13
15
  end
14
16
 
15
- def start(port = 8888)
16
- gds = @gitdocs
17
+ def start
18
+ gds = @gitdocs
17
19
  manager = @manager
18
20
  Thin::Logging.debug = @manager.debug
19
- Thin::Server.start('127.0.0.1', port) do
20
- use Rack::Static, :urls => ['/css', '/js', '/img', '/doc'], :root => File.expand_path("../public", __FILE__)
21
+ Thin::Server.start('127.0.0.1', @port) do
22
+ use Rack::Static, urls: ['/css', '/js', '/img', '/doc'], root: File.expand_path('../public', __FILE__)
21
23
  use Rack::MethodOverride
22
24
  run Renee {
23
25
  if request.path_info == '/'
24
26
  if manager.config.shares.size == 1
25
- redirect! "/0"
27
+ redirect! '/0'
26
28
  else
27
- render! "home", :layout => 'app', :locals => {:conf => manager.config, :nav_state => "home" }
29
+ render! 'home', layout: 'app', locals: { conf: manager.config, nav_state: 'home' }
28
30
  end
29
31
  else
30
32
  path 'settings' do
31
- get.render! 'settings', :layout => 'app', :locals => {:conf => manager.config, :nav_state => "settings" }
33
+ get.render! 'settings', layout: 'app', locals: { conf: manager.config, nav_state: 'settings' }
32
34
  post do
33
35
  shares = manager.config.shares
34
36
  manager.config.global.update_attributes(request.POST['config'])
@@ -47,7 +49,7 @@ module Gitdocs
47
49
  end
48
50
 
49
51
  path('search').get do
50
- render! "search", :layout => 'app', :locals => {:conf => manager.config, :results => manager.search(request.GET['q']), :nav_state => nil}
52
+ render! 'search', layout: 'app', locals: { conf: manager.config, results: manager.search(request.GET['q']), nav_state: nil }
51
53
  end
52
54
 
53
55
  path('shares') do
@@ -70,14 +72,13 @@ module Gitdocs
70
72
  gd = gds[idx]
71
73
  halt 404 if gd.nil?
72
74
  file_path = URI.unescape(request.path_info)
73
- file_ext = File.extname(file_path)
74
75
  expanded_path = File.expand_path(".#{file_path}", gd.root)
75
- message_file = File.expand_path(".gitmessage~", gd.root)
76
+ message_file = File.expand_path('.gitmessage~', gd.root)
76
77
  halt 400 unless expanded_path[/^#{Regexp.quote(gd.root)}/]
77
78
  parent = File.dirname(file_path)
78
79
  parent = '' if parent == '/'
79
80
  parent = nil if parent == '.'
80
- locals = {:idx => idx, :parent => parent, :root => gd.root, :file_path => expanded_path, :nav_state => nil }
81
+ locals = { idx: idx, parent: parent, root: gd.root, file_path: expanded_path, nav_state: nil }
81
82
  mime = File.mime_type?(File.open(expanded_path)) if File.file?(expanded_path)
82
83
  mode = request.params['mode']
83
84
  if mode == 'meta' # Meta
@@ -85,63 +86,86 @@ module Gitdocs
85
86
  elsif mode == 'save' # Saving
86
87
  File.open(expanded_path, 'w') { |f| f.print request.params['data'] }
87
88
  File.open(message_file, 'w') { |f| f.print request.params['message'] } unless request.params['message'] == ''
88
- redirect! "/" + idx.to_s + file_path
89
+ redirect! '/' + idx.to_s + file_path
89
90
  elsif mode == 'upload' # Uploading
90
91
  halt 404 unless file = request.params['file']
91
92
  tempfile, filename = file[:tempfile], file[:filename]
92
93
  FileUtils.mv(tempfile.path, File.expand_path(filename, expanded_path))
93
- redirect! "/" + idx.to_s + file_path + "/" + filename
94
+ redirect! '/' + idx.to_s + file_path + '/' + filename
94
95
  elsif !File.exist?(expanded_path) && !request.params['dir'] # edit for non-existent file
95
96
  FileUtils.mkdir_p(File.dirname(expanded_path))
96
97
  FileUtils.touch(expanded_path)
97
- redirect! "/" + idx.to_s + file_path + "?mode=edit"
98
+ redirect! '/' + idx.to_s + file_path + '?mode=edit'
98
99
  elsif !File.exist?(expanded_path) && request.params['dir'] # create directory
99
100
  FileUtils.mkdir_p(expanded_path)
100
- redirect! "/" + idx.to_s + file_path
101
+ redirect! '/' + idx.to_s + file_path
101
102
  elsif File.directory?(expanded_path) # list directory
102
103
  contents = gd.dir_files(expanded_path)
103
104
  rendered_readme = nil
104
- if readme = Dir[File.expand_path("README.{md,txt}", expanded_path)].first
105
+ if readme = Dir[File.expand_path('README.{md}', expanded_path)].first
105
106
  rendered_readme = '<h3>' + File.basename(readme) + '</h3><div class="tilt">' + render(readme) + '</div>'
106
107
  end
107
- render! "dir", :layout => 'app', :locals => locals.merge(:contents => contents, :rendered_readme => rendered_readme)
108
- elsif mode == "revisions" # list revisions
108
+ render! 'dir', layout: 'app', locals: locals.merge(contents: contents, rendered_readme: rendered_readme)
109
+ elsif mode == 'revisions' # list revisions
109
110
  revisions = gd.file_revisions(file_path)
110
- render! "revisions", :layout => 'app', :locals => locals.merge(:revisions => revisions)
111
- elsif mode == "revert" # revert file
111
+ render! 'revisions', layout: 'app', locals: locals.merge(revisions: revisions)
112
+ elsif mode == 'revert' # revert file
112
113
  if revision = request.params['revision']
113
114
  File.open(message_file, 'w') { |f| f.print "Reverting '#{file_path}' to #{revision}" }
114
115
  gd.file_revert(file_path, revision)
115
116
  end
116
- redirect! "/" + idx.to_s + file_path
117
+ redirect! '/' + idx.to_s + file_path
117
118
  elsif mode == 'delete' # delete file
118
119
  FileUtils.rm(expanded_path)
119
- redirect! "/" + idx.to_s + parent
120
+ redirect! '/' + idx.to_s + parent
120
121
  elsif mode == 'edit' && (mime.match(%r{text/}) || mime.match(%r{x-empty})) # edit file
121
122
  contents = File.read(expanded_path)
122
- render! "edit", :layout => 'app', :locals => locals.merge(:contents => contents)
123
+ render! 'edit', layout: 'app', locals: locals.merge(contents: contents)
123
124
  elsif mode != 'raw' # render file
124
125
  revision = request.params['revision']
125
126
  expanded_path = gd.file_revision_at(file_path, revision) if revision
126
127
  begin # attempting to render file
127
128
  contents = '<div class="tilt">' + render(expanded_path) + '</div>'
128
- rescue RuntimeError => e # not tilt supported
129
+ rescue RuntimeError # not tilt supported
129
130
  contents = if mime.match(%r{text/})
130
131
  '<pre class="CodeRay">' + CodeRay.scan_file(expanded_path).encode(:html) + '</pre>'
131
132
  else
132
133
  %|<embed class="inline-file" src="/#{idx}#{request.path_info}?mode=raw"></embed>|
133
134
  end
134
135
  end
135
- render! "file", :layout => 'app', :locals => locals.merge(:contents => contents)
136
+ render! 'file', layout: 'app', locals: locals.merge(contents: contents)
136
137
  else # other file
137
138
  run! Rack::File.new(gd.root)
138
139
  end
139
140
  end
140
141
  end
141
142
  }.setup {
142
- views_path File.expand_path("../views", __FILE__)
143
+ views_path File.expand_path('../views', __FILE__)
143
144
  }
144
145
  end
145
146
  end
147
+
148
+ def wait_for_start_and_open(restarting)
149
+ wait_for_web_server = proc do
150
+ i = 0
151
+ begin
152
+ TCPSocket.open('127.0.0.1', @port).close
153
+ @manager.log('Web server running!')
154
+ if !restarting && @manager.config.global.load_browser_on_startup
155
+ Launchy.open("http://localhost:#{@port}/")
156
+ end
157
+ rescue Errno::ECONNREFUSED
158
+ sleep 0.2
159
+ i += 1
160
+ if i <= 20
161
+ @manager.log('Retrying web server loop...')
162
+ retry
163
+ else
164
+ @manager.log('Web server failed to start')
165
+ end
166
+ end
167
+ end
168
+ EM.defer(wait_for_web_server)
169
+ end
146
170
  end
147
171
  end