Initial commit

master
alexey 2 months ago
parent db1cc72b8c
commit 982ea3322c

@ -0,0 +1,2 @@
---
BUNDLE_PATH: "vendor/bundle"

@ -0,0 +1,34 @@
# frozen_string_literal: true
source "https://rubygems.org"
git_source(:github) { |repo_name| "https://github.com/#{repo_name}" }
# gem "rails"
gem "sinatra", "~> 4.1"
gem "shotgun", "~> 0.9.2"
gem "sqlite", "~> 1.0"
gem "inifile", "~> 3.0"
gem "carrierwave", "~> 3.1"
gem "data_mapper", "~> 1.2"
gem "json", "~> 1.8"
gem "stringio", "~> 3.1"
gem "puma", "~> 6.6"
gem "rackup", "~> 2.2"
gem "sqlite3", "~> 2.5"
gem "rugged", "~> 1.9"
gem "sequel", "~> 5.89"

@ -0,0 +1,187 @@
GEM
remote: https://rubygems.org/
specs:
activemodel (8.0.1)
activesupport (= 8.0.1)
activesupport (8.0.1)
base64
benchmark (>= 0.3)
bigdecimal
concurrent-ruby (~> 1.0, >= 1.3.1)
connection_pool (>= 2.2.5)
drb
i18n (>= 1.6, < 2)
logger (>= 1.4.2)
minitest (>= 5.1)
securerandom (>= 0.3)
tzinfo (~> 2.0, >= 2.0.5)
uri (>= 0.13.1)
addressable (2.8.7)
public_suffix (>= 2.0.2, < 7.0)
base64 (0.2.0)
bcrypt (3.1.20)
bcrypt-ruby (3.1.5)
bcrypt (>= 3.1.3)
benchmark (0.4.0)
bigdecimal (3.1.9)
carrierwave (3.1.1)
activemodel (>= 6.0.0)
activesupport (>= 6.0.0)
addressable (~> 2.6)
image_processing (~> 1.1)
marcel (~> 1.0.0)
ssrf_filter (~> 1.0)
concurrent-ruby (1.3.5)
connection_pool (2.5.0)
data_mapper (1.2.0)
dm-aggregates (~> 1.2.0)
dm-constraints (~> 1.2.0)
dm-core (~> 1.2.0)
dm-migrations (~> 1.2.0)
dm-serializer (~> 1.2.0)
dm-timestamps (~> 1.2.0)
dm-transactions (~> 1.2.0)
dm-types (~> 1.2.0)
dm-validations (~> 1.2.0)
dm-aggregates (1.2.0)
dm-core (~> 1.2.0)
dm-constraints (1.2.0)
dm-core (~> 1.2.0)
dm-core (1.2.1)
addressable (~> 2.3)
dm-migrations (1.2.0)
dm-core (~> 1.2.0)
dm-serializer (1.2.2)
dm-core (~> 1.2.0)
fastercsv (~> 1.5)
json (~> 1.6)
json_pure (~> 1.6)
multi_json (~> 1.0)
dm-timestamps (1.2.0)
dm-core (~> 1.2.0)
dm-transactions (1.2.0)
dm-core (~> 1.2.0)
dm-types (1.2.2)
bcrypt-ruby (~> 3.0)
dm-core (~> 1.2.0)
fastercsv (~> 1.5)
json (~> 1.6)
multi_json (~> 1.0)
stringex (~> 1.4)
uuidtools (~> 2.1)
dm-validations (1.2.0)
dm-core (~> 1.2.0)
drb (2.2.1)
fastercsv (1.5.5)
ffi (1.17.1)
ffi (1.17.1-aarch64-linux-gnu)
ffi (1.17.1-aarch64-linux-musl)
ffi (1.17.1-arm-linux-gnu)
ffi (1.17.1-arm-linux-musl)
ffi (1.17.1-arm64-darwin)
ffi (1.17.1-x86-linux-gnu)
ffi (1.17.1-x86-linux-musl)
ffi (1.17.1-x86_64-darwin)
ffi (1.17.1-x86_64-linux-gnu)
ffi (1.17.1-x86_64-linux-musl)
i18n (1.14.7)
concurrent-ruby (~> 1.0)
image_processing (1.14.0)
mini_magick (>= 4.9.5, < 6)
ruby-vips (>= 2.0.17, < 3)
inifile (3.0.0)
json (1.8.6)
json_pure (1.8.6)
logger (1.6.6)
marcel (1.0.4)
mini_magick (5.1.2)
benchmark
logger
mini_portile2 (2.8.8)
minitest (5.25.4)
multi_json (1.15.0)
mustermann (3.0.3)
ruby2_keywords (~> 0.0.1)
nio4r (2.7.4)
public_suffix (6.0.1)
puma (6.6.0)
nio4r (~> 2.0)
rack (3.1.10)
rack-protection (4.1.1)
base64 (>= 0.1.0)
logger (>= 1.6.0)
rack (>= 3.0.0, < 4)
rack-session (2.1.0)
base64 (>= 0.1.0)
rack (>= 3.0.0)
rackup (2.2.1)
rack (>= 3)
ruby-vips (2.2.3)
ffi (~> 1.12)
logger
ruby2_keywords (0.0.5)
rugged (1.9.0)
securerandom (0.4.1)
sequel (5.89.0)
bigdecimal
shotgun (0.9.2)
rack (>= 1.0)
sinatra (4.1.1)
logger (>= 1.6.0)
mustermann (~> 3.0)
rack (>= 3.0.0, < 4)
rack-protection (= 4.1.1)
rack-session (>= 2.0.0, < 3)
tilt (~> 2.0)
sqlite (1.0.2)
sqlite3 (2.5.0)
mini_portile2 (~> 2.8.0)
sqlite3 (2.5.0-aarch64-linux-gnu)
sqlite3 (2.5.0-aarch64-linux-musl)
sqlite3 (2.5.0-arm-linux-gnu)
sqlite3 (2.5.0-arm-linux-musl)
sqlite3 (2.5.0-arm64-darwin)
sqlite3 (2.5.0-x86-linux-gnu)
sqlite3 (2.5.0-x86-linux-musl)
sqlite3 (2.5.0-x86_64-darwin)
sqlite3 (2.5.0-x86_64-linux-gnu)
sqlite3 (2.5.0-x86_64-linux-musl)
ssrf_filter (1.2.0)
stringex (1.5.1)
stringio (3.1.3)
tilt (2.6.0)
tzinfo (2.0.6)
concurrent-ruby (~> 1.0)
uri (1.0.2)
uuidtools (2.2.0)
PLATFORMS
aarch64-linux-gnu
aarch64-linux-musl
arm-linux-gnu
arm-linux-musl
arm64-darwin
ruby
x86-linux-gnu
x86-linux-musl
x86_64-darwin
x86_64-linux-gnu
x86_64-linux-musl
DEPENDENCIES
carrierwave (~> 3.1)
data_mapper (~> 1.2)
inifile (~> 3.0)
json (~> 1.8)
puma (~> 6.6)
rackup (~> 2.2)
rugged (~> 1.9)
sequel (~> 5.89)
shotgun (~> 0.9.2)
sinatra (~> 4.1)
sqlite (~> 1.0)
sqlite3 (~> 2.5)
stringio (~> 3.1)
BUNDLED WITH
2.6.3

