-
Notifications
You must be signed in to change notification settings - Fork 111
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
With this we get a Distribution with a bunch of Repository in the database that you can sync. Which will create, per Distribution/Repository, a gazillion Package objects with data from primary, appdata and updateinfo. The user workflow will be as following: - As an admin I setup Distribution and it's repositories - As an admin I sync a Distribution's repositories to the database - As a user I search for Package of a Distributions in it's repositories - As a user I extend the search to packages build on OBS for this Distribution (not implemented here) Separating the Distribution "repository" search from searching through OBS will hopefully make more clear for newbies that enabling extra repos is kind of dangerous.
- Loading branch information
1 parent
64aed3f
commit ca42eff
Showing
32 changed files
with
453 additions
and
1,255 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,267 +1,5 @@ | ||
# frozen_string_literal: true | ||
|
||
require 'api_connect' | ||
require 'net/https' | ||
require 'json' | ||
|
||
class OBSError < StandardError; end | ||
|
||
class ApplicationController < ActionController::Base | ||
before_action :validate_configuration | ||
before_action :set_language | ||
before_action :set_distributions | ||
before_action :set_releases | ||
before_action :set_baseproject | ||
|
||
helper :all # include all helpers, all the time | ||
require 'rexml/document' | ||
|
||
class MissingParameterError < RuntimeError; end | ||
|
||
EXCEPTIONS_TO_IGNORE = [OBS::InvalidSearchTerm, | ||
ApiConnect::Error, | ||
ApplicationController::MissingParameterError, | ||
Timeout::Error].freeze | ||
|
||
rescue_from Exception do |exception| | ||
logger.error "Exception: #{exception.class}: #{exception.message}" | ||
@message = exception.message | ||
layout = request.xhr? ? false : 'application' | ||
logger.error exception.backtrace.join("\n") unless EXCEPTIONS_TO_IGNORE.include? exception | ||
render template: 'error', formats: [:html], layout: layout, status: 400 | ||
end | ||
|
||
def prepare_appdata | ||
@appdata = case @baseproject | ||
when 'ALL' | ||
tw = tumbleweed_appdata | ||
stable = leap_appdata(@stable_version) | ||
testing = @testing_version ? leap_appdata(@testing_version) : {} | ||
legacy = @legacy_release ? leap_appdata(@legacy_release) : {} | ||
# Overwriting entries is okay, appdata is not used for | ||
# installation when @baseproject == 'ALL' | ||
tw.merge(stable).merge(testing).merge(legacy) | ||
when 'openSUSE:Factory' | ||
tumbleweed_appdata | ||
when "openSUSE:Leap:#{@stable_version}" | ||
leap_appdata(@stable_version) | ||
when "openSUSE:Leap:#{@testing_version}" | ||
leap_appdata(@testing_version) | ||
when "openSUSE:Leap:#{@legacy_release}" | ||
leap_appdata(@legacy_release) | ||
else | ||
{ apps: [], categories: Set.new } | ||
end | ||
end | ||
|
||
# TODO: Used to alter what OBS.search_published_binary returns, extract this into OBS. | ||
def fix_package_projects | ||
# Due to Leap 15.3's release model, there is no 1:1 distribution <> | ||
# baseproject relation anymore. | ||
# official packages: | ||
# DISTRIBUTION_PROJECTS_OVERRIDE contains valid baseprojects | ||
# -> treat as if it was from the distribution's main project, but save the | ||
# link to the real project for the generation of the download page | ||
# other packages: | ||
# package.repo uses the distribution's default reponame | ||
# -> only "fix" the baseproject for grouping purposes | ||
@packages.each do |package| | ||
dist = @distributions.find do |d| | ||
projects = DISTRIBUTION_PROJECTS_OVERRIDE.fetch(d[:dist_id], nil) | ||
projects&.include?(package.project) | ||
end | ||
|
||
if dist | ||
logger.debug("Match in override hash, changing #{package.baseproject} to #{dist[:project]}") | ||
package.realproject = package.project | ||
package.baseproject = dist[:project] | ||
package.project = dist[:project] | ||
else | ||
repo = @distributions.find { |d| d[:reponame] == package.repository } | ||
if repo | ||
package.realproject = package.project | ||
package.baseproject = repo[:project] | ||
elsif package.repository == 'openSUSE_Leap_15.4' | ||
leap154 = @distributions.find { |d| d[:dist_id] == '23178' } | ||
next unless leap154 | ||
|
||
package.baseproject = leap154[:project] | ||
elsif package.repository == 'openSUSE_Leap_15.5' | ||
leap155 = @distributions.find { |d| d[:dist_id] == '23175' } | ||
next unless leap155 | ||
|
||
package.baseproject = leap155[:project] | ||
end | ||
end | ||
end | ||
end | ||
|
||
# TODO: Used to alter what OBS.search_published_binary returns, extract this into OBS. | ||
def filter_packages | ||
# remove maintenance projects, they are not meant for end users | ||
@packages.reject! { |p| p.project.include? 'openSUSE:Maintenance:' } | ||
@packages.reject! { |p| p.project == 'openSUSE:Factory:Rebuild' } | ||
@packages.reject! { |p| p.project.start_with?('openSUSE:Factory:Staging') } | ||
|
||
# only show packages | ||
@packages.reject! { |p| p.type == 'ymp' } | ||
|
||
@packages.reject! { |p| /-devel/i.match?(p.name) } unless @search_devel | ||
|
||
unless @search_lang | ||
@packages.reject! { |p| p.name.end_with?('-lang') || p.name.include?('-translations-') || p.name.include?('-l10n-') } | ||
end | ||
|
||
@packages.reject! { |p| p.name.end_with?('-buildsymbols', '-debuginfo', '-debugsource') } unless @search_debug | ||
|
||
# filter out ports for different arch | ||
if @baseproject.end_with?('ARM') | ||
@packages.select! { |p| p.project.include?('ARM') || p.repository.include?('ARM') } | ||
elsif @baseproject.end_with?('PowerPC') | ||
@packages.select! { |p| p.project.include?('PowerPC') || p.repository.include?('PowerPC') } | ||
else # x86 | ||
@packages.reject! do |p| | ||
p.repository.end_with?('_ARM', '_PowerPC', '_zSystems') || p.repository == 'ports' || | ||
p.project.include?('ARM') || p.project.include?('PowerPC') || p.project.include?('zSystems') | ||
end | ||
end | ||
end | ||
|
||
private | ||
|
||
def validate_configuration | ||
config = Rails.configuration.x | ||
layout = request.xhr? ? false : 'application' | ||
|
||
if config.api_username.blank? && config.opensuse_cookie.blank? | ||
@message = _('The authentication to the OBS API has not been configured correctly.') | ||
render template: 'error', formats: [:html], layout: layout, status: 503 | ||
end | ||
end | ||
|
||
def set_language | ||
set_gettext_locale | ||
requested_locale = FastGettext.locale | ||
# if we don't have translations for the requested locale, try | ||
# the short form without underscore | ||
unless LANGUAGES.include? requested_locale | ||
requested_locale = requested_locale.split('_').first | ||
params[:locale] = LANGUAGES.include?(requested_locale) ? requested_locale : 'en' | ||
set_gettext_locale | ||
end | ||
@lang = FastGettext.locale | ||
end | ||
|
||
def load_releases | ||
release_file_url = 'https://get.opensuse.org/api/v0/distributions.json' | ||
Rails.cache.fetch('software-o-o/releases', expires_in: 10.minutes) do | ||
JSON.parse(URI.parse(release_file_url).open.read)['Leap'].sort_by { |r| -r['upgrade-weight'] } | ||
rescue StandardError => e | ||
Rails.logger.error "Error while parsing releases entry in #{release_file_url}: #{e}" | ||
next | ||
end | ||
rescue StandardError => e | ||
Rails.logger.error "Error while parsing releases file #{release_file_url}: #{e}" | ||
raise e | ||
end | ||
|
||
def set_releases | ||
@stable_version = nil | ||
@testing_version = nil | ||
@testing_state = nil | ||
@legacy_release = nil | ||
|
||
# look for most current release | ||
versions = load_releases | ||
unless versions.blank? | ||
if versions[0]['state'] == 'Stable' | ||
@stable_version = versions[0]['version'].to_s | ||
@legacy_release = versions[1]['version'].to_s | ||
else | ||
@testing_version = versions[0]['version'].to_s | ||
@testing_state = versions[0]['state'].to_s | ||
@stable_version = versions[1]['version'].to_s | ||
@legacy_release = versions[2]['version'].to_s | ||
end | ||
end | ||
end | ||
|
||
def tumbleweed_appdata | ||
Rails.cache.fetch('appdata/tumbleweed', expires_in: 12.hours) do | ||
Appdata.new('tumbleweed').data | ||
end | ||
end | ||
|
||
def leap_appdata(version) | ||
Rails.cache.fetch("appdata/leap#{version}", expires_in: 12.hours) do | ||
Appdata.new("leap/#{version}").data | ||
end | ||
end | ||
|
||
def set_distributions | ||
@distributions = Rails.cache.fetch('distributions', expires_in: 120.minutes) do | ||
load_distributions | ||
end | ||
rescue OBSError | ||
@distributions = nil | ||
@hide_search_box = true | ||
flash[:error] = 'Connection to OBS is unavailable. Functionality of this site is limited.' | ||
end | ||
|
||
def load_distributions | ||
logger.debug 'Loading distributions' | ||
loaded_distros = [] | ||
begin | ||
response = ApiConnect.get('public/distributions') | ||
doc = REXML::Document.new response.body | ||
doc.elements.each('distributions/distribution') do |element| | ||
loaded_distros << parse_distribution(element) | ||
end | ||
loaded_distros.unshift({ name: 'ALL Distributions', project: 'ALL' }) | ||
rescue Exception => e | ||
logger.error "Error while loading distributions: #{e}" | ||
raise OBSError.new, _('OBS Backend not available') | ||
end | ||
loaded_distros | ||
end | ||
|
||
def parse_distribution(element) | ||
dist = { | ||
name: element.elements['name'].text, | ||
project: element.elements['project'].text, | ||
reponame: element.elements['reponame'].text, | ||
repository: element.elements['repository'].text, | ||
dist_id: element.attributes['id'] | ||
} | ||
logger.debug "Added Distribution: #{dist}" | ||
dist | ||
end | ||
|
||
def set_search_options | ||
@search_term = params[:q] || '' | ||
@search_devel = (cookies[:search_devel] == 'true') | ||
@search_lang = (cookies[:search_lang] == 'true') | ||
@search_debug = (cookies[:search_debug] == 'true') | ||
end | ||
|
||
def set_baseproject | ||
default_baseproject = "openSUSE:Leap:#{@stable_version}" | ||
|
||
if params[:baseproject].present? && valid_baseproject?(params[:baseproject]) | ||
@baseproject = params[:baseproject] | ||
update_baseproject_cookie(params[:baseproject]) | ||
elsif cookies[:baseproject].present? && valid_baseproject?(cookies[:baseproject]) | ||
@baseproject = cookies[:baseproject] | ||
end | ||
@baseproject = default_baseproject unless @baseproject.present? | ||
end | ||
|
||
def valid_baseproject?(project) | ||
@distributions.present? && @distributions.select { |d| d[:project] == project }.present? | ||
end | ||
|
||
def update_baseproject_cookie(project) | ||
cookies.delete :baseproject | ||
cookies.permanent[:baseproject] = project | ||
def set_distribution | ||
@distribution = Distribution.find_by!(name: params[:distribution_name] || params[:distribution]) | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
class MainController < ApplicationController | ||
before_action :set_distribution, only: :search | ||
|
||
def index; end | ||
|
||
def search | ||
@packages = @distribution.packages.where('name ILIKE ?', "%#{params[:q]}%").order("LENGTH(name) ASC").order(:weight) | ||
end | ||
end |
Oops, something went wrong.