[issue #590] Log returns through Rails with `tail -n`
This commit is contained in:
parent
99ce249fe6
commit
84328742e4
|
@ -1434,6 +1434,37 @@ div.log-wrapper {
|
||||||
padding: 5px 10px;
|
padding: 5px 10px;
|
||||||
border-bottom: none;
|
border-bottom: none;
|
||||||
border-radius: 5px 5px 0 0;
|
border-radius: 5px 5px 0 0;
|
||||||
|
|
||||||
|
table.options {
|
||||||
|
border-spacing: 5px 0;
|
||||||
|
|
||||||
|
tr {
|
||||||
|
|
||||||
|
td a {
|
||||||
|
display: inline-block;
|
||||||
|
height: 13px;
|
||||||
|
padding-left: 16px;
|
||||||
|
background: image-url('code.png') no-repeat;
|
||||||
|
padding-bottom: 2px;
|
||||||
|
margin: 2px 0 0 1px;
|
||||||
|
}
|
||||||
|
td.first {
|
||||||
|
padding-right: 5px;
|
||||||
|
}
|
||||||
|
td.last {
|
||||||
|
border-left: 1px solid #ccc;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tr.bottom {
|
||||||
|
td {
|
||||||
|
padding-left: 5px;
|
||||||
|
}
|
||||||
|
td.first {
|
||||||
|
border-top: 1px solid #ccc;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.log {
|
.log {
|
||||||
|
|
|
@ -5,9 +5,9 @@ class Projects::BuildListsController < Projects::BaseController
|
||||||
|
|
||||||
before_filter :authenticate_user!, :except => CALLBACK_ACTIONS
|
before_filter :authenticate_user!, :except => CALLBACK_ACTIONS
|
||||||
before_filter :authenticate_build_service!, :only => CALLBACK_ACTIONS
|
before_filter :authenticate_build_service!, :only => CALLBACK_ACTIONS
|
||||||
skip_before_filter :authenticate_user!, :only => [:show, :index, :search] if APP_CONFIG['anonymous_access']
|
skip_before_filter :authenticate_user!, :only => [:show, :index, :search, :log] if APP_CONFIG['anonymous_access']
|
||||||
|
|
||||||
before_filter :find_build_list, :only => [:show, :publish, :cancel, :update]
|
before_filter :find_build_list, :only => [:show, :publish, :cancel, :update, :log]
|
||||||
before_filter :find_build_list_by_bs, :only => [:publish_build, :status_build, :pre_build, :post_build, :circle_build]
|
before_filter :find_build_list_by_bs, :only => [:publish_build, :status_build, :pre_build, :post_build, :circle_build]
|
||||||
|
|
||||||
load_and_authorize_resource :project, :only => NESTED_ACTIONS
|
load_and_authorize_resource :project, :only => NESTED_ACTIONS
|
||||||
|
@ -101,6 +101,15 @@ class Projects::BuildListsController < Projects::BaseController
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def log
|
||||||
|
@log = `tail -n #{params[:load_lines].to_i} #{Rails.root + 'public' + @build_list.fs_log_path}`
|
||||||
|
@log = t("layout.build_lists.log.not_available") unless $?.success?
|
||||||
|
|
||||||
|
respond_to do |format|
|
||||||
|
format.json { render :json => { :log => @log, :building => @build_list.build_started? } }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def publish_build
|
def publish_build
|
||||||
if params[:status].to_i == 0 # ok
|
if params[:status].to_i == 0 # ok
|
||||||
@build_list.published
|
@build_list.published
|
||||||
|
|
|
@ -49,7 +49,7 @@ module BuildListsHelper
|
||||||
end
|
end
|
||||||
|
|
||||||
def build_list_log_url(log_type)
|
def build_list_log_url(log_type)
|
||||||
"#{container_url}/log/#{@build_list.project.name}/#{log_type.to_s}.log".html_safe
|
"http://#{request.host_with_port}/#{@build_list.fs_log_path(log_type)}".html_safe
|
||||||
end
|
end
|
||||||
|
|
||||||
def log_reload_time_options
|
def log_reload_time_options
|
||||||
|
@ -57,4 +57,8 @@ module BuildListsHelper
|
||||||
|
|
||||||
options_for_select(t, t.first).html_safe
|
options_for_select(t, t.first).html_safe
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def log_reload_lines_options
|
||||||
|
options_for_select([100, 200, 500, 1000, 1500, 2000], 1000).html_safe
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -17,7 +17,7 @@ class Ability
|
||||||
can :archive, Project, :visibility => 'open'
|
can :archive, Project, :visibility => 'open'
|
||||||
can :read, Issue, :project => {:visibility => 'open'}
|
can :read, Issue, :project => {:visibility => 'open'}
|
||||||
can :search, BuildList
|
can :search, BuildList
|
||||||
can [:read, :everything], BuildList, :project => {:visibility => 'open'}
|
can [:read, :log, :everything], BuildList, :project => {:visibility => 'open'}
|
||||||
can :read, ProductBuildList#, :product => {:platform => {:visibility => 'open'}} # double nested hash don't work
|
can :read, ProductBuildList#, :product => {:platform => {:visibility => 'open'}} # double nested hash don't work
|
||||||
can :read, Advisory
|
can :read, Advisory
|
||||||
can(:advisories, Platform) {APP_CONFIG['anonymous_access']}
|
can(:advisories, Platform) {APP_CONFIG['anonymous_access']}
|
||||||
|
@ -62,10 +62,10 @@ class Ability
|
||||||
can(:destroy, Project) {|project| project.owner_type == 'Group' and project.owner.actors.exists?(:actor_type => 'User', :actor_id => user.id, :role => 'admin')}
|
can(:destroy, Project) {|project| project.owner_type == 'Group' and project.owner.actors.exists?(:actor_type => 'User', :actor_id => user.id, :role => 'admin')}
|
||||||
can :remove_user, Project
|
can :remove_user, Project
|
||||||
|
|
||||||
can [:read, :owned, :everything], BuildList, :user_id => user.id
|
can [:read, :log, :owned, :everything], BuildList, :user_id => user.id
|
||||||
can [:read, :related, :everything], BuildList, :project => {:owner_type => 'User', :owner_id => user.id}
|
can [:read, :log, :related, :everything], BuildList, :project => {:owner_type => 'User', :owner_id => user.id}
|
||||||
can [:read, :related, :everything], BuildList, :project => {:owner_type => 'Group', :owner_id => user.group_ids}
|
can [:read, :log, :related, :everything], BuildList, :project => {:owner_type => 'Group', :owner_id => user.group_ids}
|
||||||
can([:read, :everything], BuildList, read_relations_for('build_lists', 'projects')) {|build_list| can? :read, build_list.project}
|
can([:read, :log, :everything], BuildList, read_relations_for('build_lists', 'projects')) {|build_list| can? :read, build_list.project}
|
||||||
can([:create, :update], BuildList) {|build_list| build_list.project.is_package && can?(:write, build_list.project)}
|
can([:create, :update], BuildList) {|build_list| build_list.project.is_package && can?(:write, build_list.project)}
|
||||||
|
|
||||||
can(:publish, BuildList) do |build_list|
|
can(:publish, BuildList) do |build_list|
|
||||||
|
|
|
@ -266,6 +266,10 @@ class BuildList < ActiveRecord::Base
|
||||||
I18n.t("layout.build_lists.human_duration", {:hours => (duration/3600).to_i, :minutes => (duration%3600/60).to_i})
|
I18n.t("layout.build_lists.human_duration", {:hours => (duration/3600).to_i, :minutes => (duration%3600/60).to_i})
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def fs_log_path(log_type = :build)
|
||||||
|
container_path? ? "downloads/#{container_path}/log/#{project.name}/#{log_type.to_s}.log" : nil
|
||||||
|
end
|
||||||
|
|
||||||
def in_work?
|
def in_work?
|
||||||
status == BuildServer::BUILD_STARTED
|
status == BuildServer::BUILD_STARTED
|
||||||
#[WAITING_FOR_RESPONSE, BuildServer::BUILD_PENDING, BuildServer::BUILD_STARTED].include?(status)
|
#[WAITING_FOR_RESPONSE, BuildServer::BUILD_PENDING, BuildServer::BUILD_STARTED].include?(status)
|
||||||
|
|
|
@ -9,19 +9,26 @@
|
||||||
.both
|
.both
|
||||||
.log-body.hidden
|
.log-body.hidden
|
||||||
.reloader
|
.reloader
|
||||||
= label_tag :word_wrap do
|
%table.options
|
||||||
= check_box_tag :word_wrap
|
%tr.top
|
||||||
= t("layout.word_wrap")
|
%td.first
|
||||||
|
= label_tag :word_wrap do
|
||||||
%span{ :class => @build_list.build_started? ? nil : :hidden }
|
= check_box_tag :word_wrap
|
||||||
= label_tag :autoreload do
|
= t("layout.word_wrap")
|
||||||
= check_box_tag :autoreload, true, @build_list.build_started?
|
%td.last{ :class => @build_list.build_started? ? nil : :hidden }
|
||||||
= t("layout.autoreload_log")
|
= label_tag :autoreload do
|
||||||
= select_tag :reload_interval, log_reload_time_options
|
= check_box_tag :autoreload, true, @build_list.build_started?
|
||||||
|
= t("layout.build_lists.log.autoreload")
|
||||||
|
= select_tag :reload_interval, log_reload_time_options
|
||||||
|
%tr.bottom
|
||||||
|
%td.first
|
||||||
|
= link_to t("layout.build_lists.log.download"), build_list_log_url(:build), :id => :log_url
|
||||||
|
%td.last{ :class => @build_list.build_started? ? nil : :hidden }
|
||||||
|
= label_tag :load_lines do
|
||||||
|
= raw t("layout.build_lists.log.load_lines", :count => select_tag(:load_lines, log_reload_lines_options))
|
||||||
.both
|
.both
|
||||||
%textarea.log{ :readonly => :readonly,
|
%textarea.log{ :readonly => :readonly, :wrap => 'off',
|
||||||
:wrap => 'off',
|
:data => { :url => log_build_list_path(@build_list), :log_type => :build } }
|
||||||
:data => {:url => build_list_log_url(:build)}}
|
|
||||||
= t("layout.build_lists.log.not_available")
|
= t("layout.build_lists.log.not_available")
|
||||||
|
|
||||||
:javascript
|
:javascript
|
||||||
|
@ -30,8 +37,10 @@
|
||||||
var $wrapper = $('div.log-wrapper');
|
var $wrapper = $('div.log-wrapper');
|
||||||
var $logBody = $wrapper.children('div.log-body').first();
|
var $logBody = $wrapper.children('div.log-body').first();
|
||||||
var $logCont = $logBody.children('.log').first();
|
var $logCont = $logBody.children('.log').first();
|
||||||
var logUrl = $logCont.data('url');
|
|
||||||
|
var logUrl = $logCont.data('url');
|
||||||
var $logHead = $wrapper.children('div.log-header').first();
|
var $logHead = $wrapper.children('div.log-header').first();
|
||||||
|
|
||||||
var $trigger = $logHead.children('span').first();
|
var $trigger = $logHead.children('span').first();
|
||||||
var $autoload = $('#autoreload');
|
var $autoload = $('#autoreload');
|
||||||
|
|
||||||
|
@ -64,17 +73,24 @@
|
||||||
$.ajax({
|
$.ajax({
|
||||||
url: logUrl,
|
url: logUrl,
|
||||||
type: "GET",
|
type: "GET",
|
||||||
|
dataType: 'json',
|
||||||
|
data: $logCont.data(),
|
||||||
|
beforeSend: function( xhr ) {
|
||||||
|
var token = $('meta[name="csrf-token"]').attr('content');
|
||||||
|
if (token) xhr.setRequestHeader('X-CSRF-Token', token);
|
||||||
|
},
|
||||||
success: function(data, textStatus, jqXHR) {
|
success: function(data, textStatus, jqXHR) {
|
||||||
var l = $logCont[0];
|
var l = $logCont[0];
|
||||||
var vScroll = l.scrollTop;
|
var vScroll = l.scrollTop;
|
||||||
var hScroll = l.scrollLeft;
|
var hScroll = l.scrollLeft;
|
||||||
var onBottom = Math.abs((l.clientHeight + vScroll - l.scrollHeight)) < getLineHeight(l);
|
var onBottom = Math.abs((l.clientHeight + vScroll - l.scrollHeight)) < getLineHeight(l);
|
||||||
|
|
||||||
$logCont.text(data);
|
$logCont.text(data.log);
|
||||||
|
|
||||||
$logCont.scrollLeft(hScroll);
|
$logCont.scrollLeft(hScroll);
|
||||||
$logCont.scrollTop((onBottom || first_open) ? l.scrollHeight - l.clientHeight : vScroll);
|
$logCont.scrollTop((onBottom || first_open) ? l.scrollHeight - l.clientHeight : vScroll);
|
||||||
first_open = false;
|
first_open = false;
|
||||||
|
if (!data.building) $autoload.attr({'checked': false}).trigger('change');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -110,18 +126,23 @@
|
||||||
window.location.href = $('a#log_anchor').attr('href');
|
window.location.href = $('a#log_anchor').attr('href');
|
||||||
}
|
}
|
||||||
|
|
||||||
loadLog();
|
|
||||||
$wrapper.on('click', '.log-header > span', toggleHandler);
|
$wrapper.on('click', '.log-header > span', toggleHandler);
|
||||||
$autoload.on('change', reloadChange);
|
$autoload.on('change', reloadChange);
|
||||||
|
|
||||||
$('#word_wrap').on('change', function() {
|
$('#word_wrap').on('change', function() {
|
||||||
$logCont.attr({'wrap': ($(this).is(':checked')) ? 'soft' : 'off'});
|
$logCont.attr({'wrap': ($(this).is(':checked')) ? 'soft' : 'off'});
|
||||||
});
|
});
|
||||||
|
|
||||||
$('#reload_interval').on('change', function() {
|
$('#reload_interval').on('change', function() {
|
||||||
clearInterval(t);
|
clearInterval(t);
|
||||||
if ($autoload.is(':checked')) {
|
if ($autoload.is(':checked')) {
|
||||||
t = setInterval($(this).val());
|
t = setInterval($(this).val());
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
$('#load_lines').on('change', function() {
|
||||||
|
$logCont.data('load_lines', $(this).val());
|
||||||
|
}).trigger('change');
|
||||||
|
loadLog();
|
||||||
|
|
||||||
})();
|
})();
|
||||||
});
|
});
|
||||||
|
|
|
@ -121,6 +121,9 @@ en:
|
||||||
log:
|
log:
|
||||||
build_log: Build Log
|
build_log: Build Log
|
||||||
not_available: Log not available yet.
|
not_available: Log not available yet.
|
||||||
|
download: Download log
|
||||||
|
autoreload: Update log every
|
||||||
|
load_lines: Load last %{count} lines
|
||||||
|
|
||||||
reload_times:
|
reload_times:
|
||||||
10000: "10 s"
|
10000: "10 s"
|
||||||
|
|
|
@ -120,6 +120,9 @@ ru:
|
||||||
log:
|
log:
|
||||||
build_log: Лог сборки
|
build_log: Лог сборки
|
||||||
not_available: В настоящий момент лог недоступен.
|
not_available: В настоящий момент лог недоступен.
|
||||||
|
download: Загрузить лог
|
||||||
|
autoreload: Обновлять лог каждые
|
||||||
|
load_lines: Загружать последние %{count} строк
|
||||||
|
|
||||||
reload_times:
|
reload_times:
|
||||||
10000: "10 сек"
|
10000: "10 сек"
|
||||||
|
|
|
@ -134,6 +134,7 @@ Rosa::Application.routes.draw do
|
||||||
resources :build_lists, :only => [:index, :show, :update] do
|
resources :build_lists, :only => [:index, :show, :update] do
|
||||||
member do
|
member do
|
||||||
put :cancel
|
put :cancel
|
||||||
|
get :log
|
||||||
end
|
end
|
||||||
collection { post :search }
|
collection { post :search }
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in New Issue