@ -1,3 +1,11 @@
# mock-gui
## Запуск
Система управления сборкой rpm пакетов на базе mock+git
```
bundle exec ruby app.rb
```
## Подготовка базы данных
```
bundle exec sequel -m db/migrations sqlite://db/workbase.sqlite3
```

@ -0,0 +1,98 @@
# coding: utf-8
hestiacp_ruby_gem_version = "3.3.0"
Gem.paths = {
"GEM_HOME" => "#{__dir__}/vendor/bundle/ruby/#{hestiacp_ruby_gem_version}",
"GEM_PATH" => "#{__dir__}/vendor/bundle/ruby/#{hestiacp_ruby_gem_version}",
}
require "rubygems"
require "sinatra"
require "puma"
require_relative "classes/config"
require_relative "classes/gitinfo"
require_relative "classes/db"
def print_error_page(error_status, error_meaasge)
@page_name = "Ошибка выполнения"
@status_err = error_status
@error_msg = error_meaasge
halt erb(:page5xx)
end
def sanitize_filename(filename)
filename = filename.strip
sanitized = filename.gsub(/[^a-zA-Z0-9_]/, "_")
sanitized.gsub!(/_+/, "_")
sanitized.gsub!(/^_+|_+$/, "")
sanitized
end
cfg = IniConfig.new()
db = DBase.new()
set :port, cfg.get_port
set :public_folder, File.dirname(__FILE__) + "/public"
use Rack::Session::Pool, :expire_after => 2592000
get "/" do
@page_name = "Система сборки rpm пакетов"
erb :index
end
get "/repos/:reponame" do
@page_name = params["reponame"]
erb :gits
end
get "/repos" do
@page_name = "Список доступных git репозиториев"
repo = GitRepo.new(cfg.get_repo, db)
if repo.path.nil?
print_error_page(503, "Путь к репозиториям не существует")
else
@repo_data = repo.getrepos
erb :gits
end
end
get "/gitcreate" do
@page_name = "Создать новый пустой git репозиторий"
@error_data = session[:gitcreate_error]
session[:gitcreate_error] = nil
erb :newgit
end
post "/gitcreate" do
if request.form_data?
if params["gitname"].nil?
session[:gitcreate_error] = "Не задано имя репозитория"
else
filename = sanitize_filename(params["gitname"])
if filename != ""
repo = GitRepo.new(cfg.get_repo, db)
if repo.path.nil?
print_error_page(503, "Путь к репозиториям не существует")
else
if repo.create_git(filename, params["gitdescr"]) != 0
session[:gitcreate_error] = repo.error
else
redirect "/repos"
return
end
end
else
session[:gitcreate_error] = "Название репозитория должно содержать только символы a-z, A-Z. 0-9 и _"
end
end
end
redirect "/gitcreate"
end
not_found do
status 404
@page_name = "Кто-то потерялся"
@req_referer = request.referer
erb :page404
end

