diff --git a/app.rb b/app.rb index f5ffdc2..2c7eb81 100644 --- a/app.rb +++ b/app.rb @@ -26,7 +26,7 @@ def print_error_page(error_status, error_meaasge) end cfg = IniConfig.new() -db = DBase.new() +db = DBase.new(cfg) set :port, cfg.get_port set :public_folder, File.dirname(__FILE__) + "/public" diff --git a/classes/db.rb b/classes/db.rb index d2f8c69..7fd892b 100644 --- a/classes/db.rb +++ b/classes/db.rb @@ -28,9 +28,13 @@ class BuildTask < Sequel::Model(:buildtask) end class DBase - attr :error, :last_id + attr :error, :last_id, :cfg - def creategit(project_name, description) + def initialize(cfg) + @cfg = cfg + end + + def creategit(project_name, description, cfg) @error = nil data = Repos.where(reponame: project_name).first if data.nil? @@ -238,4 +242,12 @@ class DBase def get_build_task_process_log(build_id) BuildTask.where(id: build_id.to_i).first end + + def before_fork() + Sequel::DATABASES.each(&:disconnect) + end + + def after_fork() + Sequel.connect(@cfg.get_db) + end end diff --git a/classes/mock.rb b/classes/mock.rb index 13677cf..cfa4fce 100644 --- a/classes/mock.rb +++ b/classes/mock.rb @@ -1,15 +1,21 @@ require_relative "spork" require_relative "runner" require "fileutils" +require "logger" + +BUILD_STRUCTURE = { + :SRC => "src", + :RPMS => "rpms", + :RESULT => "result", + :RESULT_SRPM => "result_srpm", +} -# -#mock -r /home/alexey/workspace/ruby-projects/mock-gui/projects/prjt1.prj/configs/prjt1.cfg --buildsrpm --spec srcprp/bayrepo_neuro_farm.spec --sources srcprp/ --resultdir result/ --isolation=simple --disable-plugin=ccache #mock -r /home/alexey/workspace/ruby-projects/mock-gui/projects/prjt1.prj/configs/prjt1.cfg result/bayrepo-neuro-farm-0.1-2.src.rpm --resultdir result2/ --isolation simple class MockManager - attr :path, :config, :error, :last_status, :last_pid, :prep_dir, :db, :resultpath, :process_log, :repo_path + attr :path, :config, :error, :last_status, :last_pid, :prep_dir, :db, :resultpath, :process_log, :repo_path, :git_path, :build_id, :log, :recips, :spec, :repo_lock - def initialize(path, config, cfg_counter_path, db, result_path, repo_path) + def initialize(path, config, cfg_counter_path, db, result_path, repo_path, git_path, build_id, recips, spec_file, repo_lock) @error = nil unless File.exist? (path) Dir.mkdir(path) @@ -20,6 +26,11 @@ class MockManager @db = db @resultpath = result_path @repo_path = repo_path + @git_path = git_path + @build_id = build_id + @recips = recips + @spec = spec_file + @repo_lock = repo_lock File.open(cfg_counter_path, "r+") do |f| f.flock(File::LOCK_EX) @@ -34,6 +45,7 @@ class MockManager @process_log = File.join(@prep_dir, "process.log") Dir.mkdir(@prep_dir) FileUtils.touch(@process_log) + @log = nil end def get_build_process_log() @@ -41,10 +53,110 @@ class MockManager end def finalize_build_task() + @log.close + end + + def clean_build + @log.info("Удаление временной сборочной среды #{@path}") FileUtils.rm_rf(@path) end + def prepare_structure() + @log.info("Подготовка структуры каталогов") + BUILD_STRUCTURE.each_pair do |key, value| + new_path = File.join(@prep_dir, value) + @log.info("Создан каталог #{new_path}") + Dir.mkdir(new_path) + end + end + + def prepare_src() + @log.info("Подготовка исходных файлов проекта к формированию SRPMS") + if File.exist?(@git_path) + if File.directory?(@git_path) + FileUtils.cp_r(@git_path, File.join(@prep_dir, BUILD_STRUCTURE[:SRC]), verbose: true, remove_destination: true) + FileUtils.rm_rf(File.join(@prep_dir, BUILD_STRUCTURE[:SRC], ".git"), secure: true) + else + @log.error("Это файл #{@git_path}, а не каталог") + @error = true + end + else + @log.error("Каталог #{@git_path} не существует") + @error = true + end + end + + def prepare_source() + @log.info("Запукс подготовительных скриптов") + @recips.each_with_index do |item, index| + @log.info("Формируем рецепт #{item[:filepath]}") + rcp_name = "#{index}rcp_#{item[:filepath]}" + File.open(File.join(@prep_dir, BUILD_STRUCTURE[:SRC], rcp_name)) do |f| + f.write(item[:content]) + end + Dir.chdir(File.join(@prep_dir, BUILD_STRUCTURE[:SRC])) do + script = File.join(@prep_dir, BUILD_STRUCTURE[:SRC], rcp_name) + cmd_args = %Q(/usr/bin/bash -x "#{script}") + cmd = Runner.new(cmd_args, @log) + cmd.run_clean + @error = true if cmd.exit_status != 0 + end + break if @error + end + end + + def prepare_src_rpm() + @log.info("Подготовка SRCRPM") + spec_file = File.join(@prep_dir, BUILD_STRUCTURE[:SRC], @spec) + if File.exist?(spec_file) + Dir.chdir(File.join(@prep_dir, BUILD_STRUCTURE[:SRC])) do + script = File.join(@prep_dir, BUILD_STRUCTURE[:SRC], rcp_name) + cmd_args = %Q(/usr/bin/mock -r #{@config} --buildsrpm --spec #{spec_file} --sources #{File.join(@prep_dir, BUILD_STRUCTURE[:SRC])} --resultdir #{File.join(@prep_dir, BUILD_STRUCTURE[:RESULT_SRPM])} --isolation=simple --disable-plugin=ccache") + cmd = Runner.new(cmd_args, @log) + cmd.run_clean + @error = true if cmd.exit_status != 0 + end + else + @error = true + @log.error("Не могу найти sepc файл #{spec_file}") + end + end + + def build_rpm() + end + + def save_logs() + end + + def save_rpms() + File.open(@repo_lock, File::RDWR | File::CREAT) do |f| + f.flock(File::LOCK_EX) + # выклдака пакетов и пересоздание repodata + end + end + def build_task() - finalize_build_task + @error = false + @db.before_fork + spock = Spork.spork(:logger => log) do + @db.after_fork + $stdout = File.open(@process_log, "w") + @log = Logger.new($stdout) + if @sepc == "" + @error = true + @log.error("Не могу найти spec файл") + end + prepare_structure if @error == false + prepare_src if @error == false + prepare_source if @error == false + prepare_src_rpm if @error == false + build_rpm if @error == false + save_logs + save_rpms if @error == false + clean_build + @log.close + end + @db.after_fork + spock end end diff --git a/classes/projects.rb b/classes/projects.rb index 6690830..97a0d0b 100644 --- a/classes/projects.rb +++ b/classes/projects.rb @@ -2,6 +2,7 @@ require "fileutils" require_relative "db" require_relative "repomanage" require_relative "mock" +require_relative "utilities" PROJECTS_STRUCTURE = { :REPO => "repo", @@ -243,6 +244,23 @@ class ProjectsActions end end + def find_spec_file(prj_id, git_id) + spec_file = "" + proj_path = get_project_path(prj_id) + git_name = @db.get_repo_info_by_id(git_id) + git_source = File.join(proj_path, PROJECTS_STRUCTURE[:SRC], git_name[:reponame]) + spec = @db.get_project_repo_spec(prj_id, git_id) + if spec.nil? + spec_files = get_spec_files_in_dir(git_source) + unless spec_files.nil? + spec_file = spec_files.first + end + else + spec_file = spec[:spec_name] + end + spec_file + end + def build_projects_git(prj_id, git_id, counter_file) bld_id = 0 build_ok = true @@ -250,6 +268,8 @@ class ProjectsActions git_name = @db.get_repo_info_by_id(git_id) prep_script = @db.get_git_recips(git_id) prepare_path = File.join(proj_path, PROJECTS_STRUCTURE[:SRCPRP], git_name[:reponame]) + spec_file = find_spec_file(prj_id, git_id) + repo_lock = File.join(proj_path, PROJECTS_STRUCTURE[:CONFIGS], ".repolock") if File.exist?(prepare_path) lockf_path = File.join(prepare_path, "lock") File.open(lockf_path, File::RDWR | File::CREAT) do |f| @@ -282,12 +302,15 @@ class ProjectsActions #Начинаем сборку build_path = File.join(proj_path, PROJECTS_STRUCTURE[:LOGS], git_name[:reponame]) repo_path = File.join(proj_path, PROJECTS_STRUCTURE[:REPO]) + git_source = File.join(proj_path, PROJECTS_STRUCTURE[:SRC], git_name[:reponame]) @db.create_build_task(prj_id, git_id, build_path) build_id = @db.last_id - mock = MockManager.new(prepare_path, get_project_config(prj_id), counter_file, @db, build_path, repo_path) + mock = MockManager.new(prepare_path, get_project_config(prj_id), counter_file, @db, build_path, repo_path, git_source, build_id, prep_script, spec_file, repo_lock) bld_id = build_id @db.update_build_task_error_log(build_id, mock.get_build_process_log) mock.build_task + mock.finalize_build_task + f.flock(File::LOCK_UN) end end bld_id diff --git a/classes/runner.rb b/classes/runner.rb index f2a84ac..1ef66f4 100644 --- a/classes/runner.rb +++ b/classes/runner.rb @@ -1,7 +1,8 @@ require "open3" +require "logger" class Runner - attr_reader :cmd, :exit_status, :stdout, :stderr, :pid + attr_reader :cmd, :exit_status, :stdout, :stderr, :pid, :log # Run a command, return runner instance # @param cmd [String,Array] command to execute @@ -26,11 +27,12 @@ class Runner Error = Class.new(StandardError) # @param cmd [String,Array] command to execute - def initialize(cmd) + def initialize(cmd, log = nil) @cmd = cmd.is_a?(Array) ? cmd.join(" ") : cmd @stdout = +"" @stderr = +"" @exit_status = nil + @log = log end # @return [Boolean] success or failure? @@ -58,10 +60,54 @@ class Runner if stream == stdout @stdout << data - $stdout.write(data) + if log.nil? + $stdout.write(data) + else + log.info(data) + end else @stderr << data - $stderr.write(data) + if log.nil? + $stderr.write(data) + else + log.error(data) + end + end + end + end + @exit_status = wait_thr.value.exitstatus + @pid = wait_thr.pid + end + + self + end + + # Run the command no output, return self + # @return [Runner] + def run_clean + 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 + unless log.nil? + log.info(data) + end + else + unless log.nil? + log.error(data) + end end end end diff --git a/views/prjlist.erb b/views/prjlist.erb index e48a9e7..da78752 100644 --- a/views/prjlist.erb +++ b/views/prjlist.erb @@ -24,7 +24,7 @@
<%= item[:projname] %>

<%= item[:descr] %>

- Редактировать + Перейти к проекту