Added mock build. Part 1

master
alexey 4 weeks ago
parent 91fa281237
commit 48b648f46b

@ -733,6 +733,30 @@ post "/prjaddrepo/:id" do
end
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
not_found do

@ -82,7 +82,6 @@ class GitRepo
repo = Rugged::Repository.new(git_path)
db_info = @db.get_repo_info_by_name(reponame)
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 }
else
result = create_git_db_only(reponame)

@ -1,11 +1,27 @@
require_relative "spork"
require_relative "runner"
class MockManager
attr :path, :error, :last_status, :last_pid
attr :path, :config, :error, :last_status, :last_pid, :prep_dir
def initialize(path)
def initialize(path, config, cfg_counter_path)
@error = nil
unless File.exist? (path)
Dir.mkdir(path)
end
@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

@ -72,12 +72,14 @@ class ProjectsActions
linked_prj = []
proj_repo_path = File.join(proj_path, PROJECTS_STRUCTURE[:REPO])
proj_repo = <<~PRJ_CFG
config_opts['dnf.conf'] += """
[#{proj_name}-repository]
name=Project repository #{proj_name}
baseurl=file://#{proj_repo_path}
enabled=1
priority=80
skip_if_unavailable=True
"""
PRJ_CFG
linked_prj << proj_repo
unless id.nil?
@ -238,4 +240,7 @@ class ProjectsActions
@db.save_linked_projects(prj_id, item)
end
end
def build_projects_git(prj_id, git_id)
end
end

@ -1,3 +1,5 @@
require_relative "runner"
class RepoManager
attr :path, :error, :last_status, :last_pid
@ -10,10 +12,14 @@ class RepoManager
end
def create_repo
%x(/usr/bin/createrepo_c --database --workers 1 "#{@path}")
result = $?
@last_status = result.exitstatus
@last_pid = result.pid
result
repo_path = File.join(@path, "repodata")
cmd_args = %Q(/usr/bin/createrepo_c --database --workers 1 "#{@path}")
if File.exist?(repo_path)
cmd_args = %Q(/usr/bin/createrepo_c --database --workers 1 --update "#{@path}")
end
cmd = Runner.new(cmd_args)
cmd.run
@last_status = cmd.exit_status
@last_pid = cmd.pid
end
end

@ -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

@ -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

@ -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 %>
Loading…
Cancel
Save