@ -0,0 +1,41 @@
require "inifile"
class IniConfig
attr :path
def initialize(in_path = "config.ini")
@path = in_path
@config = {}
parse_ini
end
def parse_ini()
return if path.nil?
return unless File.exist? path
@config = IniFile.load(path)
end
def get_port()
unless @config["server"]["port"].nil?
@config["server"]["port"].to_i
else
8080
end
end
def get_repo()
unless @config["repo"]["repo"].nil?
@config["repo"]["repo"].to_s
else
"repo"
end
end
def get_db()
unless @config["server"]["db"].nil?
@config["server"]["db"].to_s
else
"db"
end
end
end

@ -0,0 +1,27 @@
require "sequel"
cfg_internal = IniConfig.new()
Sequel.connect(cfg_internal.get_db)
class Repos < Sequel::Model(:repos)
end
class DBase
attr :error, :last_id
def creategit(project_name, description)
@error = nil
data = Repos.where(reponame: project_name)
unless data.nil?
id = Repos.insert(reponame: project_name, descr: description, public: 1)
@last_id = id
else
@error = "Данный репозиторий уже существует"
end
@error
end
def get_repo_info_by_name(repo_name)
Repos.where(reponame: repo_name)
end
end

@ -0,0 +1,80 @@
require "sqlite3"
require "rugged"
require "fileutils"
require_relative "db"
class GitRepo
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 create_git(project_name, description)
@error = nil
ret_val = 0
File.open("locks/gitcreate", "r") do |f|
f.flock(File::LOCK_EX)
fname = File.expand_path("#{project_name}.git", @path)
if File.exist?(fname)
@error = "Репозиторий с таким именем уже существует: #{project_name}"
ret_val = 1
else
Dir.mkdir(fname)
Rugged::Repository.init_at(fname, :bare)
repo = Rugged::Repository.new(fname)
created = false
if repo.bare?
@error = @db.creategit(project_name, description)
if @error.nil?
created = true
end
else
@error = "Репозиторий почему-то не пустой"
end
unless created
FileUtils.rm_rf(fname, secure: true)
end
end
end
ret_val
end
def create_git_db_only(project_name)
@error = @db.creategit(project_name, "")
@error
end
def getrepos
repos_data = []
repos_files = Dir[File.join(@path, "*.git")]
repos_files.each do |fl|
repo_name = File.basename(fl, ".git")
db_info = @db.get_repo_info_by_name(repo_name)
unless db_info.nil?
db_info = db_info.first
repos_data << { :reponame => db_info.reponame, :descr => db_info.descr, :public => db_info.public }
else
result = create_git_db_only(repo_name)
if result.nil?
db_info = @db.get_repo_info_by_name(repo_name)
db_info = db_info.first
repos_data << { :reponame => db_info.reponame, :descr => db_info.descr, :public => db_info.public }
end
end
end
repos_data
end
end

