Added mock build. Part 1
This commit is contained in:
24
app.rb
24
app.rb
@@ -733,6 +733,30 @@ post "/prjaddrepo/:id" do
|
|||||||
end
|
end
|
||||||
|
|
||||||
get "/gitbld/:id/:git_id" do
|
get "/gitbld/:id/:git_id" do
|
||||||
|
prj = ProjectsActions.new(cfg.get_projects_path, db)
|
||||||
|
if prj.path.nil?
|
||||||
|
print_error_page(503, "Путь к проектам не существует")
|
||||||
|
else
|
||||||
|
repo = GitRepo.new(cfg.get_repo, db)
|
||||||
|
if repo.path.nil?
|
||||||
|
print_error_page(503, "Путь к репозиториям не существует")
|
||||||
|
else
|
||||||
|
prj_info = prj.get_project(params["id"])
|
||||||
|
if prj_info.nil?
|
||||||
|
print_error_page(503, "Путь к проектам не существует")
|
||||||
|
else
|
||||||
|
git_info = repo.get_repo_short_info_by_id(params["git_id"].to_i)
|
||||||
|
@page_name = "#{prj_info[:projname]} - сборка #{git_info[:reponame]}"
|
||||||
|
@proj_name = prj_info[:projname]
|
||||||
|
@proj_descr = prj_info[:descr]
|
||||||
|
@git_name = git_info[:reponame]
|
||||||
|
|
||||||
|
prj.build_projects_git(prj_info[:id], git_info[:id])
|
||||||
|
|
||||||
|
erb :prjbld
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
not_found do
|
not_found do
|
||||||
|
|||||||
@@ -82,7 +82,6 @@ class GitRepo
|
|||||||
repo = Rugged::Repository.new(git_path)
|
repo = Rugged::Repository.new(git_path)
|
||||||
db_info = @db.get_repo_info_by_name(reponame)
|
db_info = @db.get_repo_info_by_name(reponame)
|
||||||
unless db_info.nil?
|
unless db_info.nil?
|
||||||
db_info = db_info.first
|
|
||||||
repos_data = { :reponame => db_info.reponame, :descr => db_info.descr, :public => db_info.public, :full => 1 }
|
repos_data = { :reponame => db_info.reponame, :descr => db_info.descr, :public => db_info.public, :full => 1 }
|
||||||
else
|
else
|
||||||
result = create_git_db_only(reponame)
|
result = create_git_db_only(reponame)
|
||||||
|
|||||||
@@ -1,11 +1,27 @@
|
|||||||
class MockManager
|
require_relative "spork"
|
||||||
attr :path, :error, :last_status, :last_pid
|
require_relative "runner"
|
||||||
|
|
||||||
def initialize(path)
|
class MockManager
|
||||||
|
attr :path, :config, :error, :last_status, :last_pid, :prep_dir
|
||||||
|
|
||||||
|
def initialize(path, config, cfg_counter_path)
|
||||||
@error = nil
|
@error = nil
|
||||||
unless File.exist? (path)
|
unless File.exist? (path)
|
||||||
Dir.mkdir(path)
|
Dir.mkdir(path)
|
||||||
end
|
end
|
||||||
@path = path
|
@path = path
|
||||||
|
@config = config
|
||||||
|
cntr = 0
|
||||||
|
|
||||||
|
File.open(cfg_counter_path, "r+") do |f|
|
||||||
|
f.flock(File::LOCK_EX)
|
||||||
|
counter = f.gets.strip
|
||||||
|
i_counter = counter.to_i
|
||||||
|
i_counter = i_counter + 1
|
||||||
|
f.puts("#{i_counter}")
|
||||||
|
cnt = i_counter
|
||||||
|
end
|
||||||
|
tmp_name = (0...10).map { ("a".."z").to_a[rand(26)] }.join
|
||||||
|
@prep_dir = File.join(path, "#{cntr}_#{tmp_name}")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -72,12 +72,14 @@ class ProjectsActions
|
|||||||
linked_prj = []
|
linked_prj = []
|
||||||
proj_repo_path = File.join(proj_path, PROJECTS_STRUCTURE[:REPO])
|
proj_repo_path = File.join(proj_path, PROJECTS_STRUCTURE[:REPO])
|
||||||
proj_repo = <<~PRJ_CFG
|
proj_repo = <<~PRJ_CFG
|
||||||
|
config_opts['dnf.conf'] += """
|
||||||
[#{proj_name}-repository]
|
[#{proj_name}-repository]
|
||||||
name=Project repository #{proj_name}
|
name=Project repository #{proj_name}
|
||||||
baseurl=file://#{proj_repo_path}
|
baseurl=file://#{proj_repo_path}
|
||||||
enabled=1
|
enabled=1
|
||||||
priority=80
|
priority=80
|
||||||
skip_if_unavailable=True
|
skip_if_unavailable=True
|
||||||
|
"""
|
||||||
PRJ_CFG
|
PRJ_CFG
|
||||||
linked_prj << proj_repo
|
linked_prj << proj_repo
|
||||||
unless id.nil?
|
unless id.nil?
|
||||||
@@ -238,4 +240,7 @@ class ProjectsActions
|
|||||||
@db.save_linked_projects(prj_id, item)
|
@db.save_linked_projects(prj_id, item)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def build_projects_git(prj_id, git_id)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
require_relative "runner"
|
||||||
|
|
||||||
class RepoManager
|
class RepoManager
|
||||||
attr :path, :error, :last_status, :last_pid
|
attr :path, :error, :last_status, :last_pid
|
||||||
|
|
||||||
@@ -10,10 +12,14 @@ class RepoManager
|
|||||||
end
|
end
|
||||||
|
|
||||||
def create_repo
|
def create_repo
|
||||||
%x(/usr/bin/createrepo_c --database --workers 1 "#{@path}")
|
repo_path = File.join(@path, "repodata")
|
||||||
result = $?
|
cmd_args = %Q(/usr/bin/createrepo_c --database --workers 1 "#{@path}")
|
||||||
@last_status = result.exitstatus
|
if File.exist?(repo_path)
|
||||||
@last_pid = result.pid
|
cmd_args = %Q(/usr/bin/createrepo_c --database --workers 1 --update "#{@path}")
|
||||||
result
|
end
|
||||||
|
cmd = Runner.new(cmd_args)
|
||||||
|
cmd.run
|
||||||
|
@last_status = cmd.exit_status
|
||||||
|
@last_pid = cmd.pid
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
89
classes/runner.rb
Normal file
89
classes/runner.rb
Normal file
@@ -0,0 +1,89 @@
|
|||||||
|
require "open3"
|
||||||
|
|
||||||
|
class Runner
|
||||||
|
attr_reader :cmd, :exit_status, :stdout, :stderr, :pid
|
||||||
|
|
||||||
|
# Run a command, return runner instance
|
||||||
|
# @param cmd [String,Array<String>] command to execute
|
||||||
|
def self.run(*cmd)
|
||||||
|
Runner.new(*cmd).run
|
||||||
|
end
|
||||||
|
|
||||||
|
# Run a command, raise Runner::Error if it fails
|
||||||
|
# @param cmd [String,Array<String>] command to execute
|
||||||
|
# @raise [Runner::Error]
|
||||||
|
def self.run!(*cmd)
|
||||||
|
Runner.new(*cmd).run!
|
||||||
|
end
|
||||||
|
|
||||||
|
# Run a command, return true if it succeeds, false if not
|
||||||
|
# @param cmd [String,Array<String>] command to execute
|
||||||
|
# @return [Boolean]
|
||||||
|
def self.run?(*cmd)
|
||||||
|
Runner.new(*cmd).run?
|
||||||
|
end
|
||||||
|
|
||||||
|
Error = Class.new(StandardError)
|
||||||
|
|
||||||
|
# @param cmd [String,Array<String>] command to execute
|
||||||
|
def initialize(cmd)
|
||||||
|
@cmd = cmd.is_a?(Array) ? cmd.join(" ") : cmd
|
||||||
|
@stdout = +""
|
||||||
|
@stderr = +""
|
||||||
|
@exit_status = nil
|
||||||
|
end
|
||||||
|
|
||||||
|
# @return [Boolean] success or failure?
|
||||||
|
def success?
|
||||||
|
exit_status.zero?
|
||||||
|
end
|
||||||
|
|
||||||
|
# Run the command, return self
|
||||||
|
# @return [Runner]
|
||||||
|
def run
|
||||||
|
Open3.popen3(cmd) do |stdin, stdout, stderr, wait_thr|
|
||||||
|
until [stdout, stderr].all?(&:eof?)
|
||||||
|
readable = IO.select([stdout, stderr])
|
||||||
|
next unless readable&.first
|
||||||
|
|
||||||
|
readable.first.each do |stream|
|
||||||
|
data = +""
|
||||||
|
# rubocop:disable Lint/HandleExceptions
|
||||||
|
begin
|
||||||
|
stream.read_nonblock(1024, data)
|
||||||
|
rescue EOFError
|
||||||
|
# ignore, it's expected for read_nonblock to raise EOFError
|
||||||
|
# when all is read
|
||||||
|
end
|
||||||
|
|
||||||
|
if stream == stdout
|
||||||
|
@stdout << data
|
||||||
|
$stdout.write(data)
|
||||||
|
else
|
||||||
|
@stderr << data
|
||||||
|
$stderr.write(data)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
@exit_status = wait_thr.value.exitstatus
|
||||||
|
@pid = wait_thr.pid
|
||||||
|
end
|
||||||
|
|
||||||
|
self
|
||||||
|
end
|
||||||
|
|
||||||
|
# Run the command and return stdout, raise if fails
|
||||||
|
# @return stdout [String]
|
||||||
|
# @raise [Runner::Error]
|
||||||
|
def run!
|
||||||
|
return run.stdout if run.success?
|
||||||
|
|
||||||
|
raise(Error, "command failed, exit: %d - stdout: %s / stderr: %s" % [exit_status, stdout, stderr])
|
||||||
|
end
|
||||||
|
|
||||||
|
# Run the command and return true if success, false if failure
|
||||||
|
# @return success [Boolean]
|
||||||
|
def run?
|
||||||
|
run.success?
|
||||||
|
end
|
||||||
|
end
|
||||||
80
classes/spork.rb
Normal file
80
classes/spork.rb
Normal file
@@ -0,0 +1,80 @@
|
|||||||
|
# A way to cleanly handle process forking in Sinatra when using Passenger, aka "sporking some code".
|
||||||
|
# This will allow you to properly execute some code asynchronously, which otherwise does not work correctly.
|
||||||
|
#
|
||||||
|
# Written by Ron Evans
|
||||||
|
# More info at http://deadprogrammersociety.com
|
||||||
|
#
|
||||||
|
# Mostly lifted from the Spawn plugin for Rails (http://github.com/tra/spawn)
|
||||||
|
# but with all of the Rails stuff removed.... cause you are using Sinatra. If you are using Rails, Spawn is
|
||||||
|
# what you need. If you are using something else besides Sinatra that is Rack-based under Passenger, and you are having trouble with
|
||||||
|
# asynch processing, let me know if spork helped you.
|
||||||
|
#
|
||||||
|
module Spork
|
||||||
|
# things to close in child process
|
||||||
|
@@resources = []
|
||||||
|
def self.resources
|
||||||
|
@@resources
|
||||||
|
end
|
||||||
|
|
||||||
|
# set the resource to disconnect from in the child process (when forking)
|
||||||
|
def self.resource_to_close(resource)
|
||||||
|
@@resources << resource
|
||||||
|
end
|
||||||
|
|
||||||
|
# close all the resources added by calls to resource_to_close
|
||||||
|
def self.close_resources
|
||||||
|
@@resources.each do |resource|
|
||||||
|
resource.close if resource && resource.respond_to?(:close) && !resource.closed?
|
||||||
|
end
|
||||||
|
@@resources = []
|
||||||
|
end
|
||||||
|
|
||||||
|
# actually perform the fork... er, spork
|
||||||
|
# valid options are:
|
||||||
|
# :priority => to set the process priority of the child
|
||||||
|
# :logger => a logger object to use from the child
|
||||||
|
# :no_detach => true if you want to keep the child process under the parent control. usually you do NOT want this
|
||||||
|
def self.spork(options = {})
|
||||||
|
logger = options[:logger]
|
||||||
|
logger.debug "spork> parent PID = #{Process.pid}" if logger
|
||||||
|
child = fork do
|
||||||
|
begin
|
||||||
|
start = Time.now
|
||||||
|
logger.debug "spork> child PID = #{Process.pid}" if logger
|
||||||
|
|
||||||
|
# set the nice priority if needed
|
||||||
|
Process.setpriority(Process::PRIO_PROCESS, 0, options[:priority]) if options[:priority]
|
||||||
|
|
||||||
|
# disconnect from the rack
|
||||||
|
Spork.close_resources
|
||||||
|
|
||||||
|
# run the block of code that takes so long
|
||||||
|
yield
|
||||||
|
rescue => ex
|
||||||
|
logger.error "spork> Exception in child[#{Process.pid}] - #{ex.class}: #{ex.message}" if logger
|
||||||
|
ensure
|
||||||
|
logger.info "spork> child[#{Process.pid}] took #{Time.now - start} sec" if logger
|
||||||
|
# this form of exit doesn't call at_exit handlers
|
||||||
|
exit!(0)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# detach from child process (parent may still wait for detached process if they wish)
|
||||||
|
Process.detach(child) unless options[:no_detach]
|
||||||
|
|
||||||
|
return child
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# Patch to work with passenger
|
||||||
|
if defined? Passenger::Rack::RequestHandler
|
||||||
|
class Passenger::Rack::RequestHandler
|
||||||
|
alias_method :orig_process_request, :process_request
|
||||||
|
|
||||||
|
def process_request(env, input, output)
|
||||||
|
Spork.resource_to_close(input)
|
||||||
|
Spork.resource_to_close(output)
|
||||||
|
orig_process_request(env, input, output)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
47
views/prjbld.erb
Normal file
47
views/prjbld.erb
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
<%= erb :header %>
|
||||||
|
<div class="container">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-4">
|
||||||
|
<h3 class="bg-secondary-subtle text-center border-bottom border-primary-subtle rounded-1 pb-1 mb-2">
|
||||||
|
<a href="/prjedit/<%= ERB::Util.url_encode(@proj_id) %>"><%= @proj_name %></a>
|
||||||
|
</h3>
|
||||||
|
<div class="pb-2"><%= @proj_descr %></div>
|
||||||
|
<div class="pb-2">git репозиторий <%= @git_name %></div>
|
||||||
|
</div>
|
||||||
|
<div class="col-8">
|
||||||
|
<div class="hstack gap-3">
|
||||||
|
<div class="p-2">Процесс сборки</div>
|
||||||
|
<div><button type="button" class="btn btn-outline-primary" id="startBtn"><i
|
||||||
|
class="bi bi-play-fill"></i></button>
|
||||||
|
</div>
|
||||||
|
<div><button type="button" class="btn btn-outline-primary" id="stopBtn"><i
|
||||||
|
class="bi bi-pause-fill"></i></button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="ratio ratio-4x3">
|
||||||
|
<iframe src="/" title="Процесс сборки" id="bldframe" allowfullscreen></iframe>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<script type="text/javascript">
|
||||||
|
var intervalId = null;
|
||||||
|
$(function () {
|
||||||
|
intervalId = setInterval(refreshiframe, 5000);
|
||||||
|
});
|
||||||
|
function refreshiframe() {
|
||||||
|
$('#bldframe').attr('src', $('#bldframe').attr('src'));
|
||||||
|
}
|
||||||
|
$("#startBtn").click(function () {
|
||||||
|
if (intervalId == null) {
|
||||||
|
intervalId = setInterval(refreshiframe, 5000);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
$("#stopBtn").click(function () {
|
||||||
|
if (intervalId != null) {
|
||||||
|
clearInterval(intervalId);
|
||||||
|
intervalId = null;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
<%= erb :footer %>
|
||||||
Reference in New Issue
Block a user