diff options
author | Alex Legler <alex@a3li.li> | 2016-07-20 14:37:49 +0200 |
---|---|---|
committer | Alex Legler <alex@a3li.li> | 2016-07-20 14:37:49 +0200 |
commit | b145840323316610dd5a958cad89bbb84712ca5b (patch) | |
tree | ddfd7996d65feeccf927900131482842df3253f1 /app | |
download | packages-5-b145840323316610dd5a958cad89bbb84712ca5b.tar.gz packages-5-b145840323316610dd5a958cad89bbb84712ca5b.tar.bz2 packages-5-b145840323316610dd5a958cad89bbb84712ca5b.zip |
Initial commit w/currently running code
Diffstat (limited to 'app')
112 files changed, 3539 insertions, 0 deletions
diff --git a/app/assets/images/.keep b/app/assets/images/.keep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/app/assets/images/.keep diff --git a/app/assets/javascripts/application.js b/app/assets/javascripts/application.js new file mode 100644 index 0000000..9bca50a --- /dev/null +++ b/app/assets/javascripts/application.js @@ -0,0 +1,18 @@ +// This is a manifest file that'll be compiled into application.js, which will include all the files +// listed below. +// +// Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts, +// or any plugin's vendor/assets/javascripts directory can be referenced here using a relative path. +// +// It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the +// compiled file. +// +// Read Sprockets README (https://github.com/rails/sprockets#sprockets-directives) for details +// about supported directives. +// +//= require jquery +//= require jquery_ujs +//= require turbolinks +//= require jquery.typeahead.min +//= require moment.min +//= require_directory . diff --git a/app/assets/javascripts/arches.js b/app/assets/javascripts/arches.js new file mode 100644 index 0000000..dee720f --- /dev/null +++ b/app/assets/javascripts/arches.js @@ -0,0 +1,2 @@ +// Place all the behaviors and hooks related to the matching controller here. +// All this logic will automatically be available in application.js. diff --git a/app/assets/javascripts/index/typeahead.js b/app/assets/javascripts/index/typeahead.js new file mode 100644 index 0000000..3232fe8 --- /dev/null +++ b/app/assets/javascripts/index/typeahead.js @@ -0,0 +1,26 @@ +$(function() { + $('#q').typeahead({ + order: 'asc', + dynamic: true, + delay: 500, + source: { + packages: { + display: 'name', + href: function(item) { return '/packages/' + item.category + '/' + item.name; }, + url: [{ + type: 'GET', + url: "/packages/suggest.json", + data: { + q: "{{query}}" + } + }, 'results'], + template: '<span class="kk-suggest-cat">{{category}}</span>/<span class="kk-suggest-pkg">{{name}}</span> <span class="kk-suggest-detail">{{description}}</span>' + } + }, + callback: { + onClick: function(node, a, item, event) { + window.location = item.href; + } + } + }); +}); diff --git a/app/assets/javascripts/kkuleomi.js b/app/assets/javascripts/kkuleomi.js new file mode 100644 index 0000000..3a01529 --- /dev/null +++ b/app/assets/javascripts/kkuleomi.js @@ -0,0 +1,9 @@ +$(document).on('ready page:load kkuleomi:ajax', function(event) { + $('[data-toggle="tooltip"]').tooltip(); + + $('.kk-i18n-date').each(function(idx) { + // TODO: Support different date formats + var me = $(this); + me.text(moment.unix(me.data('utcts')).local().format('ddd, D MMM YYYY HH:mm')); + }); +}); diff --git a/app/assets/javascripts/packages/show.js b/app/assets/javascripts/packages/show.js new file mode 100644 index 0000000..01f5300 --- /dev/null +++ b/app/assets/javascripts/packages/show.js @@ -0,0 +1,24 @@ +$(function() { + var atom = $('#package-title').data('atom'); + + $.ajax({ + url: '/packages/' + atom + '/changelog' + }).done(function(data) { + $('#changelog-container').html(data); + $(document).trigger('kkuleomi:ajax'); + }).fail(function() { + $('#changelog-container > li').html('<span class="fa fa-fw fa-3x fa-ban text-danger"></span><br><br>Changelog currently not available. Please check back later.'); + }); + + $('#kk-keyword-legend-btn').popover({ + content: function(btn) { + return $('#kk-keyword-legend-text').html(); + }, + html: true, + trigger: 'toggle' + }); + + $('#kk-keyword-legend-btn').click(function() { + return false; + }); +}); diff --git a/app/assets/javascripts/useflags/render-bubbles.js b/app/assets/javascripts/useflags/render-bubbles.js new file mode 100644 index 0000000..6c99e43 --- /dev/null +++ b/app/assets/javascripts/useflags/render-bubbles.js @@ -0,0 +1,70 @@ +$('#bubble-placeholder').show(); + +var width = 600; + height = 600; + +var diameter = 960, + format = d3.format(",d"), + color = d3.scale.category20c(); + +var bubble = d3.layout.pack() + .sort(null) + .size([width, height]) + .padding(1.5); + +var svg = d3.select("#bubble-placeholder").append("svg") + .attr("width", width) + .attr("height", height) + .attr("class", "bubble"); + +d3.json("/useflags/popular.json", function(error, root) { + if (error) throw error; + + var node = svg.selectAll(".node") + .data(bubble.nodes(classes(root)) + .filter(function(d) { return !d.children; })) + .enter().append("g") + .attr("class", "node") + .attr("transform", function(d) { return "translate(" + d.x + "," + d.y + ")"; }); + + node.append("title") + .text(function(d) { return d.className + ": " + format(d.value); }); + + node.append("circle") + .attr("r", function(d) { return d.r; }) + .attr("class", "kk-useflag-circle") + .attr("onclick", function(d) { return "location.href='/useflags/" + d.className + "';"; }) + .style("fill", function(d) { return color(d.className); }); + + node.append("text") + .attr("dy", ".3em") + .attr('class', 'kk-useflag-circle') + .attr("onclick", function(d) { return "location.href='/useflags/" + d.className + "';"; }) + .style("text-anchor", "middle") + .style("font-size", function(d) { + var len = d.className.substring(0, d.r / 3).length; + var size = d.r/3; + size *= 8 / len; + if (len == 1) { + size -= 60; + } + size += 1; + return Math.round(size)+'px'; + }) + .text(function(d) { return d.className.substring(0, d.r / 3); }); +}); + +// Returns a flattened hierarchy containing all leaf nodes under the root. +function classes(root) { + var classes = []; + + function recurse(name, node) { + if (node.children) node.children.forEach(function(child) { recurse(node.name, child); }); + else classes.push({packageName: name, className: node.name, value: node.size}); + } + + recurse(null, root); + return {children: classes}; +} + +d3.select(self.frameElement).style("height", height + "px"); diff --git a/app/assets/javascripts/useflags/typeahead.js b/app/assets/javascripts/useflags/typeahead.js new file mode 100644 index 0000000..3912380 --- /dev/null +++ b/app/assets/javascripts/useflags/typeahead.js @@ -0,0 +1,25 @@ +$(function() { + $('#q').typeahead({ + order: "asc", + dynamic: true, + source: { + use: { + display: 'name', + href: function(item) { return '/useflags/' + item.name; }, + url: [{ + type: 'GET', + url: "/useflags/suggest.json", + data: { + q: "{{query}}" + } + }, 'results'], + template: '<span>{{name}}</span> <span class="kk-suggest-detail">{{description}}</span>' + } + }, + callback: { + onClick: function(node, a, item, event) { + window.location = item.href; + } + } + }); +}); diff --git a/app/assets/stylesheets/about.scss b/app/assets/stylesheets/about.scss new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/app/assets/stylesheets/about.scss diff --git a/app/assets/stylesheets/application.css b/app/assets/stylesheets/application.css new file mode 100644 index 0000000..6b38ea1 --- /dev/null +++ b/app/assets/stylesheets/application.css @@ -0,0 +1,16 @@ +/* + * This is a manifest file that'll be compiled into application.css, which will include all the files + * listed below. + * + * Any CSS and SCSS file within this directory, lib/assets/stylesheets, vendor/assets/stylesheets, + * or any plugin's vendor/assets/stylesheets directory can be referenced here using a relative path. + * + * You're free to add application-wide styles to this file and they'll appear at the bottom of the + * compiled file so the styles you add here take precedence over styles defined in any styles + * defined in the other CSS/SCSS files in this directory. It is generally better to create a new + * file per style scope. + * + *= require_tree . + *= require jquery.typeahead.min + *= require_self + */ diff --git a/app/assets/stylesheets/arches.scss b/app/assets/stylesheets/arches.scss new file mode 100644 index 0000000..f0daf89 --- /dev/null +++ b/app/assets/stylesheets/arches.scss @@ -0,0 +1,3 @@ +// Place all the styles related to the Arches controller here. +// They will automatically be included in application.css. +// You can use Sass (SCSS) here: http://sass-lang.com/ diff --git a/app/assets/stylesheets/categories.scss b/app/assets/stylesheets/categories.scss new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/app/assets/stylesheets/categories.scss @@ -0,0 +1 @@ + diff --git a/app/assets/stylesheets/index.scss b/app/assets/stylesheets/index.scss new file mode 100644 index 0000000..00db929 --- /dev/null +++ b/app/assets/stylesheets/index.scss @@ -0,0 +1,9 @@ +.site-welcome { + font-size: 2.5em; + text-align: center; + margin-bottom: 1em; + + @media screen and (max-width: 767px) { + font-size: 1.75em; + } +} diff --git a/app/assets/stylesheets/keywords.scss b/app/assets/stylesheets/keywords.scss new file mode 100644 index 0000000..e860d2f --- /dev/null +++ b/app/assets/stylesheets/keywords.scss @@ -0,0 +1,24 @@ +.kk-keyword-stable { + background-color: #81C784; + color: #2E7D32; +} + +.kk-keyword-testing { + background-color: #FFF176; + color: #a08700; +} + +.kk-keyword-unavailable { + background-color: #d5d5d5; + color: #666; +} + +.kk-keyword-masked { + background-color: #EF9A9A; + color: #B71C1C; +} + +.kk-keyword-unknown { + background-color: #fafafa; + color: #333; +} diff --git a/app/assets/stylesheets/misc.scss b/app/assets/stylesheets/misc.scss new file mode 100644 index 0000000..f3c557d --- /dev/null +++ b/app/assets/stylesheets/misc.scss @@ -0,0 +1,158 @@ +h1 { + a.kk-feed-icon { + font-size: 65%; + } +} + +.label { + cursor: default; +} + +.kk-cell-sep-right { + border-right-width: 3px !important; +} + +.panel { + table.table { + tr { + th:first-child, + td:first-child { + padding-left: 1em; + } + } + } +} + +.black { + color: #333; +} + +td .alert { + margin-bottom: 0; +} + +.kk-nobreak-cell { + white-space: nowrap; +} + +.kk-panel-content-sorry { + background-color: #f0f0f0; + text-align: center; + padding-top: 2em; + padding-bottom: 2em; + color: #666; +} + +.kk-3col-list { + columns: 3; + -webkit-columns: 3; + -moz-columns: 3; +} + +.kk-4col-list { + columns: 4; + -webkit-columns: 4; + -moz-columns: 4; +} + +.kk-5col-list { + columns: 5; + -webkit-columns: 5; + -moz-columns: 5; +} + +.kk-6col-list { + columns: 6; + -webkit-columns: 6; + -moz-columns: 6; +} + +.kk-col-list { + @media screen and (max-width: 767px) { + columns: 1; + -webkit-columns: 1; + -moz-columns: 1; + } + + padding: 0; + + li { + list-style-type: none; + + a:link, + a:hover, + a:active, + a:visited { + display: block; + padding: .2em; + } + + a:hover { + background-color: #eee; + border-radius: 2px; + text-decoration: none; + } + } +} + +.kk-col-list-header { + margin-top: 1em; + + .kk-group-header { + display: block; + border-bottom: 1px solid #eee; + } +} + +.kk-col-list .kk-col-list-header:first-of-type { + margin-top: 0; +} + +.kk-group-header { + color: #8a8a8a; + letter-spacing: 1px; + text-transform: uppercase; + font-size: 90%; +} + +.kk-suggest-cat { + color: #8a8a8a; +} + +.kk-suggest-pkg { +} + +.kk-suggest-detail { + float: right; + color: #8a8a8a; + font-size: 90%; + + @media screen and (max-width: 767px) { + display: block; + float: none; + overflow: hidden; + text-overflow: ellipsis; + } +} + +body.kk .typeahead-list > li > a { + // Firefox workaround again + white-space: normal; +} + +.kk-site-notice { + font-size: 90%; + padding-top: .5em; + padding-bottom: .5em; + text-align: center; +} + +a.kk-box-meta-link:link, +a.kk-box-meta-link:active, +a.kk-box-meta-link:visited { + color: #aaa; +} + +a.kk-box-meta-link:hover { + color: #555; +} diff --git a/app/assets/stylesheets/packages.scss b/app/assets/stylesheets/packages.scss new file mode 100644 index 0000000..1c2811a --- /dev/null +++ b/app/assets/stylesheets/packages.scss @@ -0,0 +1,232 @@ +.kk-keyword-header { + width: 5em; + font-size: 85%; + white-space: normal !important; +} + +@media screen and (max-width: 767px) { + .kk-keyword-header { + min-width: 5em; + max-width: 5em; + } +} + +.kk-version { + // Only set on small screens due to: + // https://bugzilla.mozilla.org/show_bug.cgi?id=488725 + @media screen and (max-width: 767px) { + white-space: nowrap; + } +} + +.kk-slot { + color: #888; +} + +.kk-keyword { + text-align: center; + white-space: normal !important; +} + +.kk-search-result-header { + margin-top: 0; +} + +.kk-metadata-key { + font-weight: bold; +} + +.kk-package-title .kk-package-icon { + float: left; +} + +.kk-package-title .kk-package-name { + margin-left: 1.3em; + word-wrap: break-word; +} + +.kk-package-title .kk-package-cat { + padding-left: 2.05em; +} + +.kk-package-maindesc { + margin-top: 1.75em; +} + +.kk-package-homepage { + margin: 0; + font-size: 125%; +} + +.kk-byline { + padding-left: 1em; + font-style: italic; +} + +.kk-commit { + font-family: monospace; +} + +.kk-changelog-diffstat { + margin-top: 1em; + margin-bottom: 0; + border: 1px solid #ddd; + border-top: none; +} + +.kk-changelog-diffstat { + a:link, a:visited, a:active { + color: #333; + } +} + +.kk-changelog-diffstat-icon { + width: 20px; +} + +.kk-octicon-spacer { + padding-left: 18px; +} + +.kk-useflag a:link, +.kk-useflag a:visited { + padding: 0.2em; + padding-top: 0.1em; + padding-bottom: 0.1em; + background-color: #f0f0f0; + border: 1px solid #eaeaea; + border-radius: 2px; + color: #333; + font-family: monospace; + font-size: 90%; +} + +.kk-useflag a:hover { + background-color: #e9e9e9; + color: #305d8c; +} + +.kk-useflag a:hover { + text-decoration: none; +} + +.kk-useflag { + list-style-type: none; + margin-bottom: 0.4em; + margin-right: 0.2em; +} + +.kk-useflag-container { + padding: 0; + margin-top: .4em; + + display: flex; + flex-wrap: wrap; +} + +.kk-useflag-container-many { + justify-content: space-between; +} + +.kk-useflag-container-few { + justify-content: flex-start; +} + +.kk-useflag-group { + color: #8a8a8a; + letter-spacing: 1px; + text-transform: uppercase; + font-size: 90%; +} + +.kk-versions-table { + .kk-restrict-label, + .kk-properties-label { + float: right; + + @media screen and (max-width: 767px) { + float: none; + } + } +} + +.kk-version-card > p:last-of-type { + margin-bottom: 0; +} + +@media screen and (max-width: 767px) { + .kk-version-card > p:first-of-type { + margin-top: .5em; + } +} + +.kk-mask { + background-color: #f2dede; +} + +.kk-mask-details { + font-size: 90%; + + .row { + margin-bottom: 1em; + } + + margin-top: 1em; + margin-bottom: -1em; +} + +.kk-mask-reason { + a:link, + a:visited { + color: inherit; + text-decoration: underline; + } +} + +.kk-mask-atoms { + max-height: 3.6em; + overflow-x: scroll; + line-height: 1.2em; +} + +.popover .kk-keyword-legend { + margin-top: 10px; + margin-bottom: 10px; + width: 240px; +} + +.kk-package-detailed { + h4 { + margin-bottom: 5px; + } +} + +.kk-package-detailed-toolbox { + float:right; + margin-top: -1.75em; +} + +.kk-inline-changelog-entry { + font-size: 90%; + border-radius: 2px; + border: 1px solid #ddd; + background-color: #f5f5f5; + margin-top: 5px; + + a:link, + a:active, + a:visited, + a:hover { + display: block; + padding: 5px; + color: #333; + } + + .kk-commit-message { + margin-left: .5em; + } + + .kk-commit { + color: #999; + } +} diff --git a/app/assets/stylesheets/sprockets-octicons.scss b/app/assets/stylesheets/sprockets-octicons.scss new file mode 100755 index 0000000..cef21ae --- /dev/null +++ b/app/assets/stylesheets/sprockets-octicons.scss @@ -0,0 +1,217 @@ +@font-face { + font-family: 'octicons'; + src: font-url('octicons.eot?#iefix') format('embedded-opentype'), + font-url('octicons.woff') format('woff'), + font-url('octicons.ttf') format('truetype'), + font-url('octicons.svg#octicons') format('svg'); + font-weight: normal; + font-style: normal; +} + +// .octicon is optimized for 16px. +// .mega-octicon is optimized for 32px but can be used larger. +.octicon, .mega-octicon { + font: normal normal normal 16px/1 octicons; + display: inline-block; + text-decoration: none; + text-rendering: auto; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; +} +.mega-octicon { font-size: 32px; } + +.octicon-alert:before { content: '\f02d'} /* */ +.octicon-arrow-down:before { content: '\f03f'} /* */ +.octicon-arrow-left:before { content: '\f040'} /* */ +.octicon-arrow-right:before { content: '\f03e'} /* */ +.octicon-arrow-small-down:before { content: '\f0a0'} /* */ +.octicon-arrow-small-left:before { content: '\f0a1'} /* */ +.octicon-arrow-small-right:before { content: '\f071'} /* */ +.octicon-arrow-small-up:before { content: '\f09f'} /* */ +.octicon-arrow-up:before { content: '\f03d'} /* */ +.octicon-microscope:before, +.octicon-beaker:before { content: '\f0dd'} /* */ +.octicon-bell:before { content: '\f0de'} /* */ +.octicon-book:before { content: '\f007'} /* */ +.octicon-bookmark:before { content: '\f07b'} /* */ +.octicon-briefcase:before { content: '\f0d3'} /* */ +.octicon-broadcast:before { content: '\f048'} /* */ +.octicon-browser:before { content: '\f0c5'} /* */ +.octicon-bug:before { content: '\f091'} /* */ +.octicon-calendar:before { content: '\f068'} /* */ +.octicon-check:before { content: '\f03a'} /* */ +.octicon-checklist:before { content: '\f076'} /* */ +.octicon-chevron-down:before { content: '\f0a3'} /* */ +.octicon-chevron-left:before { content: '\f0a4'} /* */ +.octicon-chevron-right:before { content: '\f078'} /* */ +.octicon-chevron-up:before { content: '\f0a2'} /* */ +.octicon-circle-slash:before { content: '\f084'} /* */ +.octicon-circuit-board:before { content: '\f0d6'} /* */ +.octicon-clippy:before { content: '\f035'} /* */ +.octicon-clock:before { content: '\f046'} /* */ +.octicon-cloud-download:before { content: '\f00b'} /* */ +.octicon-cloud-upload:before { content: '\f00c'} /* */ +.octicon-code:before { content: '\f05f'} /* */ +.octicon-color-mode:before { content: '\f065'} /* */ +.octicon-comment-add:before, +.octicon-comment:before { content: '\f02b'} /* */ +.octicon-comment-discussion:before { content: '\f04f'} /* */ +.octicon-credit-card:before { content: '\f045'} /* */ +.octicon-dash:before { content: '\f0ca'} /* */ +.octicon-dashboard:before { content: '\f07d'} /* */ +.octicon-database:before { content: '\f096'} /* */ +.octicon-clone:before, +.octicon-desktop-download:before { content: '\f0dc'} /* */ +.octicon-device-camera:before { content: '\f056'} /* */ +.octicon-device-camera-video:before { content: '\f057'} /* */ +.octicon-device-desktop:before { content: '\f27c'} /* */ +.octicon-device-mobile:before { content: '\f038'} /* */ +.octicon-diff:before { content: '\f04d'} /* */ +.octicon-diff-added:before { content: '\f06b'} /* */ +.octicon-diff-ignored:before { content: '\f099'} /* */ +.octicon-diff-modified:before { content: '\f06d'} /* */ +.octicon-diff-removed:before { content: '\f06c'} /* */ +.octicon-diff-renamed:before { content: '\f06e'} /* */ +.octicon-ellipsis:before { content: '\f09a'} /* */ +.octicon-eye-unwatch:before, +.octicon-eye-watch:before, +.octicon-eye:before { content: '\f04e'} /* */ +.octicon-file-binary:before { content: '\f094'} /* */ +.octicon-file-code:before { content: '\f010'} /* */ +.octicon-file-directory:before { content: '\f016'} /* */ +.octicon-file-media:before { content: '\f012'} /* */ +.octicon-file-pdf:before { content: '\f014'} /* */ +.octicon-file-submodule:before { content: '\f017'} /* */ +.octicon-file-symlink-directory:before { content: '\f0b1'} /* */ +.octicon-file-symlink-file:before { content: '\f0b0'} /* */ +.octicon-file-text:before { content: '\f011'} /* */ +.octicon-file-zip:before { content: '\f013'} /* */ +.octicon-flame:before { content: '\f0d2'} /* */ +.octicon-fold:before { content: '\f0cc'} /* */ +.octicon-gear:before { content: '\f02f'} /* */ +.octicon-gift:before { content: '\f042'} /* */ +.octicon-gist:before { content: '\f00e'} /* */ +.octicon-gist-secret:before { content: '\f08c'} /* */ +.octicon-git-branch-create:before, +.octicon-git-branch-delete:before, +.octicon-git-branch:before { content: '\f020'} /* */ +.octicon-git-commit:before { content: '\f01f'} /* */ +.octicon-git-compare:before { content: '\f0ac'} /* */ +.octicon-git-merge:before { content: '\f023'} /* */ +.octicon-git-pull-request-abandoned:before, +.octicon-git-pull-request:before { content: '\f009'} /* */ +.octicon-globe:before { content: '\f0b6'} /* */ +.octicon-graph:before { content: '\f043'} /* */ +.octicon-heart:before { content: '\2665'} /* ♥ */ +.octicon-history:before { content: '\f07e'} /* */ +.octicon-home:before { content: '\f08d'} /* */ +.octicon-horizontal-rule:before { content: '\f070'} /* */ +.octicon-hubot:before { content: '\f09d'} /* */ +.octicon-inbox:before { content: '\f0cf'} /* */ +.octicon-info:before { content: '\f059'} /* */ +.octicon-issue-closed:before { content: '\f028'} /* */ +.octicon-issue-opened:before { content: '\f026'} /* */ +.octicon-issue-reopened:before { content: '\f027'} /* */ +.octicon-jersey:before { content: '\f019'} /* */ +.octicon-key:before { content: '\f049'} /* */ +.octicon-keyboard:before { content: '\f00d'} /* */ +.octicon-law:before { content: '\f0d8'} /* */ +.octicon-light-bulb:before { content: '\f000'} /* */ +.octicon-link:before { content: '\f05c'} /* */ +.octicon-link-external:before { content: '\f07f'} /* */ +.octicon-list-ordered:before { content: '\f062'} /* */ +.octicon-list-unordered:before { content: '\f061'} /* */ +.octicon-location:before { content: '\f060'} /* */ +.octicon-gist-private:before, +.octicon-mirror-private:before, +.octicon-git-fork-private:before, +.octicon-lock:before { content: '\f06a'} /* */ +.octicon-logo-github:before { content: '\f092'} /* */ +.octicon-mail:before { content: '\f03b'} /* */ +.octicon-mail-read:before { content: '\f03c'} /* */ +.octicon-mail-reply:before { content: '\f051'} /* */ +.octicon-mark-github:before { content: '\f00a'} /* */ +.octicon-markdown:before { content: '\f0c9'} /* */ +.octicon-megaphone:before { content: '\f077'} /* */ +.octicon-mention:before { content: '\f0be'} /* */ +.octicon-milestone:before { content: '\f075'} /* */ +.octicon-mirror-public:before, +.octicon-mirror:before { content: '\f024'} /* */ +.octicon-mortar-board:before { content: '\f0d7'} /* */ +.octicon-mute:before { content: '\f080'} /* */ +.octicon-no-newline:before { content: '\f09c'} /* */ +.octicon-octoface:before { content: '\f008'} /* */ +.octicon-organization:before { content: '\f037'} /* */ +.octicon-package:before { content: '\f0c4'} /* */ +.octicon-paintcan:before { content: '\f0d1'} /* */ +.octicon-pencil:before { content: '\f058'} /* */ +.octicon-person-add:before, +.octicon-person-follow:before, +.octicon-person:before { content: '\f018'} /* */ +.octicon-pin:before { content: '\f041'} /* */ +.octicon-plug:before { content: '\f0d4'} /* */ +.octicon-repo-create:before, +.octicon-gist-new:before, +.octicon-file-directory-create:before, +.octicon-file-add:before, +.octicon-plus:before { content: '\f05d'} /* */ +.octicon-primitive-dot:before { content: '\f052'} /* */ +.octicon-primitive-square:before { content: '\f053'} /* */ +.octicon-pulse:before { content: '\f085'} /* */ +.octicon-question:before { content: '\f02c'} /* */ +.octicon-quote:before { content: '\f063'} /* */ +.octicon-radio-tower:before { content: '\f030'} /* */ +.octicon-repo-delete:before, +.octicon-repo:before { content: '\f001'} /* */ +.octicon-repo-clone:before { content: '\f04c'} /* */ +.octicon-repo-force-push:before { content: '\f04a'} /* */ +.octicon-gist-fork:before, +.octicon-repo-forked:before { content: '\f002'} /* */ +.octicon-repo-pull:before { content: '\f006'} /* */ +.octicon-repo-push:before { content: '\f005'} /* */ +.octicon-rocket:before { content: '\f033'} /* */ +.octicon-rss:before { content: '\f034'} /* */ +.octicon-ruby:before { content: '\f047'} /* */ +.octicon-screen-full:before { content: '\f066'} /* */ +.octicon-screen-normal:before { content: '\f067'} /* */ +.octicon-search-save:before, +.octicon-search:before { content: '\f02e'} /* */ +.octicon-server:before { content: '\f097'} /* */ +.octicon-settings:before { content: '\f07c'} /* */ +.octicon-shield:before { content: '\f0e1'} /* */ +.octicon-log-in:before, +.octicon-sign-in:before { content: '\f036'} /* */ +.octicon-log-out:before, +.octicon-sign-out:before { content: '\f032'} /* */ +.octicon-squirrel:before { content: '\f0b2'} /* */ +.octicon-star-add:before, +.octicon-star-delete:before, +.octicon-star:before { content: '\f02a'} /* */ +.octicon-stop:before { content: '\f08f'} /* */ +.octicon-repo-sync:before, +.octicon-sync:before { content: '\f087'} /* */ +.octicon-tag-remove:before, +.octicon-tag-add:before, +.octicon-tag:before { content: '\f015'} /* */ +.octicon-telescope:before { content: '\f088'} /* */ +.octicon-terminal:before { content: '\f0c8'} /* */ +.octicon-three-bars:before { content: '\f05e'} /* */ +.octicon-thumbsdown:before { content: '\f0db'} /* */ +.octicon-thumbsup:before { content: '\f0da'} /* */ +.octicon-tools:before { content: '\f031'} /* */ +.octicon-trashcan:before { content: '\f0d0'} /* */ +.octicon-triangle-down:before { content: '\f05b'} /* */ +.octicon-triangle-left:before { content: '\f044'} /* */ +.octicon-triangle-right:before { content: '\f05a'} /* */ +.octicon-triangle-up:before { content: '\f0aa'} /* */ +.octicon-unfold:before { content: '\f039'} /* */ +.octicon-unmute:before { content: '\f0ba'} /* */ +.octicon-versions:before { content: '\f064'} /* */ +.octicon-watch:before { content: '\f0e0'} /* */ +.octicon-remove-close:before, +.octicon-x:before { content: '\f081'} /* */ +.octicon-zap:before { content: '\26A1'} /* ⚡ */ diff --git a/app/assets/stylesheets/useflags.scss b/app/assets/stylesheets/useflags.scss new file mode 100644 index 0000000..90f667d --- /dev/null +++ b/app/assets/stylesheets/useflags.scss @@ -0,0 +1,20 @@ +.kk-useflag-circle { + cursor: pointer; +} + +.kk-useflag-bubble-container { + text-align: center; + overflow: scroll; +} + +.kk-useflag-listing { + a:link, + a:visited { + color: #333; + } +} + +form.useflag-search { + margin-top: 2.5em; + margin-bottom: 1em; +} diff --git a/app/controllers/about_controller.rb b/app/controllers/about_controller.rb new file mode 100644 index 0000000..e41c3b5 --- /dev/null +++ b/app/controllers/about_controller.rb @@ -0,0 +1,27 @@ +class AboutController < ApplicationController + before_action :set_nav + + def feedback + if params.key? :feedback + FeedbackMailer.feedback_email(params[:feedback], params[:contact]).deliver_now + render text: 'Thank you for your feedback!', layout: 'application' + end + end + + def index + end + + def feeds + end + + def legacy + @feed_type = 'legacy' + @feed_title = 'packages.gentoo.org Legacy Feed' + end + + private + + def set_nav + @nav = :about + end +end diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb new file mode 100644 index 0000000..9e8e1ca --- /dev/null +++ b/app/controllers/application_controller.rb @@ -0,0 +1,13 @@ +class ApplicationController < ActionController::Base + before_action :set_locale, :set_caching + + def set_locale + I18n.locale = params[:hl] || I18n.default_locale + rescue + I18n.default_locale + end + + def set_caching + expires_in 10.minutes, public: true + end +end diff --git a/app/controllers/arches_controller.rb b/app/controllers/arches_controller.rb new file mode 100644 index 0000000..cbbcb65 --- /dev/null +++ b/app/controllers/arches_controller.rb @@ -0,0 +1,63 @@ +class ArchesController < ApplicationController + before_action :set_nav + before_action :set_arch, only: [:show, :added, :updated, :stable, :keyworded] + + def index + end + + def show + end + + def stable + @changes = stabled_packages @arch + render_changes_feed :stable, t(:feed_stable_arch, arch: @arch) + end + + def keyworded + @changes = keyworded_packages @arch + render_changes_feed :keyworded, t(:feed_keyworded, arch: @arch) + end + + private + + def set_nav + @nav = :arches + end + + def set_arch + fail ActionController::RoutingError, 'No such architecture' unless ::KKULEOMI_ARCHES.include? params[:id] + @arch = params[:id] + @feed_id = @arch + end + + def render_changes_feed(type, title) + respond_to do |wants| + wants.html {} + wants.atom do + @feed_type = type + @feed_title = title + render template: 'feeds/changes' + end + end + end + + def keyworded_packages(arch) + Rails.cache.fetch("keyworded_packages/#{arch}", expires_in: 10.minutes) do + Change.filter_all({ change_type: 'keyword', arches: arch }, + size: 50, + sort: { created_at: { order: 'desc' } }).map do |change| + change.to_os(:change_type, :package, :category, :version, :arches, :created_at) + end + end + end + + def stabled_packages(arch) + Rails.cache.fetch("stabled_packages/#{arch}", expires_in: 10.minutes) do + Change.filter_all({ change_type: 'stable', arches: arch }, + size: 50, + sort: { created_at: { order: 'desc' } }).map do |change| + change.to_os(:change_type, :package, :category, :version, :arches, :created_at) + end + end + end +end diff --git a/app/controllers/categories_controller.rb b/app/controllers/categories_controller.rb new file mode 100644 index 0000000..e144df7 --- /dev/null +++ b/app/controllers/categories_controller.rb @@ -0,0 +1,39 @@ +class CategoriesController < ApplicationController + before_action :set_category, only: [:show, :search] + before_action :set_nav + + def index + @categories = Category.all_sorted_by(:name, :asc) + end + + def show + @packages = Rails.cache.fetch("category/#{@category.name}/packages", + expires_in: 10.minutes) do + Package.find_all_by(:category, + @category.name, + sort: { name_sort: { order: 'asc' } }).map do |pkg| + pkg.to_os(:name, :atom, :description) + end + end + + @description = t(:desc_categories_show, + category: @category.name, + description: @category.description) + end + + def search + end + + private + + def set_category + @category = Category.find_by(:name, params[:id]) + fail ActionController::RoutingError, 'No such category' unless @category + + @title = @category.name + end + + def set_nav + @nav = :packages + end +end diff --git a/app/controllers/concerns/.keep b/app/controllers/concerns/.keep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/app/controllers/concerns/.keep diff --git a/app/controllers/concerns/package_update_feeds.rb b/app/controllers/concerns/package_update_feeds.rb new file mode 100644 index 0000000..2d20672 --- /dev/null +++ b/app/controllers/concerns/package_update_feeds.rb @@ -0,0 +1,35 @@ +module PackageUpdateFeeds + extend ActiveSupport::Concern + + def new_packages + Rails.cache.fetch('new_packages', expires_in: 10.minutes) do + Change.find_all_by(:change_type, 'new_package', { size: 50, sort: { created_at: { order: 'desc' } } }).map do |change| + change.to_os(:change_type, :package, :category, :created_at) + end + end + end + + def version_bumps + Rails.cache.fetch('version_bumps', expires_in: 10.minutes) do + Change.find_all_by(:change_type, 'version_bump', { size: 50, sort: { created_at: { order: 'desc' } } }).map do |change| + change.to_os(:change_type, :package, :category, :version, :created_at) + end + end + end + + def keyworded_packages + Rails.cache.fetch('keyworded_packages', expires_in: 10.minutes) do + Change.find_all_by(:change_type, 'keyword', { size: 50, sort: { created_at: { order: 'desc' } } }).map do |change| + change.to_os(:change_type, :package, :category, :version, :arches, :created_at) + end + end + end + + def stabled_packages + Rails.cache.fetch('stabled_packages', expires_in: 10.minutes) do + Change.find_all_by(:change_type, 'stable', { size: 50, sort: { created_at: { order: 'desc' } } }).map do |change| + change.to_os(:change_type, :package, :category, :version, :arches, :created_at) + end + end + end +end diff --git a/app/controllers/index_controller.rb b/app/controllers/index_controller.rb new file mode 100644 index 0000000..ba866c6 --- /dev/null +++ b/app/controllers/index_controller.rb @@ -0,0 +1,10 @@ +class IndexController < ApplicationController + include PackageUpdateFeeds + + def index + @nav = :index + + @new_packages = new_packages[0..9] + @version_bumps = version_bumps[0..9] + end +end diff --git a/app/controllers/packages_controller.rb b/app/controllers/packages_controller.rb new file mode 100644 index 0000000..ee098ae --- /dev/null +++ b/app/controllers/packages_controller.rb @@ -0,0 +1,84 @@ +class PackagesController < ApplicationController + include PackageUpdateFeeds + before_action :set_nav + + def index + redirect_to categories_path + end + + def search + @offset = params[:o].to_i || 0 + @packages = Package.default_search(params[:q], @offset) + + redirect_to package_path(@packages.first).gsub('%2F', '/') if @packages.size == 1 + end + + def suggest + @packages = Package.suggest(params[:q]) + end + + def resolve + @packages = Package.resolve(params[:atom]) + end + + def show + @package = Package.find_by(:atom, params[:id]) + fail ActionController::RoutingError, 'No such package' unless @package + + # Enable this in 2024 (when we have full-color emojis on a Linux desktop) + # @title = ' 📦 %s' % @package.atom + @title = @package.atom + @description = 'Gentoo package %s: %s' % [@package.atom, @package.description] + end + + def changelog + @package = Package.find_by(:atom, params[:id]) + fail ActionController::RoutingError, 'No such package' unless @package + + @changelog = Rails.cache.fetch("changelog/#{@package.atom}", expires_in: 10.minutes) do + Portage::Util::History.for(@package.category, @package.name, 5) + end + + respond_to do |wants| + wants.html { render layout: false } + wants.json {} + end + end + + def added + @changes = new_packages + render_changes_feed :added, t(:feed_added) + end + + def updated + @changes = version_bumps + render_changes_feed :updated, t(:feed_updated) + end + + def stable + @changes = stabled_packages + render_changes_feed :stable, t(:feed_stable) + end + + def keyworded + @changes = keyworded_packages + render_changes_feed :keyworded, t(:feed_keyworded) + end + + private + + def render_changes_feed(type, title) + respond_to do |wants| + wants.html {} + wants.atom do + @feed_type = type + @feed_title = title + render template: 'feeds/changes' + end + end + end + + def set_nav + @nav = :packages + end +end diff --git a/app/controllers/useflags_controller.rb b/app/controllers/useflags_controller.rb new file mode 100644 index 0000000..0fa74f4 --- /dev/null +++ b/app/controllers/useflags_controller.rb @@ -0,0 +1,50 @@ +class UseflagsController < ApplicationController + before_action :set_nav + + def index + @title = t :use_flags + end + + def show + @useflags = Useflag.get_flags(params[:id]) + + if @useflags.empty? || (@useflags[:use_expand].empty? && @useflags[:local].empty? && @useflags[:global].empty?) + fail ActionController::RoutingError, 'No such useflag' + end + + @packages = Package.find_atoms_by_useflag(params[:id]) + @title = '%s – %s' % [params[:id], t(:use_flags)] + + unless @useflags[:use_expand].empty? + @useflag = @useflags[:use_expand].first + @use_expand_flags = Useflag.find_all_by(:use_expand_prefix, @useflag.use_expand_prefix) + @use_expand_flag_name = @useflag.use_expand_prefix.upcase + + render template: 'useflags/show_use_expand' + return + else + render template: 'useflags/show' + end + end + + def search + # TODO: Different search? + @flags = Useflag.suggest(params[:q]) + end + + def suggest + @flags = Useflag.suggest(params[:q]) + end + + def popular + @popular_useflags = Rails.cache.fetch('popular_useflags', expires_in: 24.hours) do + Version.get_popular_useflags(100) + end + end + + private + + def set_nav + @nav = :use + end +end diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb new file mode 100644 index 0000000..619582c --- /dev/null +++ b/app/helpers/application_helper.rb @@ -0,0 +1,51 @@ +module ApplicationHelper + def cp_to_atom(category, package) + '%s/%s' % [category, package] + end + + def atom_add_version(atom, version) + '%s-%s' % [atom, version] + end + + # Generates a somewhat sensible atom ID + def atom_id(*args) + ['tag:packages.gentoo.org,2015-10-03', args].flatten.compact.join ':' + end + + def alternate_feed_link(url, description, mime = 'application/atom+xml') + tag :link, + rel: 'alternate', + href: url, + title: description, + type: mime + end + + # Renders a label displaying the first letters of the components of a string + def abbreviated_label(items, css_class, message_id) + return '' if items.nil? || items.empty? + + letters = strip_conditionals(items).map { |r| r[0].upcase }.uniq + + content_tag :span, + letters.join(', '), + class: 'label %s' % css_class, + title: t(message_id, list: items.join(' ')) + end + + def last_import_start + Rails.cache.fetch(::KK_CACHE_LAST_IMPORT) + end + + def i18n_date(date, format = '%a, %e %b %Y %H:%M') + content_tag :span, + l(date, format: format), + class: 'kk-i18n-date', + :'data-utcts' => date.strftime('%s'), + :'data-format' => format.to_s, + title: date.to_formatted_s(:rfc822) + end + + def kk_changelog + File.read('CHANGES.md') + end +end diff --git a/app/helpers/arches_helper.rb b/app/helpers/arches_helper.rb new file mode 100644 index 0000000..670d125 --- /dev/null +++ b/app/helpers/arches_helper.rb @@ -0,0 +1,2 @@ +module ArchesHelper +end diff --git a/app/helpers/keywords_helper.rb b/app/helpers/keywords_helper.rb new file mode 100644 index 0000000..2444a6b --- /dev/null +++ b/app/helpers/keywords_helper.rb @@ -0,0 +1,90 @@ +# Helper methods for dealing with package version KEYWORDS +module KeywordsHelper + # Renders an icon for a keyword status + def keyword_icon_tag(keyword) + css_class = KK_KEYWORD_ICON[keyword] + + if css_class + content_tag :span, + '', + class: ['octicon', css_class] + else + '' + end + end + + # Retrieves the CSS class for a keyword + def keyword_class(keyword) + KK_KEYWORD_CLASS[keyword] || nil + end + + # Displays a keyword icon plus text-mdoe browser fallback + def keyword_icon(keyword, arch) + capture do + concat keyword_icon_tag(keyword) + concat keyword_fallback_tag(keyword, arch) + end + end + + # Renders a keyword as a familiar string + def keyword_string(keyword, arch) + case keyword + when :stable + arch + when :testing + '~%s' % arch + when :unavailable + '-%s' % arch + when :masked + '[M]%s' % arch + else + '?%s' % arch + end + end + + def keyword_fallback_tag(keyword, arch) + content_tag :span, + keyword_string(keyword, arch), + class: 'sr-only' + end + + def verbalize_version_visibility(version, arch) + keyword = t(KK_KEYWORD_VERBALIZATION[version.keyword(arch)]) + + keyword_str = keyword + keyword_str = '%s (%s)' % [ + t(KK_KEYWORD_VERBALIZATION[:masked]), + keyword + ] if version.is_masked? + + t 'keyword_tooltip', + version: version.version, + keyword: keyword_str, + arch: arch + end + + def keyword_cell(version, arch, large_separator = false) + effective_keyword = version.effective_keyword arch + + css_class = ['kk-keyword'] + css_class << 'kk-cell-sep-right' if large_separator + css_class << keyword_class(effective_keyword) + + content_tag :td, + keyword_icon(effective_keyword, arch), + class: css_class, + title: verbalize_version_visibility(version, arch) + end + + def keyword_label(version, arch) + effective_keyword = version.effective_keyword arch + + css_class = ['label'] + css_class << keyword_class(effective_keyword) + + content_tag :span, + keyword_string(effective_keyword, arch), + class: css_class, + title: verbalize_version_visibility(version, arch) + end +end diff --git a/app/helpers/links_helper.rb b/app/helpers/links_helper.rb new file mode 100644 index 0000000..5a28fb0 --- /dev/null +++ b/app/helpers/links_helper.rb @@ -0,0 +1,56 @@ +module LinksHelper + # Slash-in-Link-Fix + # Replaces the URLencoded slash with a proper slash + def slf(input) + input.gsub('%2F', '/') + end + + def link_to_gitweb_commit(commitid) + link_to commitid[0...8], + gitweb_commit_url(commitid), + title: commitid, + class: 'kk-commit' + end + + def gitweb_commit_url(commitid) + 'https://gitweb.gentoo.org/repo/gentoo.git/commit/?id=%s' % commitid + end + + def link_to_gitweb_ebuild_diff(name, commitid, cat, pkg) + link_to name, 'https://gitweb.gentoo.org/repo/gentoo.git/diff/%s/%s/%s?id=%s' % [cat, pkg, name, commitid] + end + + def link_to_license_text(license) + link_to license, 'https://gitweb.gentoo.org/repo/gentoo.git/plain/licenses/%s' % license + end + + def link_to_category(category) + link_to category.name, + category_path(category), + title: category.description, + 'data-toggle' => 'tooltip', + 'data-placement' => 'right' + end + + def link_to_package(atom) + link_to atom, slf(package_path(atom)) + end + + def link_to_herd(herd) + link_to herd, 'https://www.gentoo.org/inside-gentoo/developers/herds.html#%s' % herd + end + + def link_to_bug(str, bugid) + link_to str, 'https://bugs.gentoo.org/show_bug.cgi?id=%s' % bugid + end + + def absolute_link_to_package(atom) + slf package_url(atom) + end + + def feed_icon(url) + content_tag :a, + content_tag(:span, '', class: 'fa fa-fw fa-rss-square'), + title: t(:atom_feed), href: url, class: 'kk-feed-icon' + end +end diff --git a/app/helpers/packages_helper.rb b/app/helpers/packages_helper.rb new file mode 100644 index 0000000..ed90f5d --- /dev/null +++ b/app/helpers/packages_helper.rb @@ -0,0 +1,81 @@ +# Helpers for displaying package models +module PackagesHelper + def restrict_label(version) + abbreviated_label version.restrict, + 'label-danger kk-restrict-label', + :restrict_tooltip + end + + def properties_label(version) + abbreviated_label version.properties, + 'label-info kk-properties-label', + :properties_tooltip + end + + def version_labels(version) + capture do + concat restrict_label(version) + concat properties_label(version) + end + end + + def annotate_license_str(str) + str.split(/\s/).map do |license| + if license[0] =~ /[[:alpha:]]/ && !license.end_with?('?') + link_to_license_text license + else + h license + end + end.join(' ').html_safe + end + + def annotate_bugs(str) + annotated_str = str.gsub(/([bB]ug\s+|[bB]ug\s+#|#)(\d+)/) do + link_to_bug("#{$1}#{$2}", $2) + end + + sanitize(annotated_str, tags: ['a'], attributes: ['href']) + end + + # Filters duplicate masks + def filter_masks(versions) + masks = {} + + versions.each do |version| + version.masks.each do |mask| + masks[mask['reason']] = mask + end + end + + masks.values + end + + def version_slot(slot, subslot = nil) + title = "subslot #{subslot}" if subslot && !subslot.empty? + + content_tag :span, + sanitize(' : %s' % slot), + class: 'kk-slot', + title: title + end + + # Returns a list of members belonging to a project + def project_members(project) + Portage::Util::Projects.cached_instance.inherited_members(project) + end + + # Tries to find a matching changelog entry for a change object + def matching_changelog_entry(change) + changelog = Rails.cache.fetch("changelog/#{cp_to_atom(change.category, change.package)}", expires_in: 10.minutes) do + Portage::Util::History.for(change.category, change.package, 5) + end + + changelog.each do |changelog_entry| + if changelog_entry[:files][:added].include?('%s-%s.ebuild' % [change.package, change.version]) + return changelog_entry + end + end + + nil + end +end diff --git a/app/helpers/portage_helper.rb b/app/helpers/portage_helper.rb new file mode 100644 index 0000000..3e1b9e6 --- /dev/null +++ b/app/helpers/portage_helper.rb @@ -0,0 +1,8 @@ +module PortageHelper + # Strips condition constructs ("foo? ()") from a Portage definition + def strip_conditionals(ary) + ary.reject do |item| + (not item[0] =~ /[[:alpha:]]/) or item.end_with? '?' + end + end +end diff --git a/app/helpers/useflags_helper.rb b/app/helpers/useflags_helper.rb new file mode 100644 index 0000000..258cec2 --- /dev/null +++ b/app/helpers/useflags_helper.rb @@ -0,0 +1,5 @@ +module UseflagsHelper + def annotate_useflag_description(str) + sanitize(str.gsub(/<pkg>([^<]+)<\/pkg>/) { pkg=$~[1] ; link_to(pkg, slf(package_path(pkg))) }, tags: ['a'], attributes: ['href']) + end +end diff --git a/app/jobs/category_update_job.rb b/app/jobs/category_update_job.rb new file mode 100644 index 0000000..6418bb4 --- /dev/null +++ b/app/jobs/category_update_job.rb @@ -0,0 +1,39 @@ +class CategoryUpdateJob < ActiveJob::Base + queue_as :default + + def perform(*args) + category_path, options = args + + model = Portage::Repository::Category.new(category_path) + category = Category.find_by(:name, model.name) || Category.new + idx_packages = Package.find_all_by(:category, model.name) || [] + + if category.needs_import? model + category.import! model + end + + idx_package_map = Hash[idx_packages.map { |p| [p.name, p] }] + model_package_map = Hash[model.packages.map { |p| [p.name, p] }] + + idx_keys = idx_package_map.keys + model_keys = model_package_map.keys + + new_p = model_keys - idx_keys + eql_p = model_keys & idx_keys + del_p = idx_keys - model_keys + + new_p.each do |pkg_name| + PackageUpdateJob.perform_later model_package_map[pkg_name].path, options.merge(package_state: 'new') + end + + eql_p.each do |pkg_name| + if idx_package_map[pkg_name].needs_import? model_package_map[pkg_name] + PackageUpdateJob.perform_later model_package_map[pkg_name].path, options.merge(package_state: 'existing') + end + end + + del_p.each do |pkg_name| + PackageRemovalJob.perform_later '%s/%s' % [category.name, pkg_name] + end + end +end diff --git a/app/jobs/masks_update_job.rb b/app/jobs/masks_update_job.rb new file mode 100644 index 0000000..a6574a0 --- /dev/null +++ b/app/jobs/masks_update_job.rb @@ -0,0 +1,7 @@ +class MasksUpdateJob < ActiveJob::Base + queue_as :default + + def perform(*_args) + Portage::Util::Masks.update! + end +end diff --git a/app/jobs/package_removal_job.rb b/app/jobs/package_removal_job.rb new file mode 100644 index 0000000..1041f05 --- /dev/null +++ b/app/jobs/package_removal_job.rb @@ -0,0 +1,16 @@ +class PackageRemovalJob < ActiveJob::Base + queue_as :default + + def perform(*args) + atom, _options = args + + package_doc = Package.find_by(:atom, atom) + return if package_doc.nil? + + package_doc.versions.each(&:delete) + package_doc.delete + + Rails.logger.warn { "Package deleted: #{atom}" } + # USE flags are cleaned up by the UseflagsUpdateJob + end +end diff --git a/app/jobs/package_update_job.rb b/app/jobs/package_update_job.rb new file mode 100644 index 0000000..8c4fd43 --- /dev/null +++ b/app/jobs/package_update_job.rb @@ -0,0 +1,13 @@ +class PackageUpdateJob < ActiveJob::Base + queue_as :default + + def perform(*args) + path, options = args + package_model = Portage::Repository::Package.new(path) + package_doc = Package.find_by(:atom, package_model.to_cp) || Package.new + + if package_doc.needs_import? package_model + package_doc.import!(package_model, options) + end + end +end diff --git a/app/jobs/record_change_job.rb b/app/jobs/record_change_job.rb new file mode 100644 index 0000000..b2b4b10 --- /dev/null +++ b/app/jobs/record_change_job.rb @@ -0,0 +1,30 @@ +class RecordChangeJob < ActiveJob::Base + queue_as :default + + # Creates a Change object for the given data + def perform(args) + c = Change.new + c.package = args[:package] + c.category = args[:category] + c.actor = args[:actor] if args.has_key? :actor + + if args[:type] == 'new_package' + c.change_type = 'new_package' + elsif args[:type] == 'version_bump' + c.change_type = 'version_bump' + c.version = args[:version] + elsif args[:type] == 'stable' + c.change_type = 'stable' + c.version = args[:version] + c.arches = args[:arches] + elsif args[:type] == 'keyword' + c.change_type = 'keyword' + c.version = args[:version] + c.arches = args[:arches] + elsif args[:type] == 'package_removed' + c.change_type = 'removal' + end + + c.save + end +end diff --git a/app/jobs/useflags_update_job.rb b/app/jobs/useflags_update_job.rb new file mode 100644 index 0000000..d6f9e9b --- /dev/null +++ b/app/jobs/useflags_update_job.rb @@ -0,0 +1,78 @@ +class UseflagsUpdateJob < ActiveJob::Base + queue_as :default + + def perform(*args) + repo = Portage::Repository::Model.new KKULEOMI_PORTDIR + + update_global repo + update_use_expand repo + end + + def update_global(repo) + model_flags = repo.global_useflags + index_flags = Useflag.global + + new_flags = model_flags.keys - index_flags.keys + del_flags = index_flags.keys - model_flags.keys + eql_flags = model_flags.keys & index_flags.keys + + new_flags.each do |flag| + flag_doc = Useflag.new + flag_doc.name = flag + flag_doc.description = model_flags[flag] + flag_doc.scope = 'global' + flag_doc.save + end + + eql_flags.each do |flag| + unless index_flags[flag].description == model_flags[flag] + index_flags[flag].description = model_flags[flag] + index_flags[flag].save + end + end + + del_flags.each do |flag| + index_flags[flag].delete + end + end + + def update_use_expand(repo) + model_flags = repo.use_expand_flags + index_flags = Useflag.use_expand + + # Calculate keys only once + index_flag_keys = index_flags.keys + + # Record processed flags to find deletion candidates + flag_status = Hash[index_flag_keys.map {|key| [key, false] }] + + model_flags.each_pair do |variable, values_hsh| + values_hsh.each_pair do |flag, desc| + _flag = '%s_%s' % [variable, flag] + flag_status[_flag] = true + + # Already present ones + if index_flag_keys.include? _flag + unless index_flags[_flag].description == desc + index_flags[_flag].description = desc + index_flags[_flag].save + end + else + # New flag + flag_doc = Useflag.new + flag_doc.name = _flag + flag_doc.description = desc + flag_doc.scope = 'use_expand' + flag_doc.use_expand_prefix = variable + flag_doc.save + end + end + end + + # Find and process removed flags + flag_status.each_pair do |flag, status| + index_flags[flag].delete unless status + end + end + +end diff --git a/app/mailers/.keep b/app/mailers/.keep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/app/mailers/.keep diff --git a/app/mailers/application_mailer.rb b/app/mailers/application_mailer.rb new file mode 100644 index 0000000..28eebce --- /dev/null +++ b/app/mailers/application_mailer.rb @@ -0,0 +1,4 @@ +class ApplicationMailer < ActionMailer::Base + default from: 'gpackages@gentoo.org' + layout 'mailer' +end diff --git a/app/mailers/feedback_mailer.rb b/app/mailers/feedback_mailer.rb new file mode 100644 index 0000000..3ec045c --- /dev/null +++ b/app/mailers/feedback_mailer.rb @@ -0,0 +1,8 @@ +class FeedbackMailer < ApplicationMailer + def feedback_email(feedback, contact) + @feedback = feedback + @contact = contact + + mail(to: KKULEOMI_FEEDBACK_RECIPIENT, subject: 'Feedback') + end +end diff --git a/app/models/.keep b/app/models/.keep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/app/models/.keep diff --git a/app/models/category.rb b/app/models/category.rb new file mode 100644 index 0000000..5fa31ea --- /dev/null +++ b/app/models/category.rb @@ -0,0 +1,39 @@ +class Category + include Elasticsearch::Persistence::Model + include Kkuleomi::Store::Model + + index_name "packages-#{Rails.env}" + + attribute :name, String, mapping: { index: 'not_analyzed' } + attribute :description, String + attribute :metadata_hash, String, mapping: { index: 'not_analyzed' } + + # Determines if the document model needs an update from the repository model + # + # @param [Portage::Repository::Category] category_model + def needs_import?(category_model) + metadata_hash != category_model.metadata_hash + end + + # Populates values from a repository category model + # + # @param [Portage::Repository::Category] category_model Input category model + def import(category_model) + self.name = category_model.name + self.description = category_model.description + self.metadata_hash = category_model.metadata_hash + end + + # Populates values from a repository category model and saves + # + # @param [Portage::Repository::Category] category_model Input category model + def import!(category_model) + import(category_model) + save + end + + # Returns the URL parameter for referencing this package (Rails internal stuff) + def to_param + name + end +end diff --git a/app/models/change.rb b/app/models/change.rb new file mode 100644 index 0000000..9ffe258 --- /dev/null +++ b/app/models/change.rb @@ -0,0 +1,13 @@ +class Change + include Elasticsearch::Persistence::Model + include Kkuleomi::Store::Model + + index_name "packages-#{Rails.env}" + + attribute :package, String, mapping: { index: 'not_analyzed' } + attribute :category, String, mapping: { index: 'not_analyzed' } + attribute :change_type, String, mapping: { index: 'not_analyzed' } + attribute :version, String, mapping: { index: 'not_analyzed' } + attribute :arches, String, mapping: { index: 'not_analyzed' } + attribute :commit, Hash, default: {}, mapping: { type: 'object' } +end diff --git a/app/models/concerns/.keep b/app/models/concerns/.keep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/app/models/concerns/.keep diff --git a/app/models/package.rb b/app/models/package.rb new file mode 100644 index 0000000..24cbd8b --- /dev/null +++ b/app/models/package.rb @@ -0,0 +1,74 @@ +class Package + include Elasticsearch::Persistence::Model + include Kkuleomi::Store::Model + include Kkuleomi::Store::Models::PackageImport + include Kkuleomi::Store::Models::PackageSearch + + index_name "packages-#{Rails.env}" + + attribute :category, String, mapping: { index: 'not_analyzed' } + attribute :name, String, mapping: { index: 'not_analyzed' } + attribute :name_sort, String, mapping: { index: 'not_analyzed' } + attribute :atom, String, mapping: { index: 'not_analyzed' } + attribute :description, String + attribute :longdescription, String + attribute :homepage, String, default: [], mapping: { index: 'not_analyzed' } + attribute :license, String, mapping: { index: 'not_analyzed' } + attribute :licenses, String, default: [], mapping: { index: 'not_analyzed' } + attribute :herds, String, default: [], mapping: { index: 'not_analyzed' } + attribute :maintainers, Array, default: [], mapping: { type: 'object' } + attribute :useflags, Hash, default: {}, mapping: { type: 'object' } + attribute :metadata_hash, String, mapping: { index: 'not_analyzed' } + + def category_model + @category_model ||= Category.find_by(:name, category) + end + + def to_param + atom + end + + # Are all of the versions of this package pending for removal? + # + # @return [Boolean] true, if all of the versions' masks look like a removal mask + def removal_pending? + versions.map(&:removal_pending?).uniq == [true] + end + + def has_useflags? + useflags && !(useflags['local'].empty? && useflags['global'].empty? && useflags['use_expand']) + end + + def versions + @versions ||= Version.find_all_by_parent(self, sort: { sort_key: { order: 'asc' } }) + end + + def latest_version + versions.first + end + + def version(version_str) + versions.each { |version| return version if version.version == version_str } + + nil + end + + # Does this package need a maintainer? + # + # @return [Boolean] true, if it is assigned to maintainer-needed or has no maintainers + def needs_maintainer? + (maintainers.size == 1 && maintainers.first['email'] == 'maintainer-needed@gentoo.org') || + maintainers.empty? && herds.empty? + end + + private + + # Splits a license string into single licenses, stripping the permitted logic constructs + def split_license_str(str) + return [] unless str + + str.split(/\s/).reject do |license| + (not license[0] =~ /[[:alpha:]]/) or license.end_with? '?' + end + end +end diff --git a/app/models/useflag.rb b/app/models/useflag.rb new file mode 100644 index 0000000..1139c97 --- /dev/null +++ b/app/models/useflag.rb @@ -0,0 +1,99 @@ +class Useflag + include Elasticsearch::Persistence::Model + include Kkuleomi::Store::Model + + index_name "packages-#{Rails.env}" + + attribute :name, String, mapping: { index: 'not_analyzed' } + attribute :description, String + attribute :atom, String, mapping: { index: 'not_analyzed' } + attribute :scope, String, mapping: { index: 'not_analyzed' } + attribute :use_expand_prefix, String, mapping: { index: 'not_analyzed' } + + def all_fields + [:name, :description, :atom, :scope, :use_expand_prefix] + end + + def to_param + name + end + + def strip_use_expand + name.gsub(use_expand_prefix + '_', '') + end + + class << self + # Retrieves all flags sorted by their state + def get_flags(name) + result = { local: {}, global: [], use_expand: [] } + + find_all_by(:name, name).each do |flag| + case flag.scope + when 'local' + result[:local][flag.atom] = flag + when 'global' + result[:global] << flag + when 'use_expand' + result[:use_expand] << flag + end + end + + result + end + + def suggest(q) + results = Useflag.search( + size: 20, + query: { match_phrase_prefix: { name: q } } + ) + + processed_results = {} + results.each do |result| + if processed_results.key? result.name + processed_results[result.name] = { + name: result.name, + description: '(multiple definitions)', + scope: 'multi' + } + else + processed_results[result.name] = result + end + end + + processed_results.values.sort { |a, b| a[:name].length <=> b[:name].length } + end + + # Loads the local USE flags for a given package in a name -> model hash + # + # @param [String] atom Package to find flags for + # @return [Hash] + def local_for(atom) + map_by_name find_all_by(:atom, atom) + end + + # Maps the global USE flags in the index by their name + # This is expensive! + # + def global + map_by_name find_all_by(:scope, 'global') + end + + # Maps the USE_EXPAND variables in the index by their name + # + def use_expand + map_by_name find_all_by(:scope, 'use_expand') + end + + private + + def map_by_name(collection) + map = {} + + collection.each do |item| + map[item.name] = item + end + + map + end + end +end diff --git a/app/models/version.rb b/app/models/version.rb new file mode 100644 index 0000000..1dc28f8 --- /dev/null +++ b/app/models/version.rb @@ -0,0 +1,165 @@ +class Version + include Elasticsearch::Persistence::Model + include Kkuleomi::Store::Model + include Kkuleomi::Store::Models::VersionImport + + index_name "packages-#{Rails.env}" + + attribute :version, String, mapping: { index: 'not_analyzed' } + attribute :package, String, mapping: { index: 'not_analyzed' } + attribute :atom, String, mapping: { index: 'not_analyzed' } + attribute :sort_key, Integer, mapping: { index: 'not_analyzed' } + attribute :slot, String, mapping: { index: 'not_analyzed' } + attribute :subslot, String, mapping: { index: 'not_analyzed' } + attribute :eapi, String, mapping: { index: 'not_analyzed' } + attribute :keywords, String, mapping: { index: 'not_analyzed' } + attribute :masks, Array, default: [], mapping: { type: 'object' } + attribute :use, String, default: [], mapping: { index: 'not_analyzed' } + attribute :restrict, String, default: [], mapping: { index: 'not_analyzed' } + attribute :properties, String, default: [], mapping: { index: 'not_analyzed' } + attribute :metadata_hash, String, mapping: { index: 'not_analyzed' } + + # Returns the keywording state on a given architecture + # + # @param [String] arch Architecture to query + # @return [Symbol] :stable, :testing, :unavailable, :unknown + def keyword(arch) + @keyword_info_cache ||= parse_keywords keywords + + if @keyword_info_cache[:arches].key? arch + @keyword_info_cache[:arches][arch] + else + if @keyword_info_cache[:exclude_all] + :unavailable + else + :unknown + end + end + end + + # Returns the effective keyword on a given architecture, accounting for masks + # + # @param [String] arch Architecture to query + # @return [Symbol] Keyword status + def effective_keyword(arch) + if is_masked?(arch) + :masked + else + keyword(arch) + end + end + + # Returns the masks that apply to the given architecture + # + def mask(arch) + masks.reject do |m| + if m['arch'] == '*' + false + else + m['arch'] != arch + end + end + end + + # Checks the masks whether one sounds like a package removal. + def removal_pending? + return false if masks.empty? + + masks.each do |m| + if m['reason'].include?('removal') || m['reason'].include?('Removal') + return true + end + end + + false + end + + def is_masked?(arch = nil) + !mask(arch).empty? + end + + # Returns supported USE flags categorized by local, global, and USE_EXPAND + # Typically called in the import phase, not live + # + # @return [Hash] + def useflags + @useflags ||= calc_useflags + end + + # Retrieves the most widely used USE flags by all versions + # Note that packages with many versions are over-represented + def self.get_popular_useflags(n = 50) + search( + query: { match_all: {} }, + aggs: { + group_by_flag: { + terms: { + field: 'use', + size: n + } + } + }, + size: 0 + ).response.aggregations['group_by_flag'].buckets + end + + # Parses a keyword array and assigns tags for each arch + # + # @param [Array<String>] keywords Input keywords + # @return [Hash] Parsed keywords + def parse_keywords(keywords) + res = { exclude_all: false, arches: {} } + return res unless keywords + + keywords.each do |kw| + if kw == '-*' + res[:exclude_all] = true + next + end + + if kw.start_with? '-' + res[:arches][kw[1..-1]] = :unavailable + next + end + + if kw.start_with? '~' + res[:arches][kw[1..-1]] = :testing + next + end + + res[:arches][kw] = :stable + end + + res + end + + private + + def calc_useflags + result = { local: {}, global: {}, use_expand: {} } + + local_flag_map = Useflag.local_for(atom.gsub("-#{version}", '')) + local_flags = local_flag_map.keys + + use.sort.each do |flag| + if local_flags.include? flag + result[:local][flag] = local_flag_map[flag].to_hsh + else + useflag = Useflag.find_by(:name, flag) + + # This should not happen, but let's be sure + next unless useflag + + if useflag.scope == 'global' + result[:global][useflag.name] = useflag.to_hsh + elsif useflag.scope == 'use_expand' + prefix = useflag.use_expand_prefix.upcase + result[:use_expand][prefix] ||= {} + result[:use_expand][prefix][useflag.name.gsub(useflag.use_expand_prefix + '_', '')] = useflag.to_hsh + end + end + end + + result + end +end diff --git a/app/views/about/changelog.html.md b/app/views/about/changelog.html.md new file mode 100644 index 0000000..070d979 --- /dev/null +++ b/app/views/about/changelog.html.md @@ -0,0 +1,9 @@ +<ol class="breadcrumb"> + <li><a href="/"><%= t :home %></a></li> + <li><a href="/about"><%= t :about %></a></li> + <li class="active"><%= t :changelog %></li> +</ol> + +# <%= t :changelog %> + +<%= kk_changelog %> diff --git a/app/views/about/feedback.html.erb b/app/views/about/feedback.html.erb new file mode 100644 index 0000000..4a1f1f3 --- /dev/null +++ b/app/views/about/feedback.html.erb @@ -0,0 +1,64 @@ +<ol class="breadcrumb"> + <li><a href="/"><%= t :home %></a></li> + <li><a href="/about"><%= t :about %></a></li> + <li class="active"><%= t :feedback %></li> +</ol> + +<h1>Feedback</h1> + +<p class="lead"> + Thanks for checking out the new packages.gentoo.org! +</p> +<p> + This site is currently in an <abbr title="minimum viable product">MVP</abbr> state and will be extended further to provide more useful features. + To help us prioritize new features and learn about your use case for the site, please share your ideas below. + <br><br> +</p> + +<div class="row"> + <div class="col-md-8"> + <div class="panel panel-default"> + <div class="panel-heading"> + <h3 class="panel-title">Send Feedback</h3> + </div> + <div class="panel-body"> + <form class="form-horizontal" method="post" action="/about/feedback"> + <div class="form-group"> + <label for="feedback" class="col-sm-2 control-label">Your Feedback:</label> + <div class="col-sm-10"> + <textarea name="feedback" id="feedback" class="form-control" rows="10" placeholder="Please be sure to explain issues in detail and with exact URL references."></textarea> + </div> + </div> + <div class="form-group"> + <label for="contact" class="col-sm-2 control-label">Contact (optional):</label> + <div class="col-sm-10"> + <input type="text" name="contact" class="form-control" id="contact" placeholder="How can we reach you to follow up on your feedback?"> + </div> + </div> + <div class="form-group"> + <div class="col-sm-offset-2 col-sm-10"> + <button type="submit" class="btn btn-default">Send</button> + </div> + </div> + </form> + </div> + </div> + </div> + <div class="col-md-4"> + <div class="panel panel-default"> + <div class="panel-heading"> + <h3 class="panel-title">Other ways to get in touch</h3> + </div> + <div class="list-group"> + <a href="mailto:gpackages@gentoo.org" class="list-group-item"> + <span class="fa fa-fw fa-envelope"></span> + E-Mail: gpackages@gentoo.org + </a> + <a href="irc://irc.gentoo.org/gentoo-www" class="list-group-item"> + <span class="fa fa-fw fa-comments-o"></span> + IRC: #gentoo-www + </a> + </div> + </div> + </div> +</div> diff --git a/app/views/about/feeds.html.erb b/app/views/about/feeds.html.erb new file mode 100644 index 0000000..5a9c1cd --- /dev/null +++ b/app/views/about/feeds.html.erb @@ -0,0 +1,23 @@ +<ol class="breadcrumb"> + <li><a href="/"><%= t :home %></a></li> + <li><a href="/about"><%= t :about %></a></li> + <li class="active"><%= t :update_feeds %></li> +</ol> + +<h1><%= t :update_feeds %></h1> + +<p> + You can find Atom feeds here: +</p> + +<ul> + <li> + For all packages: Right column on the <a href="/categories">category listing</a>. + </li> + <li> + For specific architectures: In the <a href="/arches">architectures section</a>. + </li> + <li> + For specific packages: In the <em>Resources</em> box on the respective package pages. + </li> +</ul> diff --git a/app/views/about/help.html.erb b/app/views/about/help.html.erb new file mode 100644 index 0000000..77ddf5b --- /dev/null +++ b/app/views/about/help.html.erb @@ -0,0 +1,11 @@ +<ol class="breadcrumb"> + <li><a href="/"><%= t :home %></a></li> + <li><a href="/about"><%= t :about %></a></li> + <li class="active"><%= t :help %></li> +</ol> + +<h1><%= t :help %></h1> + +<h2 id="keyword-legend"><%= t :keyword_table_legend %></h2> + +<%= render partial: 'packages/keyword_legend' %> diff --git a/app/views/about/index.html.erb b/app/views/about/index.html.erb new file mode 100644 index 0000000..5d9ed0f --- /dev/null +++ b/app/views/about/index.html.erb @@ -0,0 +1,23 @@ +<ol class="breadcrumb"> + <li><a href="/"><%= t :home %></a></li> + <li class="active"><%= t :about %></li> +</ol> + +<h1>About packages.gentoo.org</h1> + +<p>Welcome to the new packages.gentoo.org!</p> + +<p> + This section will be extended with further information as the site continues to develop. + Feel free to <a href="/about/feedback">get in touch</a> if you have any questions that are not answered on this page. +</p> + +<h2>FAQ</h2> + +<dl> + <dt>How often is the site updated?</dt> + <dd> + Updates are scheduled <strong>every 10 minutes</strong> and are processed using delayed jobs. + You can find the last time an import task was started in the footer. + </dd> +</dl> diff --git a/app/views/about/legacy.atom.builder b/app/views/about/legacy.atom.builder new file mode 100644 index 0000000..91c0928 --- /dev/null +++ b/app/views/about/legacy.atom.builder @@ -0,0 +1,18 @@ +atom_feed(id: atom_id(@feed_type, 'feed')) do |feed| + feed.title @feed_title + feed.updated Time.now + + feed.entry('', id: atom_id(@feed_type, 'deprecated'), url: about_feeds_url) do |entry| + entry.title 'This feed is deprecated' + entry.content <<END_CONTENT.strip +This is a legacy feed from the previous version of packages.gentoo.org + +With our recent site relaunch, the feed setup has changed as well. +To continue receiving updates about Gentoo packages, please visit the Feeds section of our new packages website at: + + https://packages.gentoo.org/about/feeds + +Thank you for your interest in our packages site. +END_CONTENT + end +end diff --git a/app/views/arches/index.html.erb b/app/views/arches/index.html.erb new file mode 100644 index 0000000..8684eb1 --- /dev/null +++ b/app/views/arches/index.html.erb @@ -0,0 +1,36 @@ +<ol class="breadcrumb"> + <li><a href="/">Home</a></li> + <li class="active"><%= t :architectures %></li> +</ol> + +<h1><%= t :architectures %></h1> + +<p><%= t :arches_intro %></p> + +<div class="panel panel-default"> + <div class="panel-heading"> + <h3 class="panel-title"><%= t :architectures %></h3> + </div> + <div class="table-responsive"> + <table class="table table-striped"> + <col> + <col style="width: 20em;"> + <col style="width: 20em;"> + <tbody> + <% ::KKULEOMI_ARCHES.sort.each do |arch| %> + <tr> + <th class="kk-nobreak-cell"><%= arch %></th> + <td> + <%= link_to t(:keyworded_packages), keyworded_arch_path(id: arch) %> + <%= feed_icon keyworded_arch_path(id: arch, format: :atom) %> + </td> + <td> + <%= link_to t(:stable_packages), stable_arch_path(id: arch) %> + <%= feed_icon stable_arch_path(id: arch, format: :atom) %> + </td> + </tr> + <% end %> + </tbody> + </table> + </div> +</div> diff --git a/app/views/arches/keyworded.html.erb b/app/views/arches/keyworded.html.erb new file mode 100644 index 0000000..b7ae03d --- /dev/null +++ b/app/views/arches/keyworded.html.erb @@ -0,0 +1,23 @@ +<ol class="breadcrumb"> + <li><a href="/">Home</a></li> + <li><%= link_to t(:architectures), arches_path %></li> + <li class="active"><%= t :keyworded_packages %></li> +</ol> + +<h1> + <%= t :keyworded_packages %> (<%= @arch %>) + <%= feed_icon keyworded_arch_path(id: @arch, format: :atom) %> +</h1> + +<% cache("keyworded-full-#{@arch}-#{@changes.hash}") do %> + <ul class="list-group"> + <% @changes.each do |change| + _package = Package.find_by(:atom, cp_to_atom(change.category, change.package)) %> + <%= render partial: 'packages/changed_package', object: change, as: 'change', locals: { package: _package, version: _package.version(change.version) } %> + <% end %> + </ul> +<% end %> + +<% content_for :head do %> + <%= alternate_feed_link(keyworded_arch_url(id: @arch, format: :atom), t(:atom_feed)) %> +<% end %> diff --git a/app/views/arches/show.html.erb b/app/views/arches/show.html.erb new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/app/views/arches/show.html.erb diff --git a/app/views/arches/stable.html.erb b/app/views/arches/stable.html.erb new file mode 100644 index 0000000..b1a4548 --- /dev/null +++ b/app/views/arches/stable.html.erb @@ -0,0 +1,23 @@ +<ol class="breadcrumb"> + <li><a href="/">Home</a></li> + <li><%= link_to t(:architectures), arches_path %></li> + <li class="active"><%= t :stable_packages %></li> +</ol> + +<h1> + <%= t :stable_packages %> (<%= @arch %>) + <%= feed_icon stable_arch_path(id: @arch, format: :atom) %> +</h1> + +<% cache("stable-full-#{@arch}-#{@changes.hash}") do %> + <ul class="list-group"> + <% @changes.each do |change| + _package = Package.find_by(:atom, cp_to_atom(change.category, change.package)) %> + <%= render partial: 'packages/changed_package', object: change, as: 'change', locals: { package: _package, version: _package.version(change.version) } %> + <% end %> + </ul> +<% end %> + +<% content_for :head do %> + <%= alternate_feed_link(stable_arch_url(id: @arch, format: :atom), t(:atom_feed)) %> +<% end %> diff --git a/app/views/categories/_category_header.html.erb b/app/views/categories/_category_header.html.erb new file mode 100644 index 0000000..b52cecf --- /dev/null +++ b/app/views/categories/_category_header.html.erb @@ -0,0 +1,21 @@ +<ol class="breadcrumb"> + <li><a href="/">Home</a></li> + <li><%= link_to t(:packages), categories_path %></li> + <li class="active"><%= category.name %></li> +</ol> + +<div class="row"> + <div class="col-md-4"> + <h1 class="stick-top"> + <span class="fa fa-fw fa-cubes"></span> + <%= category.name %> + </h1> + </div> + <div class="col-md-8"> + <p class="lead" style="margin: 0;"> + <%= category.description %> + </p> + </div> +</div> + +<hr>
\ No newline at end of file diff --git a/app/views/categories/_package_line.html.erb b/app/views/categories/_package_line.html.erb new file mode 100644 index 0000000..7ac4a43 --- /dev/null +++ b/app/views/categories/_package_line.html.erb @@ -0,0 +1,4 @@ +<tr> + <th class="kk-nobreak-cell"><%= link_to package.name, slf(package_path(package.atom)) %></th> + <td><%= package.description %></td> +</tr> diff --git a/app/views/categories/index.html.erb b/app/views/categories/index.html.erb new file mode 100644 index 0000000..9c19c9c --- /dev/null +++ b/app/views/categories/index.html.erb @@ -0,0 +1,52 @@ +<ol class="breadcrumb"> + <li><a href="/">Home</a></li> + <li class="active"><%= t :packages %></li> +</ol> + +<h1><%= t :packages %></h1> + +<div class="row"> + <div class="col-md-9"> + <div class="panel panel-default"> + <div class="panel-heading"> + <h3 class="panel-title"><%= t :browse_categories %></h3> + </div> + <div class="panel-body"> + <ul class="kk-col-list kk-4col-list kk-category-listing"> + <%- prev_letter = 'z' -%> + <% @categories.each do |category| %> + <%- unless category.name[0].upcase == prev_letter ; prev_letter = category.name[0].upcase -%> + <li class="kk-col-list-header"><span class="kk-group-header"><%= prev_letter %></span></li> + <%- end -%> + <li><%= link_to_category category %></li> + <% end %> + </ul> + </div> + </div> + </div> + <div class="col-md-3"> + <div class="panel panel-default"> + <div class="panel-heading"> + <h3 class="panel-title"><%= t :update_feeds %></h3> + </div> + <div class="list-group"> + <a href="<%= added_packages_path %>" class="list-group-item"> + <span class="fa fa-fw fa-history"></span> + <%= t :added_packages %> + </a> + <a href="<%= updated_packages_path %>" class="list-group-item"> + <span class="fa fa-fw fa-asterisk"></span> + <%= t :updated_packages %> + </a> + <a href="<%= stable_packages_path %>" class="list-group-item"> + <span class="fa fa-fw fa-check-circle-o"></span> + <%= t :stable_packages %> + </a> + <a href="<%= keyworded_packages_path %>" class="list-group-item"> + <span class="fa fa-fw fa-circle-o"></span> + <%= t :keyworded_packages %> + </a> + </div> + </div> + </div> +</div> diff --git a/app/views/categories/index.json.jbuilder b/app/views/categories/index.json.jbuilder new file mode 100644 index 0000000..12cc02e --- /dev/null +++ b/app/views/categories/index.json.jbuilder @@ -0,0 +1,5 @@ +json.array!(@categories) do |category| + json.extract! category, :name + json.extract! category, :description + json.url category_url(category, format: :json) +end diff --git a/app/views/categories/show.html.erb b/app/views/categories/show.html.erb new file mode 100644 index 0000000..41cceef --- /dev/null +++ b/app/views/categories/show.html.erb @@ -0,0 +1,28 @@ +<%= render partial: 'category_header', object: @category, as: 'category' %> + +<div class="row"> + <div class="col-md-9"> + <!--<p> + <input type="text" class="form-control form-control-xl" placeholder="Search packages in <%= @category.name %>"> + </p>--> + + <div class="panel panel-default"> + <div class="panel-heading"> + <h3 class="panel-title">All packages</h3> + </div> + <table class="table"> + <%= render partial: 'package_line', collection: @packages, as: 'package' %> + </table> + </div> + </div> + <div class="col-md-3"> + <div class="panel panel-default"> + <div class="panel-heading"> + <h3 class="panel-title">Statistics</h3> + </div> + <div class="panel-body"> + <%= @packages.count %> <%= t :packages %> + </div> + </div> + </div> +</div> diff --git a/app/views/categories/show.json.jbuilder b/app/views/categories/show.json.jbuilder new file mode 100644 index 0000000..fcf3811 --- /dev/null +++ b/app/views/categories/show.json.jbuilder @@ -0,0 +1,10 @@ +json.extract! @category, :name +json.href slf category_url(id: @category.name) + +json.packages @packages do |package| + json.name package.name + json.description package.description + json.href slf(package_url(id: package.atom)) +end + +json.extract! @category, :updated_at
\ No newline at end of file diff --git a/app/views/feedback_mailer/feedback_email.text.erb b/app/views/feedback_mailer/feedback_email.text.erb new file mode 100644 index 0000000..40b0b98 --- /dev/null +++ b/app/views/feedback_mailer/feedback_email.text.erb @@ -0,0 +1,5 @@ +Feedback: +------------------------------------------------------------------------------- +<%= @feedback %> +------------------------------------------------------------------------------- +Contact: <%= @contact %> diff --git a/app/views/feeds/changes.atom.builder b/app/views/feeds/changes.atom.builder new file mode 100644 index 0000000..5991f45 --- /dev/null +++ b/app/views/feeds/changes.atom.builder @@ -0,0 +1,60 @@ +@feed_id ||= nil + +atom_feed(id: atom_id(@feed_type, @feed_id, 'feed')) do |feed| + feed.title @feed_title + feed.updated !@changes.empty? ? @changes.first.created_at : Time.now + + feed.author do |author| + author.name 'Gentoo Packages Database' + end + + @changes.each do |change| + atom = cp_to_atom change.category, change.package + package = Package.find_by :atom, atom + if package.nil? + logger.warn "Package for change (#{change}) nil!" + next + end + + id = atom + id += '-%s' % change.version if change[:version] + id += '-%s' % change.arches.join(',') if change[:arches] + + feed.entry( + change, + id: atom_id(@feed_type, @feed_id, id), + url: absolute_link_to_package(atom)) do |entry| + entry.updated change.created_at.to_datetime.rfc3339 + + case @feed_type + when :added + entry.title(t :feed_added_title, + atom: atom, + description: package.description) + entry.content(t :feed_added_content, + atom: atom, + arches: package.latest_version.keywords.join(', ')) + when :updated + entry.title(t :feed_updated_title, + atom: atom_add_version(atom, change.version), + description: package.description) + entry.content(t :feed_updated_content, + atom: change.version) + when :stable + entry.title(t :feed_stable_title, + atom: atom_add_version(atom, change.version), + description: package.description) + entry.content(t :feed_stable_content, + atom: atom, + arches: change.arches.join(', ')) + when :keyworded + entry.title(t :feed_keyworded_title, + atom: atom_add_version(atom, change.version), + description: package.description) + entry.content(t :feed_keyworded_content, + atom: atom, + arches: change.arches.join(', ')) + end + end + end +end diff --git a/app/views/index/_package.html.erb b/app/views/index/_package.html.erb new file mode 100644 index 0000000..431142a --- /dev/null +++ b/app/views/index/_package.html.erb @@ -0,0 +1,8 @@ +<tr> + <td> + <a href="<%= slf(package_path(cp_to_atom(change.category, change.package))) %>"> + <span class="text-muted"><%= change.category %></span>/<strong><%= change.package %><%= "-#{change.version}" if change[:version] %></strong> + </a> + </td> + <td><%= Package.find_by(:atom, cp_to_atom(change.category, change.package)).description %></td> +</tr>
\ No newline at end of file diff --git a/app/views/index/index.html.erb b/app/views/index/index.html.erb new file mode 100644 index 0000000..890a5f3 --- /dev/null +++ b/app/views/index/index.html.erb @@ -0,0 +1,53 @@ +<div class="jumbotron"> + <h2 class="site-welcome stick-top">Welcome to the Home of <span class="text-primary"><%= number_with_delimiter Package.count %></span> Gentoo Packages</h2> + + <form action="<%= search_packages_path %>" method="get"> + <div class="typeahead-container"> + <div class="typeahead-field"> + <span class="typeahead-query"> + <input id="q" name="q" type="search" autocomplete="off" placeholder="<%= t :find_packages %>" aria-label="<%= t :find_packages %>" autofocus> + </span> + <span class="typeahead-button"> + <button type="submit" title="<%= t :find %>" aria-label="<%= t :find %>"> + <span class="typeahead-search-icon"></span><span class="sr-only"><%= t :find %></span> + </button> + </span> + </div> + </div> + </form> +</div> + +<% cache("added-#{@new_packages.hash}") do %> +<div class="panel panel-default"> + <div class="panel-heading"> + <h3 class="panel-title"> + <span class="fa fa-fw fa-history"></span> + <%= link_to t(:added_packages), added_packages_path %> + </h3> + </div> + <div class="table-responsive"> + <table class="table table-striped"> + <%= render partial: 'package', collection: @new_packages, as: 'change' %> + </table> + </div> +</div> +<% end %> + +<% cache("updated-#{@version_bumps.hash}") do %> +<div class="panel panel-default"> + <div class="panel-heading"> + <h3 class="panel-title"> + <span class="fa fa-fw fa-asterisk"></span> + <%= link_to t(:updated_packages), updated_packages_path %> + </h3> + </div> + <ul class="list-group"> + <% @version_bumps.each do |change| + _package = Package.find_by(:atom, cp_to_atom(change.category, change.package)) %> + <%= render partial: 'packages/changed_package', object: change, as: 'change', locals: { package: _package, version: _package.version(change.version) } %> + <% end %> + </ul> +</div> +<% end %> + +<%= javascript_include_tag 'index/typeahead.js' %> diff --git a/app/views/layouts/application.html.erb b/app/views/layouts/application.html.erb new file mode 100644 index 0000000..72fb8fa --- /dev/null +++ b/app/views/layouts/application.html.erb @@ -0,0 +1,153 @@ +<!DOCTYPE html> +<html> +<head> + <title><%= "#{@title} – " if @title %>Gentoo Packages</title> + <meta charset="utf-8"> + <meta name="viewport" content="width=device-width, initial-scale=1.0"> + <meta name="theme-color" content="#54487a"> + <meta name="description" content="<%= "#{@description} in the " if @description %>Gentoo Packages Database"> + <link href="https://assets.gentoo.org/tyrian/bootstrap.min.css" rel="stylesheet" media="screen"> + <link href="https://assets.gentoo.org/tyrian/tyrian.min.css" rel="stylesheet" media="screen"> + <%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track' => true %> + <%= javascript_include_tag 'application', 'data-turbolinks-track' => true %> + <script src="https://assets.gentoo.org/tyrian/bootstrap.min.js"></script> + <link rel="icon" href="https://www.gentoo.org/favicon.ico" type="image/x-icon"> + <% if content_for? :head -%> + <%= yield :head %> + <% end -%> +</head> +<body class="kk"> +<header> + <div class="site-title"> + <div class="container"> + <div class="row"> + <div class="site-title-buttons"> + <div class="btn-group btn-group-sm"> + <a href="https://get.gentoo.org/" role="button" class="btn get-gentoo"><span class="fa fa-fw fa-download"></span> <strong>Get Gentoo!</strong></a> + <div class="btn-group btn-group-sm"> + <a class="btn gentoo-org-sites dropdown-toggle" data-toggle="dropdown" data-target="#" href="#"> + <span class="fa fa-fw fa-map-o"></span> <span class="hidden-xs">gentoo.org sites</span> <span class="caret"></span> + </a> + <ul class="dropdown-menu dropdown-menu-right"> + <li><a href="https://www.gentoo.org/" title="Main Gentoo website"><span class="fa fa-home fa-fw"></span> gentoo.org</a></li> + <li><a href="https://wiki.gentoo.org/" title="Find and contribute documentation"><span class="fa fa-file-text-o fa-fw"></span> Wiki</a></li> + <li><a href="https://bugs.gentoo.org/" title="Report issues and find common issues"><span class="fa fa-bug fa-fw"></span> Bugs</a></li> + <li><a href="https://forums.gentoo.org/" title="Discuss with the community"><span class="fa fa-comments-o fa-fw"></span> Forums</a></li> + <li><a href="https://packages.gentoo.org/" title="Find software for your Gentoo"><span class="fa fa-hdd-o fa-fw"></span> Packages</a></li> + <li class="divider"></li> + <li><a href="https://planet.gentoo.org/" title="Find out what's going on in the developer community"><span class="fa fa-rss fa-fw"></span> Planet</a></li> + <li><a href="https://archives.gentoo.org/" title="Read up on past discussions"><span class="fa fa-archive fa-fw"></span> Archives</a></li> + <li><a href="https://sources.gentoo.org/" title="Browse our source code"><span class="fa fa-code fa-fw"></span> Sources</a></li> + <li class="divider"></li> + <li><a href="https://infra-status.gentoo.org/" title="Get updates on the services provided by Gentoo"><span class="fa fa-server fa-fw"></span> Infra Status</a></li> + </ul> + </div> + </div> + </div> + <div class="logo"> + <a href="/" title="Back to the homepage" class="site-logo"> + <object data="https://assets.gentoo.org/tyrian/site-logo.svg" type="image/svg+xml"> + <img src="https://assets.gentoo.org/tyrian/site-logo.png" alt="Gentoo Linux Logo"> + </object> + </a> + <span class="site-label">Packages</span> + </div> + </div> + </div> + </div> + <nav class="tyrian-navbar" role="navigation"> + <div class="container"> + <div class="row"> + <div class="navbar-header"> + <button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-main-collapse"> + <span class="sr-only">Toggle navigation</span> + <span class="icon-bar"></span> + <span class="icon-bar"></span> + <span class="icon-bar"></span> + </button> + </div> + <div class="collapse navbar-collapse navbar-main-collapse"> + <ul class="nav navbar-nav"> + <li class="<%= 'active' if @nav == :index %>"><%= link_to t(:home), '/' %></li> + <li class="<%= 'active' if @nav == :packages %>"><%= link_to t(:packages), categories_path %></li> + <li class="<%= 'active' if @nav == :use %>"><%= link_to t(:use_flags), useflags_path %></li> + <li class="<%= 'active' if @nav == :arches %>"><%= link_to t(:architectures), arches_path %></li> + <li class="<%= 'active' if @nav == :about %>"><%= link_to t(:about), about_path %></li> + </ul> + <% unless @nav == :index %> + <form class="navbar-form navbar-right" role="search" action="<%= search_packages_path %>" method="get"> + <div class="form-group"> + <input type="text" class="form-control" placeholder="Find Packages" name="q"> + </div> + </form> + <% end %> + </div> + </div> + </div> + </nav> +</header> + +<div class="container"> + <div class="row"> + <div class="col-xs-12"> + <%= yield %> + </div> + </div> +</div> + +<footer> + <div class="container"> + <div class="row"> + <div class="col-xs-12 col-md-offset-2 col-md-7"> + <h3 class="footerhead"><%= t :app_name %></h3> + <div class="row"> + <div class="col-xs-12 col-md-4"> + <span class="kk-group-header"><%= t :data_current_as_of %></span><br><%= last_import_start ? i18n_date(last_import_start) : 'unknown' %> + </div> + <div class="col-xs-12 col-md-4"> + </div> + <div class="col-xs-12 col-md-4"> + </div> + </div> + </div> + <div class="col-xs-12 col-md-3"> + <h3 class="footerhead">Questions or comments?</h3> + Please feel free to <a href="https://www.gentoo.org/inside-gentoo/contact/">contact us</a>. + </div> + </div> + <div class="row"> + <div class="col-xs-2 col-sm-3 col-md-2"> + <ul class="footerlinks three-icons"> + <li><a href="https://twitter.com/gentoo" title="@Gentoo on Twitter"><span class="fa fa-twitter fa-fw"></span></a></li> + <li><a href="https://plus.google.com/+Gentoo" title="+Gentoo on Google+"><span class="fa fa-google-plus fa-fw"></span></a></li> + <li><a href="https://www.facebook.com/gentoo.org" title="Gentoo on Facebook"><span class="fa fa-facebook fa-fw"></span></a></li> + </ul> + </div> + <div class="col-xs-10 col-sm-9 col-md-10"> + <strong>© 2001–2016 Gentoo Foundation, Inc.</strong><br> + <small> + Gentoo is a trademark of the Gentoo Foundation, Inc. + The contents of this document, unless otherwise expressly stated, are licensed under the + <a href="https://creativecommons.org/licenses/by-sa/3.0/" rel="license">CC-BY-SA-3.0</a> license. + The <a href="https://www.gentoo.org/inside-gentoo/foundation/name-logo-guidelines.html">Gentoo Name and Logo Usage Guidelines</a> apply. + </small> + </div> + </div> + </div> +</footer> +<script type="text/javascript"> + var _paq = _paq || []; + _paq.push(['disableCookies']); + _paq.push(['trackPageView']); + _paq.push(['enableLinkTracking']); + (function() { + var u="//piwik.gentoo.org/"; + _paq.push(['setTrackerUrl', u+'piwik.php']); + _paq.push(['setSiteId', 8]); + var d=document, g=d.createElement('script'), s=d.getElementsByTagName('script')[0]; + g.type='text/javascript'; g.async=true; g.defer=true; g.src=u+'piwik.js'; s.parentNode.insertBefore(g,s); + })(); +</script> +<noscript><p><img src="//piwik.gentoo.org/piwik.php?idsite=8" style="border:0;" alt="" /></p></noscript> +</body> +</html> diff --git a/app/views/layouts/mailer.html.erb b/app/views/layouts/mailer.html.erb new file mode 100644 index 0000000..991cf0f --- /dev/null +++ b/app/views/layouts/mailer.html.erb @@ -0,0 +1,5 @@ +<html> + <body> + <%= yield %> + </body> +</html> diff --git a/app/views/layouts/mailer.text.erb b/app/views/layouts/mailer.text.erb new file mode 100644 index 0000000..37f0bdd --- /dev/null +++ b/app/views/layouts/mailer.text.erb @@ -0,0 +1 @@ +<%= yield %> diff --git a/app/views/packages/_changed_package.html.erb b/app/views/packages/_changed_package.html.erb new file mode 100644 index 0000000..2e917e7 --- /dev/null +++ b/app/views/packages/_changed_package.html.erb @@ -0,0 +1,71 @@ +<% unless version.nil? %> +<li class="list-group-item kk-package-detailed"> + <div class="row"> + <div class="col-xs-12 col-md-6"> + <h4 class="stick-top"><%= link_to package.atom, slf(package_path(package.atom)) %></h4> + <div class="kk-package-detailed-toolbox"> + <div class="btn-group"> + <button type="button" class="btn btn-default btn-xs dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"> + <span class="fa fa-fw fa-navicon"></span> + </button> + <ul class="dropdown-menu dropdown-menu-right"> + <li><a href="https://bugs.gentoo.org/buglist.cgi?quicksearch=<%= u package.atom %>" target="_blank"> + <span class="fa fa-fw fa-bug"></span> + <%= t :res_bugs %> + </a></li> + <li><a href="https://wiki.gentoo.org/index.php?title=Special%3ASearch&fulltext=Search&search=<%= u package.name %>" target="_blank"> + <span class="fa fa-fw fa-book"></span> + <%= t :res_docs %> + </a></li> + <li><a href="https://forums.gentoo.org/search.php?search_terms=all&show_results=topics&search_keywords=<%= u package.name %>&mode=results" target="_blank"> + <span class="fa fa-fw fa-comments-o"></span> + <%= t :res_forums %> + </a></li> + <li role="separator" class="divider"></li> + <li><a href="https://gitweb.gentoo.org/repo/gentoo.git/tree/<%= package.atom %>" target="_blank"> + <span class="fa fa-fw fa-code-fork"></span> + <%= t :res_repo %> + </a></li> + <li><a href="https://gitweb.gentoo.org/repo/gentoo.git/log/<%= package.atom %>?showmsg=1" target="_blank"> + <span class="fa fa-fw fa-history"></span> + <%= t :res_log %> + </a></li> + <li><a href="https://gitweb.gentoo.org/repo/gentoo.git/atom/<%= package.atom %>?h=master" target="_blank"> + <span class="fa fa-fw fa-rss"></span> + <%= t :res_feed %> + </a></li> + <li role="separator" class="divider"></li> + <li><a href="http://www.portagefilelist.de/site/query/listPackageVersions/?category=<%= package.category %>&package=<%= package.name %>&do#result" target="_blank"> + <span class="fa fa-fw fa-files-o"></span> + <%= t :res_installed_files %> <small>(via PFL<span class="fa fa-fw fa-external-link-square"></span>)</small> + </a></li> + </ul> + </div> + </div> + <%= package.description %> + <br> + <small class="text-muted"> + <% unless change.arches == nil or change.arches.empty? %> + <%= t :added_keywords, keywords: change.arches.join(', ') %> + <% end %> + </small> + <% unless (changelog_entry = matching_changelog_entry(change)).nil? %> + <div class="kk-inline-changelog-entry"> + <a href="<%= gitweb_commit_url(changelog_entry[:id]) %>" title="<%= t :git_commit %>"> + <span class="octicon octicon-git-pull-request"></span> + <span class="kk-commit-message"> + <%= changelog_entry[:message].lines.first %> + </span> + </a> + </div> + <% end %> + </div> + <div class="col-xs-12 col-md-6"> + <small class="text-muted pull-right"> + <%= i18n_date(change.created_at) %> + </small> + <%= render partial: 'packages/version_card', object: version, as: 'version' %> + </div> + </div> +</li> +<% end %> diff --git a/app/views/packages/_changelog.html.erb b/app/views/packages/_changelog.html.erb new file mode 100644 index 0000000..c469a50 --- /dev/null +++ b/app/views/packages/_changelog.html.erb @@ -0,0 +1,19 @@ +<div class="panel panel-default"> + <div class="panel-heading"> + <h3 class="panel-title">Changelog</h3> + </div> + <ul class="list-group" id="changelog-container"> + <li class="list-group-item kk-panel-content-sorry"> + <span class="fa fa-refresh fa-spin fa-3x"></span> + <noscript> + <br><br> + <%= t :changelog_error %> + <br><br> + <a href="https://gitweb.gentoo.org/repo/gentoo.git/log/<%= @package.atom %>?showmsg=1" class="btn btn-default"> + <span class="fa fa-fw fa-history"></span> + <%= t :view_git_changelog %> + </a> + </noscript> + </li> + </ul> +</div> diff --git a/app/views/packages/_changelog_entry.html.erb b/app/views/packages/_changelog_entry.html.erb new file mode 100644 index 0000000..6b7b1da --- /dev/null +++ b/app/views/packages/_changelog_entry.html.erb @@ -0,0 +1,31 @@ +<li class="list-group-item"> + <strong><%= annotate_bugs changelog[:message].lines.first %></strong> + <br> + <div class="kk-byline"> + <%= mail_to changelog[:email], changelog[:author] %>, + <%= i18n_date(changelog[:date]) %>, + commit <%= link_to_gitweb_commit changelog[:id]%> + </div> + + <table class="table table-condensed kk-changelog-diffstat"> + <% unless changelog[:files][:added].empty? %> + <tr class="success"> + <td class="kk-changelog-diffstat-icon"><span class="octicon octicon-diff-added"></span></td> + <td><%= safe_join(changelog[:files][:added].map {|f| link_to_gitweb_ebuild_diff(f, changelog[:id], @package.category, @package.name) }, ', ') %></td> + </tr> + <% end %> + <% unless changelog[:files][:modified].empty? %> + <tr class="warning"> + <td class="kk-changelog-diffstat-icon"><span class="octicon octicon-diff-modified"></span></td> + <td><%= safe_join(changelog[:files][:modified].map {|f| link_to_gitweb_ebuild_diff(f, changelog[:id], @package.category, @package.name) }, ', ') %></td> + </tr> + <% end %> + <% unless changelog[:files][:deleted].empty? %> + <tr class="danger"> + <td class="kk-changelog-diffstat-icon"><span class="octicon octicon-diff-removed"></span></td> + <td><%= safe_join(changelog[:files][:deleted].map {|f| link_to_gitweb_ebuild_diff(f, changelog[:id], @package.category, @package.name) }, ', ') %></td> + </tr> + <% end %> + + </table> +</li> diff --git a/app/views/packages/_herd.html.erb b/app/views/packages/_herd.html.erb new file mode 100644 index 0000000..3e0db76 --- /dev/null +++ b/app/views/packages/_herd.html.erb @@ -0,0 +1 @@ +<%= link_to_herd herd %> diff --git a/app/views/packages/_keyword_legend.html.erb b/app/views/packages/_keyword_legend.html.erb new file mode 100644 index 0000000..8c45e36 --- /dev/null +++ b/app/views/packages/_keyword_legend.html.erb @@ -0,0 +1,17 @@ +<ul class="list-group kk-keyword-legend"> + <li class="list-group-item kk-keyword-stable"> + <%= keyword_icon_tag :stable %> <%= t :legend_stable %> + </li> + <li class="list-group-item kk-keyword-testing"> + <%= keyword_icon_tag :testing %> <%= t :legend_testing %> + </li> + <li class="list-group-item kk-keyword-unavailable"> + <%= keyword_icon_tag :unavailable %> <%= t :legend_unavailable %> + </li> + <li class="list-group-item kk-keyword-masked"> + <%= keyword_icon_tag :masked %> <%= t :legend_masked %> + </li> + <li class="list-group-item kk-keyword-unknown"> + <span class="kk-octicon-spacer"></span> <%= t :legend_unknown %> + </li> +</ul> diff --git a/app/views/packages/_maintainer.html.erb b/app/views/packages/_maintainer.html.erb new file mode 100644 index 0000000..9f89c7c --- /dev/null +++ b/app/views/packages/_maintainer.html.erb @@ -0,0 +1 @@ +<%= mail_to maintainer['email'], maintainer['name'], title: maintainer['email'] %>
\ No newline at end of file diff --git a/app/views/packages/_maintainer_needed_notice.html.erb b/app/views/packages/_maintainer_needed_notice.html.erb new file mode 100644 index 0000000..8359547 --- /dev/null +++ b/app/views/packages/_maintainer_needed_notice.html.erb @@ -0,0 +1,7 @@ +<% if package.needs_maintainer? %> + <div class="alert alert-info"> + <strong><span class="fa fa-fw fa-wrench"></span> This package needs a new maintainer!</strong><br> + If you are interested in helping with the maintenance of <%= package.name %>, please get in touch with our + <a href="https://wiki.gentoo.org/wiki/Project:Proxy_Maintainers" class="alert-link">Proxy Maintainers team</a>. + </div> +<% end %>
\ No newline at end of file diff --git a/app/views/packages/_maintainer_spacer.html.erb b/app/views/packages/_maintainer_spacer.html.erb new file mode 100644 index 0000000..4bb959b --- /dev/null +++ b/app/views/packages/_maintainer_spacer.html.erb @@ -0,0 +1 @@ +<%= ', ' %>
\ No newline at end of file diff --git a/app/views/packages/_mask.html.erb b/app/views/packages/_mask.html.erb new file mode 100644 index 0000000..b76a103 --- /dev/null +++ b/app/views/packages/_mask.html.erb @@ -0,0 +1,30 @@ +<li class="list-group-item kk-mask"> + <strong class="kk-mask-reason text-danger"><%= annotate_bugs(mask['reason']) %></strong> + + <div class="kk-mask-details"> + <!--<div class="row"> + <div class="col-xs-12 col-md-3 kk-metadata-key"> + Affected architectures + </div> + <div class="col-xs-12 col-md-9 kk-mask-atoms"> + <%# mask['arch'] %> + </div> + </div>--> + <div class="row"> + <div class="col-xs-12 col-md-3 kk-metadata-key"> + <%= t :mask_packages %> + </div> + <div class="col-xs-12 col-md-9 kk-mask-atoms"> + <%= mask['atoms'].join ', ' %> + </div> + </div> + <div class="row"> + <div class="col-xs-12 col-md-3 kk-metadata-key"> + <%= t :mask_author %> + </div> + <div class="col-xs-12 col-md-9"> + <%= mask['author'] %> <span class="text-muted">(<%= mask['date'] %>)</span> + </div> + </div> + </div> +</li> diff --git a/app/views/packages/_masks.html.erb b/app/views/packages/_masks.html.erb new file mode 100644 index 0000000..89bf166 --- /dev/null +++ b/app/views/packages/_masks.html.erb @@ -0,0 +1,10 @@ +<% unless (_masks = filter_masks(versions)).empty? %> +<div class="panel panel-default"> + <div class="panel-heading"> + <h3 class="panel-title"><%= t :box_masks %></h3> + </div> + <ul class="list-group"> + <%= render partial: 'mask', collection: _masks.to_a, as: 'mask' %> + </ul> +</div> +<% end %> diff --git a/app/views/packages/_metadata.html.erb b/app/views/packages/_metadata.html.erb new file mode 100644 index 0000000..426afd9 --- /dev/null +++ b/app/views/packages/_metadata.html.erb @@ -0,0 +1,87 @@ +<div class="panel panel-default"> + <div class="panel-heading"> + <h3 class="panel-title"><%= t :box_metadata %></h3> + </div> + <ul class="list-group kk-metadata-list"> + <% if package.homepage.size > 1 %> + <li class="kk-metadata-item list-group-item"> + <div class="row"> + <div class="col-xs-12 col-md-3 kk-metadata-key"> + <span class="fa fa-fw fa-home"></span> + <%= t :other_homepages %> + </div> + <div class="col-xs-12 col-md-9"> + <% package.homepage[1..-1].each do |hp| %> + <%= link_to hp, hp, rel: 'nofollow' %> + <% end %> + </div> + </div> + </li> + <% end %> + <% if package.longdescription %> + <li class="kk-metadata-item list-group-item"> + <div class="row"> + <div class="col-xs-12 col-md-3 kk-metadata-key"> + <span class="fa fa-fw fa-info"></span> + <%= t :longdescription %> + </div> + <div class="col-xs-12 col-md-9"> + <%= package.longdescription %> + </div> + </div> + </li> + <% end %> + <% if package.has_useflags? %> + <li class="kk-metadata-item list-group-item"> + <div class="row"> + <div class="col-xs-12 col-md-3 kk-metadata-key"> + <span class="fa fa-fw fa-sliders"></span> + <%= t :use_flags %> + </div> + <div class="col-xs-12 col-md-9"> + <%= render partial: 'metadata_use', object: package.useflags, as: 'useflags' %> + </div> + </div> + </li> + <% end %> + <% if package.license %> + <li class="kk-metadata-item list-group-item"> + <div class="row"> + <div class="col-xs-12 col-md-3 kk-metadata-key"> + <span class="fa fa-fw fa-legal"></span> + <%= t :license %> + </div> + <div class="col-xs-12 col-md-9"> + <%= annotate_license_str package.license %> + </div> + </div> + </li> + <% end %> + <% if package.herds and package.herds.size > 0 %> + <li class="kk-metadata-item list-group-item"> + <div class="row"> + <div class="col-xs-12 col-md-3 kk-metadata-key"> + <span class="fa fa-fw fa-group"></span> + <%= t :herds %> + </div> + <div class="col-xs-12 col-md-9"> + <%= render partial: 'herd', collection: package.herds.sort, as: 'herd', spacer_template: 'maintainer_spacer' %> + </div> + </div> + </li> + <% end %> + <% if package.maintainers and package.maintainers.size > 0 %> + <li class="kk-metadata-item list-group-item"> + <div class="row"> + <div class="col-xs-12 col-md-3 kk-metadata-key"> + <span class="fa fa-fw fa-user"></span> + <%= t :maintainers %> + </div> + <div class="col-xs-12 col-md-9"> + <%= render partial: 'maintainer', collection: package.maintainers, as: 'maintainer', spacer_template: 'maintainer_spacer' %> + </div> + </div> + </li> + <% end %> + </ul> +</div> diff --git a/app/views/packages/_metadata_use.html.erb b/app/views/packages/_metadata_use.html.erb new file mode 100644 index 0000000..d33b751 --- /dev/null +++ b/app/views/packages/_metadata_use.html.erb @@ -0,0 +1,14 @@ +<% unless useflags['local'].empty? %> + <span class="kk-useflag-group"><%= t :local_use_flags %></span> + <%= render partial: 'useflag', object: useflags['local'], as: 'useflags' %> +<% end %> +<% unless useflags['global'].empty? %> + <span class="kk-useflag-group"><%= t :global_use_flags %></span> + <%= render partial: 'useflag', object: useflags['global'], as: 'useflags' %> +<% end %> +<% unless useflags['use_expand'].empty? %> + <% useflags['use_expand'].each_pair do |flag, values| %> + <span class="kk-useflag-group"><%= t :use_expand_flag, flag: flag %></span> + <%= render partial: 'useflag', object: values, as: 'useflags' %> + <% end %> +<% end %> diff --git a/app/views/packages/_package_header.html.erb b/app/views/packages/_package_header.html.erb new file mode 100644 index 0000000..5b8ae08 --- /dev/null +++ b/app/views/packages/_package_header.html.erb @@ -0,0 +1,31 @@ +<ol class="breadcrumb"> + <li><a href="/">Home</a></li> + <li><%= link_to t(:packages), categories_path %></li> + <li><%= link_to package.category_model.name, category_path(package.category_model) %></li> + <li class="active"><%= package.name %></li> +</ol> + +<div class="row"> + <div class="col-md-4"> + <h1 class="stick-top kk-package-title" id="package-title" data-atom="<%= package.atom %>" data-category="<%= package.category %>" data-name="<%= package.name %>"> + <small class="kk-package-cat"><%= package.category_model.name %>/</small> + <div> + <span class="mega-octicon octicon-package kk-package-icon"></span> + <div class="kk-package-name"><%= package.name %></div> + </div> + </h1> + </div> + <div class="col-md-8"> + <p class="lead kk-package-maindesc"> + <%= package.description %> + </p> + + <p class="kk-package-homepage"> + <% if '' != package.homepage.first %> + <span class="fa fa-fw fa-home"></span> <%= link_to package.homepage.first, package.homepage.first, rel: 'nofollow' %> + <% end %> + </p> + </div> +</div> + +<hr> diff --git a/app/views/packages/_package_result_row.html.erb b/app/views/packages/_package_result_row.html.erb new file mode 100644 index 0000000..fd6c903 --- /dev/null +++ b/app/views/packages/_package_result_row.html.erb @@ -0,0 +1,4 @@ +<a class="list-group-item" href="<%= slf package_path package %>"> + <h3 class="kk-search-result-header"><span class="text-muted"><%= package.category %>/</span><%= package.name %></h3> + <%= package.description %> +</a>
\ No newline at end of file diff --git a/app/views/packages/_removal_notice.html.erb b/app/views/packages/_removal_notice.html.erb new file mode 100644 index 0000000..20d226b --- /dev/null +++ b/app/views/packages/_removal_notice.html.erb @@ -0,0 +1,5 @@ +<div class="alert alert-danger"> + <strong><span class="fa fa-fw fa-warning"></span> This package is masked and could be removed soon!</strong><br> + The mask comment indicates that this package is scheduled for removal from our package repository.<br> + Please review the mask information below for more details. +</div>
\ No newline at end of file diff --git a/app/views/packages/_resources.html.erb b/app/views/packages/_resources.html.erb new file mode 100644 index 0000000..51576a9 --- /dev/null +++ b/app/views/packages/_resources.html.erb @@ -0,0 +1,35 @@ +<div class="panel panel-default"> + <div class="panel-heading"> + <h3 class="panel-title"><%= t(:resources) %></h3> + </div> + <div class="list-group"> + <a href="https://bugs.gentoo.org/buglist.cgi?quicksearch=<%= u package.atom %>" class="list-group-item" target="_blank"> + <span class="fa fa-fw fa-bug"></span> + <%= t :res_bugs %> + </a> + <a href="https://wiki.gentoo.org/index.php?title=Special%3ASearch&fulltext=Search&search=<%= u package.name %>" class="list-group-item" target="_blank"> + <span class="fa fa-fw fa-book"></span> + <%= t :res_docs %> + </a> + <a href="https://forums.gentoo.org/search.php?search_terms=all&show_results=topics&search_keywords=<%= u package.name %>&mode=results" class="list-group-item" target="_blank"> + <span class="fa fa-fw fa-comments-o"></span> + <%= t :res_forums %> + </a> + <a href="https://gitweb.gentoo.org/repo/gentoo.git/tree/<%= package.atom %>" class="list-group-item" target="_blank"> + <span class="fa fa-fw fa-code-fork"></span> + <%= t :res_repo %> + </a> + <a href="https://gitweb.gentoo.org/repo/gentoo.git/log/<%= package.atom %>?showmsg=1" class="list-group-item" target="_blank"> + <span class="fa fa-fw fa-history"></span> + <%= t :res_log %> + </a> + <a href="https://gitweb.gentoo.org/repo/gentoo.git/atom/<%= package.atom %>?h=master" class="list-group-item" target="_blank"> + <span class="fa fa-fw fa-rss"></span> + <%= t :res_feed %> + </a> + <a href="http://www.portagefilelist.de/site/query/listPackageVersions/?category=<%= package.category %>&package=<%= package.name %>&do#result" class="list-group-item" target="_blank"> + <span class="fa fa-fw fa-files-o"></span> + <%= t :res_installed_files %> <small>(via PFL<span class="fa fa-fw fa-external-link-square"></span>)</small> + </a> + </div> +</div> diff --git a/app/views/packages/_useflag.html.erb b/app/views/packages/_useflag.html.erb new file mode 100644 index 0000000..a60e589 --- /dev/null +++ b/app/views/packages/_useflag.html.erb @@ -0,0 +1,5 @@ +<ul class="kk-useflag-container <%= useflags.size > 10 ? 'kk-useflag-container-many' : 'kk-useflag-container-few' %>"> +<% useflags.each_pair do |flag, flag_data| %> + <li class="kk-useflag"><%= link_to flag, useflag_path(id: flag_data['name']), :title => strip_tags(flag_data['description']), 'data-toggle' => 'tooltip' %></li> +<% end %> +</ul> diff --git a/app/views/packages/_version_card.html.erb b/app/views/packages/_version_card.html.erb new file mode 100644 index 0000000..7045617 --- /dev/null +++ b/app/views/packages/_version_card.html.erb @@ -0,0 +1,14 @@ +<div class="kk-version-card"> + <p><strong><%= version.version %></strong><%= version_slot version.slot %> <%= version_labels version %></p> + <p> + <%= keyword_label version, 'amd64' %> + <%= keyword_label version, 'x86' %> + <%= keyword_label version, 'alpha' %> + <%= keyword_label version, 'arm' %> + <%= keyword_label version, 'hppa' %> + <%= keyword_label version, 'ia64' %> + <%= keyword_label version, 'ppc' %> + <%= keyword_label version, 'ppc64' %> + <%= keyword_label version, 'sparc' %> + </p> +</div> diff --git a/app/views/packages/_version_row.html.erb b/app/views/packages/_version_row.html.erb new file mode 100644 index 0000000..d30d974 --- /dev/null +++ b/app/views/packages/_version_row.html.erb @@ -0,0 +1,12 @@ +<tr> + <td class="kk-version kk-cell-sep-right"><strong><%= version.version %></strong><%= version_slot version.slot, version.subslot %> <%= version_labels version %></td> + <%= keyword_cell version, 'amd64' %> + <%= keyword_cell version, 'x86', true %> + <%= keyword_cell version, 'alpha' %> + <%= keyword_cell version, 'arm' %> + <%= keyword_cell version, 'hppa' %> + <%= keyword_cell version, 'ia64' %> + <%= keyword_cell version, 'ppc' %> + <%= keyword_cell version, 'ppc64' %> + <%= keyword_cell version, 'sparc' %> +</tr> diff --git a/app/views/packages/_versions.html.erb b/app/views/packages/_versions.html.erb new file mode 100644 index 0000000..3484dc4 --- /dev/null +++ b/app/views/packages/_versions.html.erb @@ -0,0 +1,38 @@ +<div class="panel panel-default"> + <div class="panel-heading"> + <h3 class="panel-title"> + <%= t :box_versions %> + <span class="pull-right"> + <a href="<%= about_help_path(anchor: 'keyword-legend') %>" aria-label="<%= t :show_table_legend %>" title="<%= t :legend %>" class="kk-box-meta-link" tabindex="0" role="button" id="kk-keyword-legend-btn"> + <span class="fa fa-fw fa-question-circle"></span> + </a> + </span> + </h3> + </div> + <div class="table-responsive"> + <table class="table table-bordered kk-versions-table"> + <thead> + <tr> + <th class="kk-version kk-cell-sep-right"><%= t :version %></th> + <th class="kk-keyword-header kk-keyword">amd64</th> + <th class="kk-keyword-header kk-keyword kk-cell-sep-right">x86</th> + <th class="kk-keyword-header kk-keyword">alpha</th> + <th class="kk-keyword-header kk-keyword">arm</th> + <th class="kk-keyword-header kk-keyword">hppa</th> + <th class="kk-keyword-header kk-keyword">ia64</th> + <th class="kk-keyword-header kk-keyword">ppc</th> + <th class="kk-keyword-header kk-keyword">ppc64</th> + <th class="kk-keyword-header kk-keyword">sparc</th> + </tr> + </thead> + + <tbody> + <%= render partial: 'version_row', collection: versions, as: 'version' %> + </tbody> + </table> + </div> +</div> + +<script id="kk-keyword-legend-text" type="text/template"> +<%= render partial: 'keyword_legend' %> +</script> diff --git a/app/views/packages/added.html.erb b/app/views/packages/added.html.erb new file mode 100644 index 0000000..97d5cb6 --- /dev/null +++ b/app/views/packages/added.html.erb @@ -0,0 +1,23 @@ +<ol class="breadcrumb"> + <li><a href="/">Home</a></li> + <li><%= link_to t(:packages), categories_path %></li> + <li class="active"><%= t :added_packages %></li> +</ol> + +<h1> + <%= t :added_packages %> + <%= feed_icon added_packages_path(format: :atom) %> +</h1> + +<% cache("added-full-#{@changes.hash}") do %> + <ul class="list-group"> + <% @changes.each do |change| + _package = Package.find_by(:atom, cp_to_atom(change.category, change.package)) %> + <%= render partial: 'changed_package', object: change, as: 'change', locals: { package: _package, version: _package.latest_version } %> + <% end %> + </ul> +<% end %> + +<% content_for :head do %> + <%= alternate_feed_link(added_packages_url(format: :atom), t(:atom_feed)) %> +<% end %> diff --git a/app/views/packages/changelog.html.erb b/app/views/packages/changelog.html.erb new file mode 100644 index 0000000..df9242e --- /dev/null +++ b/app/views/packages/changelog.html.erb @@ -0,0 +1,12 @@ +<% if @changelog.empty? -%> + <li class="list-group-item kk-panel-content-sorry"> + <%= t :changelog_empty %> + <br><br> + <a href="https://sources.gentoo.org/cgi-bin/viewvc.cgi/gentoo-x86/<%= @package.atom %>/ChangeLog?view=markup" class="btn btn-default"> + <span class="fa fa-fw fa-history"></span> + <%= t :view_cvs_changelog %> + </a> + </li> +<% else %> + <%= render partial: 'changelog_entry', collection: @changelog, as: 'changelog' %> +<% end %> diff --git a/app/views/packages/changelog.json.jbuilder b/app/views/packages/changelog.json.jbuilder new file mode 100644 index 0000000..a88a2db --- /dev/null +++ b/app/views/packages/changelog.json.jbuilder @@ -0,0 +1 @@ +json.changes @changelog diff --git a/app/views/packages/keyworded.html.erb b/app/views/packages/keyworded.html.erb new file mode 100644 index 0000000..ff5b60c --- /dev/null +++ b/app/views/packages/keyworded.html.erb @@ -0,0 +1,23 @@ +<ol class="breadcrumb"> + <li><a href="/">Home</a></li> + <li><%= link_to t(:packages), categories_path %></li> + <li class="active"><%= t :keyworded_packages %></li> +</ol> + +<h1> + <%= t :keyworded_packages %> + <%= feed_icon keyworded_packages_path(format: :atom) %> +</h1> + +<% cache("keyworded-full-#{@changes.hash}") do %> + <ul class="list-group"> + <% @changes.each do |change| + _package = Package.find_by(:atom, cp_to_atom(change.category, change.package)) %> + <%= render partial: 'changed_package', object: change, as: 'change', locals: { package: _package, version: _package.version(change.version) } %> + <% end %> + </ul> +<% end %> + +<% content_for :head do %> + <%= alternate_feed_link(keyworded_packages_url(format: :atom), t(:atom_feed)) %> +<% end %> diff --git a/app/views/packages/resolve.json.jbuilder b/app/views/packages/resolve.json.jbuilder new file mode 100644 index 0000000..73ffdbb --- /dev/null +++ b/app/views/packages/resolve.json.jbuilder @@ -0,0 +1,4 @@ +json.packages @packages do |package| + json.extract! package, :atom, :description + json.href slf package_url(id: package.atom) +end diff --git a/app/views/packages/search.html.erb b/app/views/packages/search.html.erb new file mode 100644 index 0000000..fe77dd3 --- /dev/null +++ b/app/views/packages/search.html.erb @@ -0,0 +1,38 @@ +<h1 class="first-header">Search Results <small>for <%= params[:q] %></small></h1> + +<% if @packages.size > 0 %> +<div class="panel panel-default"> + <div class="panel-heading"> + Results <%= @offset + 1 %>—<%= [@offset + Package.default_search_size, @packages.total].min %> of <%= @packages.total %> + </div> + <div class="list-group"> + <%= render partial: 'package_result_row', collection: @packages, as: 'package' %> + </div> + <div class="panel-footer"> + <div class="btn-group" role="group" aria-label="Result navigation"> + <%= link_to '< Prev', search_packages_path(q: params[:q], o: [@offset - Package.default_search_size, 0].max), class: 'btn btn-default' + (@offset > 0 ? '' : ' disabled') %> + <%= link_to 'Next >', search_packages_path(q: params[:q], o: @offset + Package.default_search_size), class: 'btn btn-default ' + ((@offset + Package.default_search_size) > @packages.total ? 'disabled' : '') %> + </div> + </div> +</div> +<% else %> +<div class="jumbotron"> + <h2 class="site-welcome stick-top">Nothing found. :( Try again?</h2> + + <form action="<%= search_packages_path %>" method="get"> + <div class="typeahead-container"> + <div class="typeahead-field"> + <span class="typeahead-query"> + <input id="q" name="q" type="search" autocomplete="off" placeholder="<%= t :find_packages %>" aria-label="<%= t :find_packages %>" value="<%= params[:q] %>"> + </span> + <span class="typeahead-button"> + <button type="submit" title="<%= t :find %>" aria-label="<%= t :find %>"> + <span class="typeahead-search-icon"></span><span class="sr-only"><%= t :find %></span> + </button> + </span> + </div> + </div> + </form> +</div> +<%= javascript_include_tag 'index/typeahead.js' %> +<% end %> diff --git a/app/views/packages/show.html.erb b/app/views/packages/show.html.erb new file mode 100644 index 0000000..bc649ba --- /dev/null +++ b/app/views/packages/show.html.erb @@ -0,0 +1,28 @@ +<% cache "#{@package.atom}-#{@package.metadata_hash}" do %> +<%= render partial: 'package_header', object: @package, as: 'package' %> + +<div class="row"> + <div class="col-md-9"> + <%= render partial: 'versions', object: @package.versions, as: 'versions' %> + + <% if @package.removal_pending? %> + <%= render partial: 'removal_notice', object: @package, as: 'package' %> + <% end %> + + <%= render partial: 'maintainer_needed_notice', object: @package, as: 'package' %> + <%= render partial: 'metadata', object: @package, as: 'package', locals: { latest_version: @package.versions.first} %> + + <%= render partial: 'masks', object: @package.versions, as: 'versions' %> + + <%= render partial: 'changelog', object: @changelog, as: 'changelog' %> + </div> + <div class="col-md-3"> + <%= render partial: 'resources', object: @package, as: 'package' %> + </div> +</div> + +<%= javascript_include_tag 'packages/show' %> +<% content_for :head do %> + <%= alternate_feed_link('https://gitweb.gentoo.org/repo/gentoo.git/atom/%s?h=master' % @package.atom, t(:raw_git_feed)) %> +<% end %> +<% end %> diff --git a/app/views/packages/show.json.jbuilder b/app/views/packages/show.json.jbuilder new file mode 100644 index 0000000..3b8a012 --- /dev/null +++ b/app/views/packages/show.json.jbuilder @@ -0,0 +1,43 @@ +json.extract! @package, :atom, :description +json.href slf package_url(id: @package.atom) + +json.versions @package.versions do |version| + json.version version.version + json.keywords version.keywords + json.masks version.masks +end + +json.herds @package.herds +json.maintainers @package.maintainers do |maintainer| + json.email maintainer['email'] + json.name maintainer['name'] + json.description maintainer['description'] + json.type maintainer['type'] + + if maintainer['type'] == 'project' + json.members project_members(maintainer['email']) + end +end + +json.use do + json.local @package.versions.first.useflags[:local] do |flag| + json.name flag[1][:name] + json.description strip_tags flag[1][:description] + end + + json.global @package.versions.first.useflags[:global] do |flag| + json.name flag[1][:name] + json.description strip_tags flag[1][:description] + end + + json.use_expand @package.versions.first.useflags[:use_expand] do |flag| + json.set! flag[0] do + json.array! flag[1] do |expand_flag| + json.name expand_flag[0] + json.description strip_tags expand_flag[1][:description] + end + end + end +end + +json.extract! @package, :updated_at diff --git a/app/views/packages/stable.html.erb b/app/views/packages/stable.html.erb new file mode 100644 index 0000000..7b230fe --- /dev/null +++ b/app/views/packages/stable.html.erb @@ -0,0 +1,23 @@ +<ol class="breadcrumb"> + <li><a href="/">Home</a></li> + <li><%= link_to t(:packages), categories_path %></li> + <li class="active"><%= t :stable_packages %></li> +</ol> + +<h1> + <%= t :stable_packages %> + <%= feed_icon stable_packages_path(format: :atom) %> +</h1> + +<% cache("stable-full-#{@changes.hash}") do %> + <ul class="list-group"> + <% @changes.each do |change| + _package = Package.find_by(:atom, cp_to_atom(change.category, change.package)) %> + <%= render partial: 'changed_package', object: change, as: 'change', locals: { package: _package, version: _package.version(change.version) } %> + <% end %> + </ul> +<% end %> + +<% content_for :head do %> + <%= alternate_feed_link(stable_packages_url(format: :atom), t(:atom_feed)) %> +<% end %> diff --git a/app/views/packages/suggest.json.jbuilder b/app/views/packages/suggest.json.jbuilder new file mode 100644 index 0000000..fcd8ba5 --- /dev/null +++ b/app/views/packages/suggest.json.jbuilder @@ -0,0 +1 @@ +json.results @packages, :name, :category, :description diff --git a/app/views/packages/updated.html.erb b/app/views/packages/updated.html.erb new file mode 100644 index 0000000..b774c58 --- /dev/null +++ b/app/views/packages/updated.html.erb @@ -0,0 +1,23 @@ +<ol class="breadcrumb"> + <li><a href="/">Home</a></li> + <li><%= link_to t(:packages), categories_path %></li> + <li class="active"><%= t :updated_packages %></li> +</ol> + +<h1> + <%= t :updated_packages %> + <%= feed_icon updated_packages_path(format: :atom) %> +</h1> + +<% cache("updated-full-#{@changes.hash}") do %> + <ul class="list-group"> + <% @changes.each do |change| + _package = Package.find_by(:atom, cp_to_atom(change.category, change.package)) %> + <%= render partial: 'changed_package', object: change, as: 'change', locals: { package: _package, version: _package.version(change.version) } %> + <% end %> + </ul> +<% end %> + +<% content_for :head do %> + <%= alternate_feed_link(updated_packages_url(format: :atom), t(:atom_feed)) %> +<% end %> diff --git a/app/views/useflags/_useflag_header.html.erb b/app/views/useflags/_useflag_header.html.erb new file mode 100644 index 0000000..9422fac --- /dev/null +++ b/app/views/useflags/_useflag_header.html.erb @@ -0,0 +1,5 @@ +<ol class="breadcrumb"> + <li><a href="/"><%= t :home %></a></li> + <li><%= link_to t(:use_flags), useflags_path %></li> + <li class="active"><%= params[:id] %></li> +</ol> diff --git a/app/views/useflags/_useflag_result_row.html.erb b/app/views/useflags/_useflag_result_row.html.erb new file mode 100644 index 0000000..084669f --- /dev/null +++ b/app/views/useflags/_useflag_result_row.html.erb @@ -0,0 +1,4 @@ +<a class="list-group-item" href="<%= slf useflag_path useflag[:name] %>"> + <h3 class="kk-search-result-header"><%= useflag[:name] %></h3> + <%= useflag[:description] %> +</a> diff --git a/app/views/useflags/index.html.erb b/app/views/useflags/index.html.erb new file mode 100644 index 0000000..ac006f2 --- /dev/null +++ b/app/views/useflags/index.html.erb @@ -0,0 +1,45 @@ +<ol class="breadcrumb"> + <li><a href="/"><%= t :home %></a></li> + <li class="active"><%= t :use_flags %></li> +</ol> + +<h1><%= t :use_flags %></h1> + +<div class="alert alert-info"> + Looking for the full USE flag index? + You can find it on our <a href="https://www.gentoo.org/support/use-flags/" class="alert-link">main website</a>. +</div> + +<form action="<%= search_useflags_path %>" method="get" class="useflag-search"> + <div class="typeahead-container"> + <div class="typeahead-field"> + <span class="typeahead-query"> + <input id="q" name="q" type="search" autocomplete="off" placeholder="Find USE flags"> + </span> + <span class="typeahead-button"> + <button type="submit"> + <span class="typeahead-search-icon"></span> + </button> + </span> + </div> + </div> +</form> + +<br> + +<div class="panel panel-default"> + <div class="panel-heading"> + <h3 class="panel-title">Most widely used USE flags</h3> + </div> + <noscript> + <div class="panel-body kk-panel-content-sorry"> + This feature requires JavaScript to work. + </div> + </noscript> + <div class="panel-body kk-useflag-bubble-container" id="bubble-placeholder" style="display: none;"> + </div> +</div> + +<%= javascript_include_tag 'useflags/typeahead.js' %> +<%= javascript_include_tag 'd3.min.js' %> +<%= javascript_include_tag 'useflags/render-bubbles.js' %> diff --git a/app/views/useflags/popular.json.jbuilder b/app/views/useflags/popular.json.jbuilder new file mode 100644 index 0000000..d174c9e --- /dev/null +++ b/app/views/useflags/popular.json.jbuilder @@ -0,0 +1,10 @@ +json.name 'flags' +json.children @popular_useflags do |flag| + # Very cheap filter for USE_EXPAND flags + next if flag['key'].include? '_' + next if flag['key'] =~ /^(doc|test|debug)$/ + + json.name flag['key'] + json.size flag['doc_count'] + json.children nil +end diff --git a/app/views/useflags/search.html.erb b/app/views/useflags/search.html.erb new file mode 100644 index 0000000..061405b --- /dev/null +++ b/app/views/useflags/search.html.erb @@ -0,0 +1,16 @@ +<ol class="breadcrumb"> + <li><a href="/"><%= t :home %></a></li> + <li><%= link_to t(:use_flags), useflags_path %></li> + <li class="active">Search</li> +</ol> + +<h1>USE Flag Search Results <small>for <%= params[:q] %></small></h1> + +<div class="panel panel-default"> + <div class="panel-heading"> + Results + </div> + <div class="list-group"> + <%= render partial: 'useflag_result_row', collection: @flags, as: 'useflag' %> + </div> +</div> diff --git a/app/views/useflags/show.html.erb b/app/views/useflags/show.html.erb new file mode 100644 index 0000000..b5b8bb6 --- /dev/null +++ b/app/views/useflags/show.html.erb @@ -0,0 +1,61 @@ +<%= render partial: 'useflag_header' %> + +<div class="row"> + <div class="col-md-4"> + <h1 class="stick-top"> + <span class="fa fa-fw fa-sliders"></span> + <%= params[:id] %> + </h1> + </div> + <div class="col-md-8"> + <% unless @useflags[:global].empty? %> + <div class="kk-useflag-group"><%= t :global_use_flag %></div> + <p class="lead" style="margin: 0;"> + <%= @useflags[:global].first.description %> + </p> + <% else %> + <div class="kk-useflag-group"><%= t :local_use_flag %></div> + <% end %> + </div> +</div> + +<hr> + +<% unless @useflags[:local].empty? %> + <div class="panel panel-default"> + <div class="panel-heading"> + <h3 class="panel-title"><%= t :local_use_package_list, flag: params[:id] %></h3> + </div> + <div class="table-responsive"> + <table class="table"> + <thead> + <th><%= t :package %></th> + <th><%= t :flag_description, flag: params[:id] %></th> + </thead> + <tbody> + <% @useflags[:local].keys.sort.each do |package| %> + <tr> + <th class="kk-nobreak-cell"><%= link_to package, slf(package_path(package)) %></th> + <td><%= annotate_useflag_description @useflags[:local][package].description %></td> + </tr> + <% end %> + </tbody> + </table> + </div> + </div> +<% end %> + +<% unless @useflags[:global].empty? %> + <div class="panel panel-default"> + <div class="panel-heading"> + <h3 class="panel-title"><%= t :providing_packages_list, flag: params[:id], count: @packages.count %></h3> + </div> + <div class="panel-body"> + <ul class="kk-col-list kk-3col-list kk-useflag-listing"> + <% @packages.each do |package| %> + <li><%= link_to_package package['key'] %></li> + <% end %> + </ul> + </div> + </div> +<% end %> diff --git a/app/views/useflags/show_use_expand.html.erb b/app/views/useflags/show_use_expand.html.erb new file mode 100644 index 0000000..45c2779 --- /dev/null +++ b/app/views/useflags/show_use_expand.html.erb @@ -0,0 +1,57 @@ +<%= render partial: 'useflag_header' %> + +<div class="row"> + <div class="col-md-4"> + <h1 class="stick-top"> + <span class="fa fa-fw fa-sliders"></span> + <%= @useflag.strip_use_expand %> + </h1> + </div> + <div class="col-md-8"> + <div class="kk-useflag-group"><%= t :named_use_expand_flag, name: @use_expand_flag_name %></div> + <p class="lead" style="margin: 0;"> + <%= @useflags[:use_expand].first.description %> + </p> + </div> +</div> + +<hr> + +<% unless @use_expand_flags.empty? %> + <div class="panel panel-default"> + <div class="panel-heading"> + <h3 class="panel-title"><%= t :other_use_expand_list, flag: @use_expand_flag_name %></h3> + </div> + <div class="table-responsive"> + <table class="table"> + <thead> + <th><%= t :use_flag %></th> + <th><%= t :description %></th> + </thead> + <tbody> + <% @use_expand_flags.each do |flag| %> + <tr> + <th class="kk-nobreak-cell"><%= link_to flag.name, slf(useflag_path(flag.name)) %></th> + <td><%= flag.description %></td> + </tr> + <% end %> + </tbody> + </table> + </div> + </div> +<% end %> + +<% unless @packages.empty? %> + <div class="panel panel-default"> + <div class="panel-heading"> + <h3 class="panel-title"><%= t :providing_packages_list, flag: params[:id], count: @packages.count %></h3> + </div> + <div class="panel-body"> + <ul class="kk-3col-list kk-useflag-listing"> + <% @packages.each do |package| %> + <li><%= link_to_package package['key'] %></li> + <% end %> + </ul> + </div> + </div> +<% end %> diff --git a/app/views/useflags/suggest.json.jbuilder b/app/views/useflags/suggest.json.jbuilder new file mode 100644 index 0000000..5e1571f --- /dev/null +++ b/app/views/useflags/suggest.json.jbuilder @@ -0,0 +1 @@ +json.results @flags |