@ -0,0 +1,6 @@
[server]
port = 8081
db = "sqlite://db/workbase.sqlite3"
[repo]
repo = "repo"

@ -0,0 +1,66 @@
require "sequel"
Sequel.migration do
change do
create_table(:repos) do
primary_key :id
String :reponame, :null => false, :unique => true
String :descr, text: true
Datetime :create_at, default: Sequel.lit("CURRENT_TIMESTAMP")
Integer :public
end
create_table(:projects) do
primary_key :id
String :projname
String :descr, text: true
Datetime :create_at, default: Sequel.lit("CURRENT_TIMESTAMP")
end
create_table(:repos_projects) do
foreign_key :proj_id, :projects, :key => :id
foreign_key :repo_id, :repos, :key => :id
primary_key [:proj_id, :repo_id]
end
create_table(:recips) do
primary_key :id
String :content, text: true
String :filepath, text: true
String :desct, text: true
Datetime :create_at, default: Sequel.lit("CURRENT_TIMESTAMP")
end
create_table(:repos_recips) do
foreign_key :repo_id, :repos, :key => :id
foreign_key :recip_id, :recips, :key => :id
primary_key [:recip_id, :repo_id]
end
create_table(:rpms) do
primary_key :id
String :savepath, text: true
String :rpmname, text: true
Integer :sign
String :signpath, text: true
foreign_key :repo_id, :repos, :key => :id
end
create_table(:buildtask) do
primary_key :id
foreign_key :repo_id, :repos, :key => :id
foreign_key :proj_id, :projects, :key => :id
Datetime :create_at, default: Sequel.lit("CURRENT_TIMESTAMP")
String :signpath, text: true
String :logpath, text: true
Integer :result
String :errlogpath, text: true
end
create_table(:build_rpm) do
foreign_key :build_id, :buildtask, :key => :id
foreign_key :rpm_id, :rpms, :key => :id
primary_key [:build_id, :rpm_id]
end
end
end

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

@ -0,0 +1,57 @@
.bs-icon {
--bs-icon-size: .75rem;
display: flex;
flex-shrink: 0;
justify-content: center;
align-items: center;
font-size: var(--bs-icon-size);
width: calc(var(--bs-icon-size) * 2);
height: calc(var(--bs-icon-size) * 2);
color: var(--bs-primary);
}
.bs-icon-xs {
--bs-icon-size: 1rem;
width: calc(var(--bs-icon-size) * 1.5);
height: calc(var(--bs-icon-size) * 1.5);
}
.bs-icon-sm {
--bs-icon-size: 1rem;
}
.bs-icon-md {
--bs-icon-size: 1.5rem;
}
.bs-icon-lg {
--bs-icon-size: 2rem;
}
.bs-icon-xl {
--bs-icon-size: 2.5rem;
}
.bs-icon.bs-icon-primary {
color: var(--bs-white);
background: var(--bs-primary);
}
.bs-icon.bs-icon-primary-light {
color: var(--bs-primary);
background: rgba(var(--bs-primary-rgb), .2);
}
.bs-icon.bs-icon-semi-white {
color: var(--bs-primary);
background: rgba(255, 255, 255, .5);
}
.bs-icon.bs-icon-rounded {
border-radius: .5rem;
}
.bs-icon.bs-icon-circle {
border-radius: 50%;
}

@ -0,0 +1 @@
.bs-icon{--bs-icon-size:.75rem;display:flex;flex-shrink:0;justify-content:center;align-items:center;font-size:var(--bs-icon-size);width:calc(var(--bs-icon-size) * 2);height:calc(var(--bs-icon-size) * 2);color:var(--bs-primary)}.bs-icon-xs{--bs-icon-size:1rem;width:calc(var(--bs-icon-size) * 1.5);height:calc(var(--bs-icon-size) * 1.5)}.bs-icon-sm{--bs-icon-size:1rem}.bs-icon-md{--bs-icon-size:1.5rem}.bs-icon-lg{--bs-icon-size:2rem}.bs-icon-xl{--bs-icon-size:2.5rem}.bs-icon.bs-icon-primary{color:var(--bs-white);background:var(--bs-primary)}.bs-icon.bs-icon-primary-light{color:var(--bs-primary);background:rgba(var(--bs-primary-rgb),.2)}.bs-icon.bs-icon-semi-white{color:var(--bs-primary);background:rgba(255,255,255,.5)}.bs-icon.bs-icon-rounded{border-radius:.5rem}.bs-icon.bs-icon-circle{border-radius:50%}

