You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

463 lines
15 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

require "fileutils"
require_relative "db"
require_relative "repomanage"
require_relative "mock"
require_relative "utilities"
require "digest"
PROJECTS_STRUCTURE = {
:REPO => "repo",
:LOGS => "logs",
:CONFIGS => "configs",
:SRCPRP => "srcprp",
:SIGNED => "signed",
:SRC => "src",
}
class ProjectsActions
attr :path, :error, :db
def initialize(path, db)
@path = nil
@error = nil
@db = db
if File.absolute_path?(path)
if File.exist?(path)
@path = path
end
else
apath = File.realpath(path)
if File.exist?(apath)
@path = apath
end
end
end
def get_projects
@db.proj_list
end
def get_project(id)
@db.proj(id.to_i)
end
def get_project_path(id)
@error = nil
fname = nil
prj = @db.proj(id)
if prj.nil?
@error = "Проекта с id = #{id} не существует"
else
fname = File.expand_path("#{prj[:projname]}.prj", @path)
end
fname
end
def get_project_config(id)
@error = nil
fname = nil
prj = @db.proj(id)
if prj.nil?
@error = "Проекта с id = #{id} не существует"
else
fname = File.expand_path("#{prj[:projname]}.prj", @path)
fname = File.join(fname, PROJECTS_STRUCTURE[:CONFIGS], "#{prj[:projname]}.cfg")
end
fname
end
def get_project_repo(id)
proj_path = get_project_path(id)
File.join(proj_path, PROJECTS_STRUCTURE[:REPO])
end
def get_project_path_git(id, gitname)
proj_path = get_project_path(id)
File.join(proj_path, PROJECTS_STRUCTURE[:SRC], gitname)
end
def generate_linked_repos(id, proj_path, proj_name, linked_repo_tpl)
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?
link_prj_list = @db.get_projects_links(id)
unless link_prj_list.nil?
link_prj_list.each do |item|
internal_repo = ProjectsActions.new(@path, @db)
internal_path = internal_repo.get_project_path(item[:proj_id_repository])
internal_repo_path = File.join(internal_path, PROJECTS_STRUCTURE[:REPO])
internal_proj_info = internal_repo.get_project(item[:proj_id_repository])
proj_repo = <<~PRJ_CFG
[#{internal_proj_info[:projname]}-repository]
name=Project repository #{internal_proj_info[:projname]}
baseurl=file://#{internal_repo_path}
enabled=1
skip_if_unavailable=True
PRJ_CFG
linked_prj << proj_repo
end
end
end
File.open(linked_repo_tpl, "w") { |f| f << linked_prj.join("\n\n\n") }
end
def regenerate_linked_repos(id)
proj_path = get_project_path(id)
config_path = File.join(proj_path, PROJECTS_STRUCTURE[:CONFIGS])
prj_incl_path = File.join(config_path, "repos_include.tpl")
prj_info = get_project(id)
unless prj_info.nil?
generate_linked_repos(id, proj_path, prj_info[:projname], prj_incl_path)
end
end
def generate_config(id, configuration_path, proj_path, proj_name)
proj_conf_path = File.join(proj_path, PROJECTS_STRUCTURE[:CONFIGS], "#{proj_name}.cfg")
conf_path = File.join(proj_path, PROJECTS_STRUCTURE[:CONFIGS])
prj_incl_path = File.join(conf_path, "repos_include.tpl")
proj_config = <<~PRJ_CFG
include("#{configuration_path}")
include("#{prj_incl_path}")
config_opts['plugin_conf']['ccache_enable'] = False
config_opts['plugin_conf']['ccache_opts']['max_cache_size'] = '4G'
config_opts['plugin_conf']['ccache_opts']['hashdir'] = True
config_opts['plugin_conf']['ccache_opts']['debug'] = False
config_opts['plugin_conf']['ccache_opts']['show_stats'] = True
config_opts['plugin_conf']['package_state_enable'] = True
config_opts['plugin_conf']['procenv_enable'] = False
config_opts['plugin_conf']['root_cache_enable'] = True
config_opts['plugin_conf']['showrc_enable'] = True
config_opts['plugin_conf']['yum_cache_enable'] = True
config_opts['chroot_setup_cmd'] += " gcc gcc-c++ make"
PRJ_CFG
File.open(proj_conf_path, "w") { |f| f << proj_config }
generate_linked_repos(id, proj_path, proj_name, prj_incl_path)
end
def create_project(name, description, configuration, nopublic)
@error = nil
ret_val = 0
project_name = sanitize_rcptname(name)
fname = File.expand_path("#{project_name}.prj", @path)
if File.exist?(fname)
@error = "Проект с таким именем уже существует: #{project_name}"
ret_val = 1
else
created = false
#begin
Dir.mkdir(fname)
PROJECTS_STRUCTURE.each_pair do |key, value|
new_path = File.join(fname, value)
Dir.mkdir(new_path)
end
if File.exist?(configuration)
generate_config(nil, configuration, fname, project_name)
@error = @db.proj_create(project_name, description, nopublic)
if @error.nil?
created = true
end
repo_path = File.join(fname, PROJECTS_STRUCTURE[:REPO])
repoman = RepoManager.new(repo_path)
repoman.create_repo
else
ret_val = 1
@error = "Конфигурация #{configuration} не существует"
end
#rescue => e
# ret_val = 1
# @error = e.message
#end
unless created
FileUtils.rm_rf(fname, secure: true)
end
end
ret_val
end
def get_project_gits(id, repo)
res = @db.get_gits_for_projects(id)
res_sync = res.map do |item|
prj_p = get_project_path(id)
path = File.join(prj_p, PROJECTS_STRUCTURE[:SRC], item[:reponame])
item[:is_repo_synced] = repo.is_repos_sync(item[:reponame], path)
item
end
res
end
def add_git_to_project(prj_id, git_id, repo, git_name)
path = get_project_path(prj_id)
if @error.nil?
path = File.join(path, PROJECTS_STRUCTURE[:SRC], git_name)
err = repo.clone_repo_master(git_id, path)
if err.nil?
@db.save_git_project(prj_id, git_id)
end
else
err = @error
end
err
end
def renew_git_to_project(prj_id, git_id, repo, git_name)
path = get_project_path(prj_id)
if @error.nil?
path = File.join(path, PROJECTS_STRUCTURE[:SRC], git_name)
err = repo.clone_repo_master(git_id, path)
else
err = @error
end
err
end
def get_related_projects_list(prj_id)
links_list = []
links = @db.get_projects_links(prj_id)
unless links.nil?
links_list = links.map do |item|
prj_info = @db.proj(item[:proj_id_repository])
if prj_info.nil?
item[:list_state] = false
else
item[:list_state] = true
item[:prj_info] = prj_info
end
item
end.select { |item| item[:list_state] }
end
links_list
end
def delete_linked_projects(prj_id)
@db.delete_linked_projects(prj_id)
end
def save_linked_projects(prj_id, new_ids, delete_ids)
delete_ids.each { |item| @db.delete_linked_projects_with_id(prj_id, item) }
new_ids.each do |item|
@db.save_linked_projects(prj_id, item)
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
proj_path = get_project_path(prj_id)
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|
result = f.flock(File::LOCK_EX | File::LOCK_NB)
if result == false
#Файл заблокирован считать id и вывести сведения о сборке
build_ok = false
build_id = f.gets
unless build_id.nil?
build_id = build_id.strip.to_i
end
if build_id > 0
build_info = @db.get_build_task_process_log(build_id)
unless build_info.nil?
bld_id = build_info[:id]
end
end
else
#Сборка завершилась, но каталог не подчистился
FileUtils.rm_rf(prepare_path)
f.flock(File::LOCK_UN)
build_ok = true
end
end
end
#Верная ситуация
if build_ok
Dir.mkdir(prepare_path)
lockf_path = File.join(prepare_path, "lock")
File.open(lockf_path, File::RDWR | File::CREAT) do |f|
f.flock(File::LOCK_EX)
f.rewind
#Начинаем сборку
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
f.puts(build_id)
f.flush
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, git_id)
bld_id = build_id
@db.update_build_task_error_log(build_id, mock.get_build_process_log)
mock.build_task
end
end
bld_id
end
def delete_git_from_project(prj_id, git_id)
@error = nil
builds_lst = db.get_builds_for_project_git(prj_id, git_id)
active_build = false
builds_lst.each do |item|
if item[:state] == 0
active_build = true
break
end
end
if active_build
@error = "Нельзя удалить git репозиторий с незавершенными сборками"
else
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])
FileUtils.rm_rf(git_source, secure: true)
@db.delete_git_from_project(prj_id, git_id)
end
@error
end
def delete_project(prj_id)
@error = nil
builds_lst = db.get_builds_for_project(prj_id)
active_build = false
builds_lst.each do |item|
if item[:state] == 0
active_build = true
break
end
end
if active_build
@error = "Нельзя удалить git репозиторий с незавершенными сборками"
else
linked = @db.projects_with_current_as_link(prj_id)
if linked.nil? || linked.length == 0
proj_path = get_project_path(prj_id)
FileUtils.rm_rf(proj_path, secure: true)
@db.delete_project(prj_id)
else
@error = "На текущий проект ссылаются другие проекты. Удаление запрещено"
end
end
@error
end
def sign_project(prj_id, key_path, password, url, tpl_dir)
@error = nil
proj_path = get_project_path(prj_id)
sign_repo_path = File.join(proj_path, PROJECTS_STRUCTURE[:SIGNED])
repo_path = File.join(proj_path, PROJECTS_STRUCTURE[:REPO])
repo_sign = RepoManager.new(sign_repo_path)
repo_key = RepoManagerKeys.new(key_path)
if password.nil?
password = repo_key.check_password_exists
end
if password.nil?
@error = "Не указан пароль для подписи"
else
repo_lock = File.join(proj_path, PROJECTS_STRUCTURE[:CONFIGS], ".repolock")
sign_lock = File.join(proj_path, PROJECTS_STRUCTURE[:CONFIGS], ".signlock")
prj = @db.proj(prj_id)
if repo_key.check_key_exists
File.open(sign_lock, File::RDWR | File::CREAT) do |s|
s.flock(File::LOCK_EX)
File.open(repo_lock, File::RDWR | File::CREAT) do |f|
f.flock(File::LOCK_EX)
rpm_list = get_rpms_list(repo_path)
if prj[:public] == 0
rpm_list = rpm_list.reject do |item|
block = false
block = true if item =~ /\.src\.rpm$/ || item =~ /SRPMS/ || item =~ /Debug/ || item =~ /(debuginfo.+rpm$)|(debugsource.+rpm$)/
block
end
end
rpm_signed_list = get_rpms_list(sign_repo_path)
rpm_list = rpm_list.select do |item|
sign_repo_path_rpm = File.join(sign_repo_path, item)
unless File.exist?(sign_repo_path_rpm)
file_path_full = File.join(repo_path, item)
unless File.exist?(File.dirname(sign_repo_path_rpm))
FileUtils.mkdir_p(File.dirname(sign_repo_path_rpm))
end
FileUtils.cp_r(file_path_full, File.dirname(sign_repo_path_rpm), verbose: false, remove_destination: false)
sha256 = Digest::SHA256.file(file_path_full)
rpm_info = @db.get_rpm_info_by_hash(sha256.hexdigest)
unless rpm_info.nil?
@db.update_rpm_sign(rpm_info[:id], sign_repo_path_rpm)
end
repo_key.sign_package(sign_repo_path_rpm, password)
end
end
repo_url = "http://localhost/"
if prj[:remote_address].nil? || prj[:remote_address].strip == ""
repo_url = url
else
repo_url = prj[:remote_address]
end
if repo_url[-1] != "/"
repo_url = repo_url + "/"
end
repo_sign.repoview(repo_url, prj[:projname], tpl_dir)
repo_sign.create_repo
pub_key = repo_key.get_publick_key
proj_repo_key = File.join(sign_repo_path, "#{prj[:projname]}-gpg-key")
unless File.exist?(proj_repo_key)
FileUtils.cp_r(pub_key, proj_repo_key, verbose: false, remove_destination: false)
end
end
end
else
@error = "Ключ для подписи отсутствует"
end
end
@error
end
def set_address(prj_id, address)
@error = nil
if address.nil?
address = ""
else
address = address.strip
end
@db.set_project_address(prj_id, address)
@error
end
def get_sign_path(id)
path = get_project_path(id)
File.join(path, PROJECTS_STRUCTURE[:SIGNED])
end
end