From 30176b0a3c2a482cf55046474846aaff89bdb8dd Mon Sep 17 00:00:00 2001 From: Jan Provaznik Date: Wed, 20 Oct 2010 11:00:10 +0200 Subject: [PATCH aggregator] selection model - first shoot Rerun "rake dc:prepare_repos" after applying. Note that this not yet final version, should be applied on patcheset "rebased pending patches". --- src/app/controllers/templates_controller.rb | 38 +++++++++++-- src/app/util/repository_manager.rb | 59 ++++++++++++++++++++ .../util/repository_manager/comps_repository.rb | 58 +++++++++++++++++--- src/app/util/repository_manager/pulp_repository.rb | 25 ++++++++- src/app/views/templates/_collections.haml | 6 ++ src/app/views/templates/_managed_content.haml | 4 +- src/app/views/templates/_metagroup_packages.haml | 6 ++ src/app/views/templates/content_selection.haml | 46 +++++++++------- src/app/views/templates/new.haml | 20 ++++--- .../image_descriptor_package_metagroups.conf | 20 +++++++ 10 files changed, 237 insertions(+), 45 deletions(-) create mode 100644 src/app/views/templates/_collections.haml create mode 100644 src/app/views/templates/_metagroup_packages.haml create mode 100644 src/config/image_descriptor_package_metagroups.conf diff --git a/src/app/controllers/templates_controller.rb b/src/app/controllers/templates_controller.rb index e06bae5..d658aa7 100644 --- a/src/app/controllers/templates_controller.rb +++ b/src/app/controllers/templates_controller.rb @@ -62,6 +62,13 @@ class TemplatesController < ApplicationController params[:packages] = params[:selected_packages] new + elsif params.include?('show_metagroup') + @metagroup = params['show_metagroup'] + content_selection + + elsif not params[:package_search].blank? + content_selection + end end @@ -105,9 +112,32 @@ class TemplatesController < ApplicationController @tpl = @id.blank? ? Template.new : Template.find(@id) @tpl.attributes = params[:tpl] unless params[:tpl].nil? @packages = [] - @packages = params[:packages].collect{ |p| { :name => p } } if params[:packages] + @packages += params[:packages].collect{ |p| { :name => p } } unless params[:packages].blank? + @packages += params[:selected_packages].collect{ |p| { :name => p } } unless params[:selected_packages].blank? @groups = @repository_manager.all_groups_with_tagged_selected_packages(@packages, @tpl.platform) @embed = params[:embed] + @categories = @repository_manager.categories(params[:tpl] ? params[:tpl][:platform] : nil) + @metagroups = @repository_manager.metagroups + + if not params[:package_search].blank? + @metagroup_packages = @repository_manager.search_package(params[:package_search], params[:repository]) + elsif not @metagroup.blank? + if @metagroup == 'Collections' + # TODO: if we remember selected groups, this could be done much more simply + @collections = @repository_manager.all_groups_with_tagged_selected_packages(@packages, params[:repository]) + else + @metagroup_packages = @repository_manager.metagroup_packages(@metagroup, params[:repository]) + end + end + if request.xhr? + if @metagroup_packages + render :partial => 'metagroup_packages' and return + end + if @collections + render :partial => 'collections' and return + end + end + if @embed render :layout => false else @@ -210,10 +240,8 @@ add account on 'provider', \ @repository_manager = RepositoryManager.new @groups = @repository_manager.all_groups(params[:repository]) - if params[:packages] - @selected_packages = params[:packages] - elsif params[:selected_packages] - @selected_packages = params[:selected_packages] + if not params[:packages].blank? or not params[:selected_packages].blank? + @selected_packages = params[:packages].to_a + params[:selected_packages].to_a elsif !tpl.nil? @selected_packages = tpl.xml.packages.collect { |p| p[:name] } else diff --git a/src/app/util/repository_manager.rb b/src/app/util/repository_manager.rb index fbe7a8b..64de179 100644 --- a/src/app/util/repository_manager.rb +++ b/src/app/util/repository_manager.rb @@ -47,6 +47,61 @@ class RepositoryManager return @all_groups end + def packages(repository = nil) + end + + def categories(repository = nil) + unless @all_categories + @all_categories = {} + repositories.each do |r| + next if repository and repository != 'all' and repository != r.id + r.categories.each do |id, data| + if @all_categories[id] + @all_categories[id][:groups] += data[:groups] + else + @all_categories[id] = data + end + end + end + end + return @all_categories + end + + def packages(repository = nil) + unless @packages + @packages = [] + repositories.each do |r| + next if repository and repository != 'all' and repository != r.id + @packages += r.packages + end + end + return @packages + end + + # TODO: this is temporary solution for categorizing packages + def metagroups + unless @metagroups + @metagroups = {} + File.readlines('config/image_descriptor_package_metagroups.conf').each do |line| + group, entries_str = line.chomp.split('=') + next unless group and entries_str + @metagroups[group] = entries_str.split(',') + end + end + @metagroups + end + + def metagroup_packages(category, repository = nil) + res = [] + groups = all_groups(repository) + metagroups[category].to_a.each do |entry| + cat, group = entry.split(';') + next unless c = categories[cat] and c[:groups].include?(group) and groups[group] + res += groups[group][:packages].keys + end + res.sort.uniq + end + def all_groups_with_tagged_selected_packages(pkgs, repository = nil) groups = all_groups(repository) groups.each_value do |group| @@ -67,6 +122,10 @@ class RepositoryManager res end + def search_package(str, repository = nil) + packages.select {|p| p =~ /#{Regexp.escape(str)}/i} + end + private # returns true if all non-optional packages are selected diff --git a/src/app/util/repository_manager/comps_repository.rb b/src/app/util/repository_manager/comps_repository.rb index 80391ef..86c4da7 100644 --- a/src/app/util/repository_manager/comps_repository.rb +++ b/src/app/util/repository_manager/comps_repository.rb @@ -11,11 +11,19 @@ class CompsRepository < AbstractRepository end def groups - begin - @groups ||= Marshal.load(File.open(@cache_file, 'r')) - rescue Errno::ENOENT - raise "failed to read cached packages info, run 'rake dc:prepare_repos'" + @groups ||= load_data[:groups] + end + + def categories + @categories ||= load_data[:categories] + end + + def packages + pkgs = [] + groups.each_value do |g| + pkgs += g[:packages].keys end + pkgs.uniq end def prepare_repo @@ -25,7 +33,8 @@ class CompsRepository < AbstractRepository pkgs = group_packages(g) next if pkgs.empty? name = g.at_xpath('name').text - grps[name] = { + id = g.at_xpath('id').text + grps[id] = { :name => name, :repository_id => @id, :packages => pkgs @@ -45,18 +54,51 @@ class CompsRepository < AbstractRepository } end + categories = {} + category_nodes.each do |cat| + id = cat.at_xpath('id').text + categories[id] = { + :name => cat.at_xpath('name').text, + :groups => cat.xpath('./grouplist/groupid').map {|g| g.text} + } + end + Dir.mkdir(@cache_dir) unless File.directory?(@cache_dir) - Marshal.dump(grps, File.open(@cache_file, 'w')) + Marshal.dump({:groups => grps, + :categories => categories}, File.open(@cache_file, 'w')) end private + def load_data + unless @load_data + begin + @load_data = Marshal.load(File.open(@cache_file, 'r')) + rescue Errno::ENOENT + raise "failed to read cached packages info, run 'rake dc:prepare_repos'" + end + end + @load_data + end + + def parsed_group_xml + unless @xml + return nil unless data = group_xml + @xml = Nokogiri::XML(data) + end + @xml + end + def group_nodes - return [] unless data = group_xml - xml = Nokogiri::XML(data) + return [] unless xml = parsed_group_xml xml.xpath('/comps/group') end + def category_nodes + return [] unless xml = parsed_group_xml + xml.xpath('/comps/category') + end + def pkg_names pkgs = {} xml = Nokogiri::XML(primary_xml) diff --git a/src/app/util/repository_manager/pulp_repository.rb b/src/app/util/repository_manager/pulp_repository.rb index a0ea005..051bc47 100644 --- a/src/app/util/repository_manager/pulp_repository.rb +++ b/src/app/util/repository_manager/pulp_repository.rb @@ -30,6 +30,8 @@ class PulpRepository < AbstractRepository def initialize(conf) super @groups_url = File.join(strip_path(@baseurl), conf['packagegroups']) + @categories_url = File.join(strip_path(@baseurl), conf['packagegroupcategories']) + @packages_url = File.join(strip_path(@baseurl), conf['packages']) end def groups @@ -41,8 +43,8 @@ class PulpRepository < AbstractRepository info['mandatory_package_names'].each {|p| pkgs[p] = {:type => 'mandatory'}} next if pkgs.empty? name = info['name'] - groups[name] = { - :name => name, + groups[info['id']] = { + :name => info['name'], :description => info['description'].to_s, :repository_id => @id, :packages => pkgs, @@ -51,6 +53,25 @@ class PulpRepository < AbstractRepository return groups end + def categories + categories = {} + WrappedRestClient.get(@categories_url, HTTP_OPTS).each do |id, info| + categories[info['id']] = { + :name => info['name'], + :groups => info['packagegroupids'], + } + end + return categories + end + + def packages + packages = [] + WrappedRestClient.get(@packages_url, HTTP_OPTS).each do |info| + packages << info['name'] + end + return packages + end + private def strip_path(url) diff --git a/src/app/views/templates/_collections.haml b/src/app/views/templates/_collections.haml new file mode 100644 index 0000000..1b4604b --- /dev/null +++ b/src/app/views/templates/_collections.haml @@ -0,0 +1,6 @@ +%ul.metagrouppackages + - @collections.keys.sort.each do |id| + %li + - selected = @collections[id][:selected] ? true : false + = check_box_tag 'groups[]', id, selected, {:disabled => selected, :id => "group_#{id}"} + = label_tag "group_#{id}", @collections[id][:name] diff --git a/src/app/views/templates/_managed_content.haml b/src/app/views/templates/_managed_content.haml index 97c4046..0657ff1 100644 --- a/src/app/views/templates/_managed_content.haml +++ b/src/app/views/templates/_managed_content.haml @@ -9,10 +9,10 @@ No selected packages - else - repos = @repository_manager.repositories_hash - - @selected_packages.each do |pkg| + - @selected_packages.sort.each do |pkg| - pkg_group = @groups.keys.find {|g| @groups[g][:packages][pkg]} %fieldset.clearfix - = text_field_tag 'packages[]', pkg, :id => "selected_package_#{pkg}", :class => "alpha grid_7 packagename" + = text_field_tag 'packages[]', pkg, :id => "package_#{pkg}", :class => "alpha grid_7 packagename" .grid_2= (pkg_group and repo = repos[@groups[pkg_group][:repository_id]]) ? repo.name.to_s : ' ' .grid_5.omega %button{:type => 'button', :disabled => 'disabled'} Config diff --git a/src/app/views/templates/_metagroup_packages.haml b/src/app/views/templates/_metagroup_packages.haml new file mode 100644 index 0000000..c8fc367 --- /dev/null +++ b/src/app/views/templates/_metagroup_packages.haml @@ -0,0 +1,6 @@ +%ul.metagrouppackages + - @metagroup_packages.sort.each do |pkg| + %li + - selected = @selected_packages.to_a.include?(pkg) + = check_box_tag 'packages[]', pkg, selected, {:disabled => selected, :id => "package_#{pkg}"} + = label_tag "package_#{pkg}", pkg diff --git a/src/app/views/templates/content_selection.haml b/src/app/views/templates/content_selection.haml index c9c3568..2ec5ab1 100644 --- a/src/app/views/templates/content_selection.haml +++ b/src/app/views/templates/content_selection.haml @@ -1,3 +1,14 @@ +:javascript + $(document).ready(function() { + var $metagrouppackages = $('#metagrouppackages'); + $('input[name="show_metagroup"]').click(function(e) { + e.preventDefault(); + var data = { 'show_metagroup': e.currentTarget.value }; + var url = '#{url_for :action => 'dispatch', :id => @id}'; + $metagrouppackages.load(url, data); + }); + }); + .grid_16 %h3 Managed Content Selection @@ -8,7 +19,7 @@ %fieldset.clearfix .search.grid_4.alpha - %input{:type => "search", :placeholder => "Search for package", :disabled => "disabled"} + %input{:type => "search", :placeholder => "Search for package", :name => 'package_search'} %button.action .grid_8 %p @@ -20,26 +31,21 @@ = label_tag 'repositories[]', repo.name %a.grid_4.omega Advanced Search - %ul.softwaregroups - - groups = @groups.keys.sort - - unsorted = groups.delete('unsorted') - - groups.push('unsorted') if params[:show_unsorted] and unsorted - - groups.each do |group| - - group_sel = @groups[group][:selected] - - group_id = group.gsub(/\s/, '_') + %ul.metagroups{:class => 'actionsidebar', :style => 'float:left'} + %li + = submit_tag 'Collections', :name => 'show_metagroup', :class => 'icon' + %hr + - @metagroups.keys.sort.each do |cat| %li - = check_box_tag 'groups[]', group, group_sel, :id => "group_#{group_id}" - %label.disclosure - =group - %ul{:class => "packages group_#{group_id}"} - - pkgs = @groups[group][:packages] - - pkgs.keys.sort.each do |pkg| - - pkg_sel = pkgs[pkg][:selected] ? true : false - - pkg_id = pkg.gsub(/\s/, '_') - %li - = check_box_tag 'packages[]', pkg, pkg_sel, :id => "package_#{pkg_id}" - = label_tag "package_#{pkg_id}", pkg - = link_to "Show unsorted packages", {:action => 'dispatch', :add_software_form => true, :show_unsorted => true, 'tpl[id]' => @tpl.id}, {:id => 'switch_all_link'} unless params[:show_unsorted] + = submit_tag cat, :name => "show_metagroup", :class => 'icon' + #metagrouppackages + - if @collections + = render :partial => 'collections' + - else + - if @metagroup_packages.blank? + No group selected + - else + = render :partial => 'metagroup_packages' %fieldset.clearfix = submit_tag "Add Selected", :name => "add_selected", :class => "grid_2 alpha", :id => "do_add_software" diff --git a/src/app/views/templates/new.haml b/src/app/views/templates/new.haml index 2de44cb..6fc82ac 100644 --- a/src/app/views/templates/new.haml +++ b/src/app/views/templates/new.haml @@ -11,7 +11,7 @@ 'tpl[platform]': $("select[name='tpl[platform]']").val() || '' } var url = '#{url_for :action => 'content_selection', :embed => true, :id => @id}'; - $content_container.empty().show(); + //$content_container.empty().show(); $sel_pkg_container.empty().show().addClass('loading'); $sel_pkg_container.load(url, data, function(){ $sel_pkg_container.removeClass('loading'); @@ -19,8 +19,11 @@ $('#do_add_software').click(function(e) { e.preventDefault(); var url = '#{url_for :action => 'managed_content'}'; + var new_pkgs = $("input:checked[name='packages[]']").map(function() {return $(this).val()}).get(); + var old_pkgs = $("input:hidden[name='selected_packages[]']").map(function() {return $(this).val()}).get(); var data = { - 'selected_packages[]': $("input:checked[name='packages[]']").map(function() {return $(this).val()}).get(), + 'selected_packages[]': old_pkgs.concat(new_pkgs), + 'selected_groups[]': $("input:checked[name='groups[]']").map(function() {return $(this).val()}).get(), 'template_id' : '#{@id.nil? ? nil : @id}' }; $content_container.load(url, data, function(){ @@ -45,12 +48,13 @@ $submit.show(); }); }); - //select all packages in group - $(".softwaregroups input[type='checkbox']").click(function() { - if ($(this).attr("checked") === true) { - $(this).siblings("ul").find("input[type='checkbox']").attr("checked","checked"); - } else { - $(this).siblings("ul").find("input[type='checkbox']").removeAttr("checked"); + //search + $("input[name='package_search']").keypress(function(event) { + if (event.keyCode == '13') { + event.preventDefault(); + var data = { 'package_search': $("input[name='package_search']").val() }; + var url = '#{url_for :action => 'dispatch', :id => @id}'; + $('#metagrouppackages').load(url, data); } }); //disclosure triangles diff --git a/src/config/image_descriptor_package_metagroups.conf b/src/config/image_descriptor_package_metagroups.conf new file mode 100644 index 0000000..7218e5c --- /dev/null +++ b/src/config/image_descriptor_package_metagroups.conf @@ -0,0 +1,20 @@ +admin-tools=base-system;system-tools,base-system;admin-tools,rpmfusion_free;hardware-support +desktop-gnome=rpmfusion_free;gnome-desktop,desktops;gnome-desktop +desktop-kde=desktops;kde-desktop,rpmfusion_free;kde-desktop +desktop-xfce=desktops;xfce-desktop +desktop-other=desktops;window-managers,desktops;sugar-desktop,desktops;lxde-desktop,desktops;moblin-desktop +education=apps;education,development;electronic-lab +fonts=base-system;fonts,base-system;legacy-fonts +games=apps;games,rpmfusion_free;games,rpmfusion_nonfree;games +graphics=apps;graphics +internet=apps;text-internet,apps;graphical-internet,rpmfusion_free;internet +legacy=base-system;legacy-software-support +localization=base-system;input-methods,language-support;khmer-support,language-support;persian-support,language-support;georgian-support,language-support;malay-support,language-support;tonga-support,language-support;portuguese-support,language-support;japanese-support,language-support;hungarian-support,language-support;somali-support,language-support;punjabi-support,language-support;bhutanese-support,language-support;british-support,language-support;korean-support,language-support;lao-support,language-support;inuktitut-support,language-support;german-support,language-support;hindi-support,language-support;faeroese-support,language-support;swedish-support,language-support;tsonga-support,language-support;russian-support,language-support;serbian-support,language-support;latvian-support,language-support;samoan-support,language-support;sinhala-support,language-support;catalan-support,language-support;lithuanian-support,language-support;turkish-support,language-support;arabic-support,language-support;vietnamese-support,language-support;mongolian-support,language-support;tswana-support,language-support;irish-support,language-support;italian-support,language-support;slovak-support,language-support;slovenian-support,language-support;belarusian-support,language-support;northern-sotho-support,language-support;kannada-support,language-support;malayalam-support,language-support;swati-support,language-support;breton-support,language-support;romanian-support,language-support;greek-support,language-support;tagalog-support,language-support;zulu-support,language-support;tibetan-support,language-support;danish-support,language-support;afrikaans-support,language-support;southern-sotho-support,language-support;bosnian-support,language-support;brazilian-support,language-support;basque-support,language-support;welsh-support,language-support;thai-support,language-support;telugu-support,language-support;low-saxon-support,language-support;urdu-support,language-support;tamil-support,language-support;indonesian-support,language-support;gujarati-support,language-support;xhosa-support,language-support;chinese-support,language-support;czech-support,language-support;venda-support,language-support;bulgarian-support,language-support;albanian-support,language-support;galician-support,language-support;armenian-support,language-support;dutch-support,language-support;oriya-support,language-support;maori-support,language-support;nepali-support,language-support;icelandic-support,language-support;ukrainian-support,language-support;assamese-support,language-support;bengali-support,language-support;spanish-support,language-support;hebrew-support,language-support;estonian-support,language-support;french-support,language-support;croatian-support,language-support;filipino-support,language-support;finnish-support,language-support;norwegian-support,language-support;southern-ndebele-support,language-support;polish-support,language-support;gaelic-support,language-support;marathi-support,language-support;ethiopic-support,language-support;esperanto-support,language-support;northern-sami-support,language-support;macedonian-support,language-support;walloon-support,language-support;kashubian-support,language-support;kashmiri-support,language-support;konkani-support,language-support;tajik-support,language-support;sindhi-support,language-support;uzbek-support,language-support;burmese-support,language-support;maithili-support,language-support;kazakh-support,language-support;azerbaijani-support,language-support;fijian-support,language-support;tetum-support,language-support;upper-sorbian-support,language-support;sanskrit-support,language-support;sardinian-support,language-support;swahili-support,language-support;maltese-support,language-support;friulian-support,language-support;latin-support,language-support;interlingua-support,language-support;occitan-support,language-support;hiligaynon-support,language-support;malagasy-support,language-support;amazigh-support,language-support;manx-support,language-support;turkmen-support,language-support;kinyarwanda-support,language-support;kurdish-support,language-support;coptic-support,language-support;luxembourgish-support,language-support;frisian-support,language-support;chichewa-support +multimedia=apps;sound-and-video,rpmfusion_free;sound-and-video +office=apps;office,apps;editors +other=apps;engineering-and-scientific,rpmfusion_free;misc-libs,rpmfusion_nonfree;emulators +programming=development;haskell,development;kde-software-development,development;gnome-software-development,development;development-tools,development;eclipse,development;development-libs,development;x-software-development,development;web-development,development;legacy-software-development,development;ruby,development;java-development,development;xfce-software-development,development;fedora-packager,development;mingw32,development;ocaml;development;perl;development;books +publishing=apps;authoring-and-publishing,apps;font-design +servers=servers;clustering,servers;dns-server,servers;server-cfg,servers;news-server,servers;web-server,servers;smb-server,servers;sql-server,servers;ftp-server,servers;printing,servers;mysql,servers;mail-server,servers;network-server,servers;legacy-network-server;servers;directory-server +system=base-system;java,base-system;base-x,base-system;hardware-support,base-system;dial-up,base-system;base,rpmfusion_free;base,rpmfusion_free;system-tools,rpmfusion_nonfree;hardware-support,rpmfusion_nonfree;misc-tools,rpmfusion_nonfree;base +virtualization=base-system;virtualization -- 1.7.2.3