@ -0,0 +1,22 @@
<div class="container">
<div style="padding-top: 45px;"></div>
</div>
<footer class="text-center bg-dark">
<div class="container text-white py-4 py-lg-5">
<ul class="list-inline">
<li class="list-inline-item me-4"><a class="link-light" href="https://brepo.ru">Документация</a></li>
<li class="list-inline-item me-4"><a class="link-light" href="https://dev.brepo.ru">Разработка</a></li>
<li class="list-inline-item"><a class="link-light" href="https://hestiadocs.brepo.ru">Партнеры</a></li>
</ul>
<ul class="list-inline">
<li class="list-inline-item me-4"><a href="https://dev.brepo.ru"><svg xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" fill="currentColor" viewBox="0 0 16 16" class="bi bi-github text-light">
<path d="M8 0C3.58 0 0 3.58 0 8c0 3.54 2.29 6.53 5.47 7.59.4.07.55-.17.55-.38 0-.19-.01-.82-.01-1.49-2.01.37-2.53-.49-2.69-.94-.09-.23-.48-.94-.82-1.13-.28-.15-.68-.52-.01-.53.63-.01 1.08.58 1.23.82.72 1.21 1.87.87 2.33.66.07-.52.28-.87.51-1.07-1.78-.2-3.64-.89-3.64-3.95 0-.87.31-1.59.82-2.15-.08-.2-.36-1.02.08-2.12 0 0 .67-.21 2.2.82.64-.18 1.32-.27 2-.27.68 0 1.36.09 2 .27 1.53-1.04 2.2-.82 2.2-.82.44 1.1.16 1.92.08 2.12.51.56.82 1.27.82 2.15 0 3.07-1.87 3.75-3.65 3.95.29.25.54.73.54 1.48 0 1.07-.01 1.93-.01 2.2 0 .21.15.46.55.38A8.012 8.012 0 0 0 16 8c0-4.42-3.58-8-8-8z"></path>
</svg></a></li>
</ul>
<p class="text-muted mb-0">Copyright © 2025 BayRepo</p>
</div>
</footer>
<script src="/assets/bootstrap/js/bootstrap.min.js"></script>
</body>
</html>

