lib/gitdocs/server.rb in gitdocs-0.5.0.pre6 vs lib/gitdocs/server.rb in gitdocs-0.5.0.pre7

- old
+ new

@@ -1,5 +1,13 @@ +# -*- encoding : utf-8 -*- + +# Disable style checks that are invalid for Renee +# rubocop:disable Blocks, MultilineBlockChain +# +# TODO: extract the WebApp into its own class but until then... +# rubocop:disable LineLength, ClassLength, CyclomaticComplexity, BlockNesting + require 'thin' require 'renee' require 'coderay' require 'uri' require 'haml' @@ -10,144 +18,173 @@ class Server def initialize(manager, port = 8888, repositories) @manager = manager @port = port.to_i @repositories = repositories + @search = Gitdocs::Search.new(repositories) end + def self.start_and_wait(manager, override_port, repositories) + return false unless manager.start_web_frontend + + web_port = override_port || manager.web_frontend_port + server = Server.new(manager, web_port, repositories) + server.start + server.wait_for_start + true + end + def start repositories = @repositories manager = @manager Thin::Logging.debug = @manager.debug Thin::Server.start('127.0.0.1', @port) do - use Rack::Static, urls: ['/css', '/js', '/img', '/doc'], root: File.expand_path('../public', __FILE__) + use Rack::Static, urls: %w(/css /js /img /doc), root: File.expand_path('../public', __FILE__) use Rack::MethodOverride run Renee { if request.path_info == '/' - if manager.config.shares.size == 1 + if manager.shares.size == 1 redirect! '/0' else - render! 'home', layout: 'app', locals: { conf: manager.config, nav_state: 'home' } + render!( + 'home', + layout: 'app', + locals: { shares: manager.shares, nav_state: 'home' } + ) end else path 'settings' do - get.render! 'settings', layout: 'app', locals: { conf: manager.config, nav_state: 'settings' } + get.render!( + 'settings', + layout: 'app', + locals: { conf: manager, nav_state: 'settings' } + ) post do - shares = manager.config.shares - manager.config.global.update_attributes(request.POST['config']) - request.POST['share'].each do |idx, share| - if remote_branch = share.delete('remote_branch') - share['remote_name'], share['branch_name'] = remote_branch.split('/', 2) - end - # Update paths - if share['path'] && !share['path'].empty? - shares[Integer(idx)].update_attributes(share) - end - end - EM.add_timer(0.1) { manager.restart } + manager.update_all(request.POST) redirect! '/settings' end end path('search').get do - render! 'search', layout: 'app', locals: { conf: manager.config, results: Gitdocs::Repository.search(request.GET['q'], repositories), nav_state: nil } + render!( + 'search', + layout: 'app', + locals: { results: @search.search(request.GET['q']), nav_state: nil } + ) end path('shares') do - post do - Configuration::Share.create - redirect! '/settings' - end - var(:int) do |id| delete do - share = manager.config.shares.find { |s| s.id == id } - halt 404 if share.nil? - share.destroy - redirect! '/settings' + halt(404) unless manager.remove_by_id(id) + redirect!('/settings') end end end var :int do |idx| - repository = repositories[idx] + halt(404) unless repositories[idx] + path = Gitdocs::Repository::Path.new( + repositories[idx], URI.unescape(request.path_info) + ) - halt 404 if repository.nil? - file_path = URI.unescape(request.path_info) - expanded_path = File.expand_path(".#{file_path}", repository.root) - message_file = File.expand_path('.gitmessage~', repository.root) - halt 400 unless expanded_path[/^#{Regexp.quote(repository.root)}/] - parent = File.dirname(file_path) - parent = '' if parent == '/' - parent = nil if parent == '.' - locals = { idx: idx, parent: parent, root: repository.root, file_path: expanded_path, nav_state: nil } - mime = File.mime_type?(File.open(expanded_path)) if File.file?(expanded_path) - mode = request.params['mode'] + mode = request.params['mode'] + default_locals = { + idx: idx, + root: repositories[idx].root, + nav_state: nil + } + if mode == 'meta' # Meta - halt 200, { 'Content-Type' => 'application/json' }, [repository.file_meta(file_path).to_json] + halt 200, { 'Content-Type' => 'application/json' }, [path.meta.to_json] elsif mode == 'save' # Saving - File.open(expanded_path, 'w') { |f| f.print request.params['data'] } - File.open(message_file, 'w') { |f| f.print request.params['message'] } unless request.params['message'] == '' - redirect! '/' + idx.to_s + file_path + path.write(request.params['data'], request.params['message']) + redirect!("/#{idx}/#{path.relative_path}") elsif mode == 'upload' # Uploading - halt 404 unless file = request.params['file'] - tempfile, filename = file[:tempfile], file[:filename] - FileUtils.mv(tempfile.path, File.expand_path(filename, expanded_path)) - redirect! '/' + idx.to_s + file_path + '/' + filename - elsif !File.exist?(expanded_path) && !request.params['dir'] # edit for non-existent file - FileUtils.mkdir_p(File.dirname(expanded_path)) - FileUtils.touch(expanded_path) - redirect! '/' + idx.to_s + file_path + '?mode=edit' - elsif !File.exist?(expanded_path) && request.params['dir'] # create directory - FileUtils.mkdir_p(expanded_path) - redirect! '/' + idx.to_s + file_path - elsif File.directory?(expanded_path) # list directory - contents = Dir[File.join(expanded_path, '*')].map { |x| Docfile.new(x) } - rendered_readme = nil - if readme = Dir[File.expand_path('README.{md}', expanded_path)].first - rendered_readme = '<h3>' + File.basename(readme) + '</h3><div class="tilt">' + render(readme) + '</div>' - end - render! 'dir', layout: 'app', locals: locals.merge(contents: contents, rendered_readme: rendered_readme) + file = request.params['file'] + halt 404 unless file + tempfile = file[:tempfile] + filename = file[:filename] + FileUtils.mv(tempfile.path, path.absolute_path) + redirect!("/#{idx}/#{path.relative_path}/#{filename}") + elsif !path.exist? && !request.params['dir'] # edit for non-existent file + path.touch + redirect!("/#{idx}/#{path.relative_path}?mode=edit") + elsif !path.exist? && request.params['dir'] # create directory + path.mkdir + redirect!("/#{idx}/#{path.relative_path}") + elsif path.directory? # list directory + rendered_readme = + if path.readme_path + <<-EOS.gusb(/^\s+/, '') + <h3>#{File.basename(path.readme_path)}</h3> + <div class="tilt">#{render(path.readme_path)}</div> + EOS + else + nil + end + render!( + 'dir', + layout: 'app', + locals: default_locals.merge( + contents: path.file_listing, + rendered_readme: rendered_readme + ) + ) elsif mode == 'revisions' # list revisions - revisions = repository.file_revisions(file_path) - render! 'revisions', layout: 'app', locals: locals.merge(revisions: revisions) + render!( + 'revisions', + layout: 'app', + locals: default_locals.merge(revisions: path.revisions) + ) elsif mode == 'revert' # revert file - if revision = request.params['revision'] - File.open(message_file, 'w') { |f| f.print "Reverting '#{file_path}' to #{revision}" } - repository.file_revert(file_path, revision) - end - redirect! '/' + idx.to_s + file_path + path.revert(request.params['revision']) + redirect!("/#{idx}/#{path.relative_path}") elsif mode == 'delete' # delete file - FileUtils.rm(expanded_path) - redirect! '/' + idx.to_s + parent - elsif mode == 'edit' && (mime.match(%r{text/}) || mime.match(%r{x-empty})) # edit file - contents = File.read(expanded_path) - render! 'edit', layout: 'app', locals: locals.merge(contents: contents) + path.remove + parent = File.dirname(path.relative_path) + parent = '' if parent == '/' + parent = nil if parent == '.' + redirect!("/#{idx}#{parent}") + elsif mode == 'edit' && path.text? # edit file + render!( + 'edit', + layout: 'app', + locals: default_locals.merge(contents: path.content) + ) elsif mode != 'raw' # render file - revision = request.params['revision'] - expanded_path = repository.file_revision_at(file_path, revision) if revision - begin # attempting to render file - contents = '<div class="tilt">' + render(expanded_path) + '</div>' - rescue RuntimeError # not tilt supported - contents = if mime.match(%r{text/}) - '<pre class="CodeRay">' + CodeRay.scan_file(expanded_path).encode(:html) + '</pre>' - else - %|<embed class="inline-file" src="/#{idx}#{request.path_info}?mode=raw"></embed>| + revision_path = path.absolute_path(request.params['revision']) + contents = + begin # attempting to render file + %(<div class="tilt">#{render(revision_path)}</div>) + rescue RuntimeError # not tilt supported + if path.text? + <<-EOS.gsub(/^\s+/, '') + <pre class="CodeRay"> + #{CodeRay.scan_file(revision_path).encode(:html)} + </pre> + EOS + else + %(<embed class="inline-file" src="/#{idx}#{request.path_info}?mode=raw"></embed>) + end end - end - render! 'file', layout: 'app', locals: locals.merge(contents: contents) + render!( + 'file', + layout: 'app', + locals: default_locals.merge(contents: contents) + ) else # other file - run! Rack::File.new(repository.root) + run! Rack::File.new(repositories[idx].root) end end end }.setup { - views_path File.expand_path('../views', __FILE__) + views_path(File.expand_path('../views', __FILE__)) } end end - def wait_for_start_and_open(restarting) + def wait_for_start wait_for_web_server = proc do i = 0 begin TCPSocket.open('127.0.0.1', @port).close @manager.log('Web server running!')