@ -0,0 +1,33 @@
<%= erb :header %>
<div class="container py-4 py-xl-5">
<div class="row mb-5">
<div class="col-md-8 col-xl-6 text-center mx-auto">
<h2>git проекты</h2>
<p class="w-lg-50">Страница управления git проектами</p>
<div>
<div class="px-3"><a href="/gitcreate"><svg xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" fill="currentColor" viewBox="0 0 16 16" class="bi bi-plus-circle text-primary" style="font-size: 29px;">
<path d="M8 15A7 7 0 1 1 8 1a7 7 0 0 1 0 14zm0 1A8 8 0 1 0 8 0a8 8 0 0 0 0 16z"></path>
<path d="M8 4a.5.5 0 0 1 .5.5v3h3a.5.5 0 0 1 0 1h-3v3a.5.5 0 0 1-1 0v-3h-3a.5.5 0 0 1 0-1h3v-3A.5.5 0 0 1 8 4z"></path>
</svg>&nbsp;Добавить репозиторий</a></div>
</div>
</div>
</div>
<div class="row row-cols-1 row-cols-md-2 row-cols-xl-3">
<% @repo_data.each do |item| %>
<div class="col">
<div class="d-flex p-3">
<div class="bs-icon-sm bs-icon-rounded bs-icon-primary d-flex flex-shrink-0 justify-content-center align-items-center d-inline-block bs-icon sm"><svg xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" fill="currentColor" viewBox="0 0 16 16" class="bi bi-git">
<path d="M15.698 7.287 8.712.302a1.03 1.03 0 0 0-1.457 0l-1.45 1.45 1.84 1.84a1.223 1.223 0 0 1 1.55 1.56l1.773 1.774a1.224 1.224 0 0 1 1.267 2.025 1.226 1.226 0 0 1-2.002-1.334L8.58 5.963v4.353a1.226 1.226 0 1 1-1.008-.036V5.887a1.226 1.226 0 0 1-.666-1.608L5.093 2.465l-4.79 4.79a1.03 1.03 0 0 0 0 1.457l6.986 6.986a1.03 1.03 0 0 0 1.457 0l6.953-6.953a1.031 1.031 0 0 0 0-1.457"></path>
</svg></div>
<div class="px-2">
<h5 class="mb-0 mt-1"><%= item[:reponame] %></h5>
</div>
<div class="px-3"><a class="px-3" href="/repos/<%= ERB::Util.url_encode(item[:reponame]) %>"><svg xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" fill="currentColor" viewBox="0 0 16 16" class="bi bi-arrow-right-short" style="font-size: 41px;">
<path fill-rule="evenodd" d="M4 8a.5.5 0 0 1 .5-.5h5.793L8.146 5.354a.5.5 0 1 1 .708-.708l3 3a.5.5 0 0 1 0 .708l-3 3a.5.5 0 0 1-.708-.708L10.293 8.5H4.5A.5.5 0 0 1 4 8z"></path>
</svg></a></div>
</div>
</div>
<% end %>
</div>
</div>
<%= erb :footer %>

@ -0,0 +1,22 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, shrink-to-fit=no">
<title><%= @page_name %></title>
<link rel="stylesheet" href="/assets/bootstrap/css/bootstrap.min.css">
<link rel="stylesheet" href="/assets/css/Footer-Dark-icons.css">
</head>
<body>
<div class="container">
<div class="row text-center">
<div class="col-md-12 align-self-center" style="background: #b6cff4;border-radius: 13px;">
<h2 class="text-center" style="color: rgb(44,85,128);"><%= @page_name %></h2>
</div>
</div>
</div>
<div class="container">
<div style="padding-top: 45px;"></div>
</div>

@ -0,0 +1,91 @@
<%= erb :header %>
<div class="container py-4 py-xl-5">
<div class="row gy-4 row-cols-2 row-cols-md-4">
<div class="col">
<div class="text-center d-flex flex-column justify-content-center align-items-center py-3">
<div class="bs-icon-xl bs-icon-circle bs-icon-primary d-flex flex-shrink-0 justify-content-center align-items-center d-inline-block mb-2 bs-icon lg"><svg xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" fill="currentColor" viewBox="0 0 16 16" class="bi bi-gear">
<path d="M8 4.754a3.246 3.246 0 1 0 0 6.492 3.246 3.246 0 0 0 0-6.492zM5.754 8a2.246 2.246 0 1 1 4.492 0 2.246 2.246 0 0 1-4.492 0z"></path>
<path d="M9.796 1.343c-.527-1.79-3.065-1.79-3.592 0l-.094.319a.873.873 0 0 1-1.255.52l-.292-.16c-1.64-.892-3.433.902-2.54 2.541l.159.292a.873.873 0 0 1-.52 1.255l-.319.094c-1.79.527-1.79 3.065 0 3.592l.319.094a.873.873 0 0 1 .52 1.255l-.16.292c-.892 1.64.901 3.434 2.541 2.54l.292-.159a.873.873 0 0 1 1.255.52l.094.319c.527 1.79 3.065 1.79 3.592 0l.094-.319a.873.873 0 0 1 1.255-.52l.292.16c1.64.893 3.434-.902 2.54-2.541l-.159-.292a.873.873 0 0 1 .52-1.255l.319-.094c1.79-.527 1.79-3.065 0-3.592l-.319-.094a.873.873 0 0 1-.52-1.255l.16-.292c.893-1.64-.902-3.433-2.541-2.54l-.292.159a.873.873 0 0 1-1.255-.52l-.094-.319zm-2.633.283c.246-.835 1.428-.835 1.674 0l.094.319a1.873 1.873 0 0 0 2.693 1.115l.291-.16c.764-.415 1.6.42 1.184 1.185l-.159.292a1.873 1.873 0 0 0 1.116 2.692l.318.094c.835.246.835 1.428 0 1.674l-.319.094a1.873 1.873 0 0 0-1.115 2.693l.16.291c.415.764-.42 1.6-1.185 1.184l-.291-.159a1.873 1.873 0 0 0-2.693 1.116l-.094.318c-.246.835-1.428.835-1.674 0l-.094-.319a1.873 1.873 0 0 0-2.692-1.115l-.292.16c-.764.415-1.6-.42-1.184-1.185l.159-.291A1.873 1.873 0 0 0 1.945 8.93l-.319-.094c-.835-.246-.835-1.428 0-1.674l.319-.094A1.873 1.873 0 0 0 3.06 4.377l-.16-.292c-.415-.764.42-1.6 1.185-1.184l.292.159a1.873 1.873 0 0 0 2.692-1.115l.094-.319z"></path>
</svg></div>
<div class="px-3">
<h2 class="fw-bold mb-0">5</h2>
<p class="mb-0">Проектов</p>
</div>
</div>
</div>
<div class="col">
<div class="text-center d-flex flex-column justify-content-center align-items-center py-3">
<div class="bs-icon-xl bs-icon-circle bs-icon-primary d-flex flex-shrink-0 justify-content-center align-items-center d-inline-block mb-2 bs-icon lg"><svg xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" fill="currentColor" viewBox="0 0 16 16" class="bi bi-box">
<path d="M8.186 1.113a.5.5 0 0 0-.372 0L1.846 3.5 8 5.961 14.154 3.5 8.186 1.113zM15 4.239l-6.5 2.6v7.922l6.5-2.6V4.24zM7.5 14.762V6.838L1 4.239v7.923l6.5 2.6zM7.443.184a1.5 1.5 0 0 1 1.114 0l7.129 2.852A.5.5 0 0 1 16 3.5v8.662a1 1 0 0 1-.629.928l-7.185 2.874a.5.5 0 0 1-.372 0L.63 13.09a1 1 0 0 1-.63-.928V3.5a.5.5 0 0 1 .314-.464L7.443.184z"></path>
</svg></div>
<div class="px-3">
<h2 class="fw-bold mb-0">218</h2>
<p class="mb-0">Пакетов</p>
</div>
</div>
</div>
<div class="col">
<div class="text-center d-flex flex-column justify-content-center align-items-center py-3">
<div class="bs-icon-xl bs-icon-circle bs-icon-primary d-flex flex-shrink-0 justify-content-center align-items-center d-inline-block mb-2 bs-icon lg"><svg xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" fill="currentColor" viewBox="0 0 16 16" class="bi bi-bar-chart">
<path d="M4 11H2v3h2v-3zm5-4H7v7h2V7zm5-5v12h-2V2h2zm-2-1a1 1 0 0 0-1 1v12a1 1 0 0 0 1 1h2a1 1 0 0 0 1-1V2a1 1 0 0 0-1-1h-2zM6 7a1 1 0 0 1 1-1h2a1 1 0 0 1 1 1v7a1 1 0 0 1-1 1H7a1 1 0 0 1-1-1V7zm-5 4a1 1 0 0 1 1-1h2a1 1 0 0 1 1 1v3a1 1 0 0 1-1 1H2a1 1 0 0 1-1-1v-3z"></path>
</svg></div>
<div class="px-3">
<h2 class="fw-bold mb-0">100</h2>
<p class="mb-0">Репозиториев</p>
</div>
</div>
</div>
<div class="col">
<div class="text-center d-flex flex-column justify-content-center align-items-center py-3">
<div class="bs-icon-xl bs-icon-circle bs-icon-primary d-flex flex-shrink-0 justify-content-center align-items-center d-inline-block mb-2 bs-icon lg"><svg xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" fill="currentColor" viewBox="0 0 16 16" class="bi bi-cart2">
<path d="M0 2.5A.5.5 0 0 1 .5 2H2a.5.5 0 0 1 .485.379L2.89 4H14.5a.5.5 0 0 1 .485.621l-1.5 6A.5.5 0 0 1 13 11H4a.5.5 0 0 1-.485-.379L1.61 3H.5a.5.5 0 0 1-.5-.5zM3.14 5l1.25 5h8.22l1.25-5H3.14zM5 13a1 1 0 1 0 0 2 1 1 0 0 0 0-2zm-2 1a2 2 0 1 1 4 0 2 2 0 0 1-4 0zm9-1a1 1 0 1 0 0 2 1 1 0 0 0 0-2zm-2 1a2 2 0 1 1 4 0 2 2 0 0 1-4 0z"></path>
</svg></div>
<div class="px-3">
<h2 class="fw-bold mb-0">2</h2>
<p class="mb-0">Рецепты</p>
</div>
</div>
</div>
</div>
</div>
<div class="container">
<div class="row">
<div class="col-md-6" style="padding: 12px;">
<div class="card" style="background: rgb(227,227,227);border-radius: 15px;">
<div class="card-body">
<h4 class="card-title">Git репозитории</h4>
<p class="card-text">Посмотреть список всех доступных репозиториев</p><a class="card-link" href="/repos">Перейти к репозиториям</a>
</div>
</div>
</div>
<div class="col-md-6" style="padding: 12px;">
<div class="card" style="background: rgb(227,227,227);border-radius: 15px;">
<div class="card-body">
<h4 class="card-title">Проекты</h4>
<p class="card-text">Проекты - это группировка git репозиториев, конфигураций сборки, а так же пакетов, собранных из git проекта</p><a class="card-link" href="/projs">Перейти к проектам</a>
</div>
</div>
</div>
</div>
</div>
<div class="container">
<div class="row">
<div class="col-md-6" style="padding: 12px;">
<div class="card" style="background: rgb(227,227,227);border-radius: 15px;">
<div class="card-body">
<h4 class="card-title">Пакеты</h4>
<p class="card-text">Список всех собранных rpm пакетов</p><a class="card-link" href="/rpms">Перейти к rpm пакетам</a>
</div>
</div>
</div>
<div class="col-md-6" style="padding: 12px;">
<div class="card" style="background: rgb(227,227,227);border-radius: 15px;">
<div class="card-body">
<h4 class="card-title">Рецепты</h4>
<p class="card-text">Список всех доступных рецептов для каждого git репозитория</p><a class="card-link" href="/recips">Перейти к рецептам</a>
</div>
</div>
</div>
</div>
</div>
<%= erb :footer %>

@ -0,0 +1,16 @@
<%= erb :header %>
<% unless @error_data.nil? %>
<div class="container">
<div class="alert alert-warning alert-dismissible fade show" role="alert"><span><%= @error_data %></span><button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Закрыть"></button></div>
</div>
<% end %>
<div class="container">
<form method="post">
<label class="form-label">Название git репозитория, без пробелов, все extra символы (не входящие в диапазон a-z,A-Z,0-9,_) будут преобразованы в подчеркивание</label>
<input class="form-control border-primary" type="text" name="gitname" id="gitname" required>
<label class="form-label">Описание репозитория</label>
<textarea class="form-control border-primary" name="gitdescr" id="gitdescr"></textarea>
<div class="text-end" style="padding-top: 45px;"><button class="btn btn-primary" type="submit">Создать</button></div>
</form>
</div>
<%= erb :footer %>

@ -0,0 +1,18 @@
<%= erb :header %>
<div class="container">
<div class="row">
<div class="col-md-4"></div>
<div class="col-md-4">
<div class="card">
<div class="card-header">
<h5 class="mb-0">404</h5>
</div>
<div class="card-body">
<p class="card-text">Страница не найдена, возможно вы ошиблись символом в строке запроса.&nbsp;</p><a href="<%= @req_referer %>">Вернуться на предыдущую страницу</a>
</div>
</div>
</div>
<div class="col-md-4"></div>
</div>
</div>
<%= erb :footer %>

@ -0,0 +1,18 @@
<%= erb :header %>
<div class="container">
<div class="row">
<div class="col-md-4"></div>
<div class="col-md-4">
<div class="card">
<div class="card-header">
<h5 class="mb-0"><%= @status_err %></h5>
</div>
<div class="card-body">
<p class="card-text"><%= @error_msg %>&nbsp;</p><a href="<%= @req_referer %>">Вернуться на предыдущую страницу</a>
</div>
</div>
</div>
<div class="col-md-4"></div>
</div>
</div>
<%= erb :footer %>
Loading…
Cancel
Save