Initial pass at S3 version
This commit is contained in:
parent
0371ade45e
commit
4cb98ac8df
|
@ -1 +1,5 @@
|
|||
/root
|
||||
/static/pkgs
|
||||
/static/pkg
|
||||
/static/pkgs-all
|
||||
*json
|
||||
|
|
31
pkgs/plt-services/meta/pkg-index/official/common.rkt
Normal file
31
pkgs/plt-services/meta/pkg-index/official/common.rkt
Normal file
|
@ -0,0 +1,31 @@
|
|||
#lang racket/base
|
||||
(require racket/file
|
||||
racket/runtime-path
|
||||
pkg/util
|
||||
racket/string
|
||||
web-server/http/id-cookie)
|
||||
|
||||
(define-runtime-path src ".")
|
||||
|
||||
(define-runtime-path root "root")
|
||||
(make-directory* root)
|
||||
(define secret-key
|
||||
(make-secret-salt/file
|
||||
(build-path root "secret.key")))
|
||||
(define users-path (build-path root "users"))
|
||||
(make-directory* users-path)
|
||||
(define users.new-path (build-path root "users.new"))
|
||||
(make-directory* users.new-path)
|
||||
|
||||
(github-client_id (file->string (build-path root "client_id")))
|
||||
(github-client_secret (file->string (build-path root "client_secret")))
|
||||
|
||||
(define pkgs-path (build-path root "pkgs"))
|
||||
(make-directory* pkgs-path)
|
||||
|
||||
(define static-path (build-path src "static"))
|
||||
|
||||
(define (author->list as)
|
||||
(string-split as))
|
||||
|
||||
(provide (all-defined-out))
|
|
@ -2,6 +2,7 @@
|
|||
(module+ test
|
||||
(require rackunit))
|
||||
(require web-server/http
|
||||
"common.rkt"
|
||||
web-server/servlet-env
|
||||
racket/file
|
||||
xml
|
||||
|
@ -38,24 +39,6 @@
|
|||
(define (salty str)
|
||||
(sha1 (open-input-string str)))
|
||||
|
||||
(define-runtime-path src ".")
|
||||
|
||||
(define-runtime-path root "root")
|
||||
(make-directory* root)
|
||||
(define secret-key
|
||||
(make-secret-salt/file
|
||||
(build-path root "secret.key")))
|
||||
(define users-path (build-path root "users"))
|
||||
(make-directory* users-path)
|
||||
(define users.new-path (build-path root "users.new"))
|
||||
(make-directory* users.new-path)
|
||||
|
||||
(github-client_id (file->string (build-path root "client_id")))
|
||||
(github-client_secret (file->string (build-path root "client_secret")))
|
||||
|
||||
(define pkgs-path (build-path root "pkgs"))
|
||||
(make-directory* pkgs-path)
|
||||
|
||||
(define id-cookie-name "pnrid")
|
||||
|
||||
;; XXX Add a caching system
|
||||
|
@ -159,9 +142,6 @@
|
|||
new-v]))
|
||||
#f)))
|
||||
|
||||
(define (author->list as)
|
||||
(string-split as))
|
||||
|
||||
(define (page/rss req)
|
||||
(define ps
|
||||
(sort (map package-info (package-list))
|
||||
|
@ -1132,7 +1112,7 @@
|
|||
#:ssl-cert (build-path root "server-cert.pem")
|
||||
#:ssl-key (build-path root "private-key.pem")
|
||||
#:extra-files-paths
|
||||
(list (build-path src "static"))
|
||||
(list static-path)
|
||||
#:servlet-regexp #rx""
|
||||
#:port port))
|
||||
|
||||
|
|
75
pkgs/plt-services/meta/pkg-index/official/static.rkt
Normal file
75
pkgs/plt-services/meta/pkg-index/official/static.rkt
Normal file
|
@ -0,0 +1,75 @@
|
|||
#lang racket/base
|
||||
(require web-server/http
|
||||
racket/file
|
||||
racket/match
|
||||
json
|
||||
net/url
|
||||
racket/list
|
||||
racket/path
|
||||
racket/promise
|
||||
meta/pkg-index/basic/main)
|
||||
|
||||
(define convert-to-json
|
||||
(match-lambda
|
||||
[(? list? l)
|
||||
(map convert-to-json l)]
|
||||
[(? string? s)
|
||||
s]
|
||||
[(? hash? ht)
|
||||
(for/hash ([(k v) (in-hash ht)])
|
||||
(values (convert-to-json-key k)
|
||||
(convert-to-json v)))]
|
||||
[(? number? n)
|
||||
n]
|
||||
[#f
|
||||
#f]
|
||||
[(? symbol? s)
|
||||
(symbol->string s)]
|
||||
[(? keyword? s)
|
||||
(hasheq 'kw (keyword->string s))]
|
||||
[x
|
||||
(error 'convert-to-json "~e" x)]))
|
||||
(define convert-to-json-key
|
||||
(match-lambda
|
||||
[(? string? s)
|
||||
(string->symbol s)]
|
||||
[(? symbol? s)
|
||||
s]
|
||||
[x
|
||||
(error 'convert-to-json-key "~e" x)]))
|
||||
|
||||
(module+ main
|
||||
(require "common.rkt")
|
||||
|
||||
(define pkg-list
|
||||
(map path->string (directory-list pkgs-path)))
|
||||
|
||||
(define dispatch
|
||||
(pkg-index/basic
|
||||
(λ () pkg-list)
|
||||
(λ (pkg-name)
|
||||
(define ht (file->value (build-path pkgs-path pkg-name)))
|
||||
(hash-set* ht
|
||||
'name pkg-name
|
||||
'tags (hash-ref ht 'tags empty)
|
||||
'authors (author->list (hash-ref ht 'author ""))))))
|
||||
|
||||
(define (url->request u)
|
||||
(make-request #"GET" (string->url u) empty
|
||||
(delay empty) #f "1.2.3.4" 80 "4.3.2.1"))
|
||||
|
||||
(define (cache url file)
|
||||
(define p (build-path static-path file))
|
||||
(make-directory* (path-only p))
|
||||
(with-output-to-file p
|
||||
#:exists 'replace
|
||||
(λ () ((response-output (dispatch (url->request url))) (current-output-port))))
|
||||
(with-output-to-file (path-add-suffix p #".json")
|
||||
#:exists 'replace
|
||||
(λ () (write-json (convert-to-json (file->value p)))))
|
||||
(void))
|
||||
|
||||
(cache "/pkgs" "pkgs")
|
||||
(cache "/pkgs-all" "pkgs-all")
|
||||
(for ([p (in-list pkg-list)])
|
||||
(cache (format "/pkg/~a" p) (format "pkg/~a" p))))
|
39
pkgs/plt-services/meta/pkg-index/official/static/index.html
Normal file
39
pkgs/plt-services/meta/pkg-index/official/static/index.html
Normal file
|
@ -0,0 +1,39 @@
|
|||
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
|
||||
<html>
|
||||
<head>
|
||||
<title>Packages > Search > !main-distribution > !main-tests</title>
|
||||
<script src="/sorttable.js"></script>
|
||||
<script src="http://code.jquery.com/jquery-1.10.1.min.js"></script>
|
||||
<script src="/index.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/style.css">
|
||||
</head>
|
||||
<body>
|
||||
<div class="breadcrumb">
|
||||
<span><a href="/">Packages</a></span> >
|
||||
<span>Search</span>
|
||||
|
||||
<span id="logout">jay.mccarthy@gmail.com | <a href="/curate">curate</a> | <a href="/rss">rss</a> | <a href="/account/login">re-login</a> | <a href="/account/logout">logout</a></span>
|
||||
</div>
|
||||
<div id="menu"><form action="/query/search/!main-distribution/!main-tests">
|
||||
<span class="menu_option"><input name="input_0" type="text"><input type="submit" value="Search"></span><span class="menu_option"><a href="/manage">Manage
|
||||
Your Packages</a></span>
|
||||
</form></div>
|
||||
<p id="search_menu"></p>
|
||||
<table class="packages sortable">
|
||||
<thead><tr>
|
||||
<th>Package</th>
|
||||
<th>Authors</th>
|
||||
<th>Description</th>
|
||||
<th>Tags</th>
|
||||
</tr></thead>
|
||||
<tbody id="packages_table">
|
||||
</tbody>
|
||||
<tfoot></tfoot>
|
||||
</table>
|
||||
<div id="footer">
|
||||
Powered by <a href="http://racket-lang.org">Racket</a> and a
|
||||
mess of ugly JS. Written
|
||||
by <a href="http://faculty.cs.byu.edu/~jay">Jay McCarthy</a>.
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
116
pkgs/plt-services/meta/pkg-index/official/static/index.js
Normal file
116
pkgs/plt-services/meta/pkg-index/official/static/index.js
Normal file
|
@ -0,0 +1,116 @@
|
|||
// xxx curate
|
||||
// xxx rss
|
||||
// xxx re-login
|
||||
// xxx logout
|
||||
// xxx what user am i
|
||||
// xxx manage packages
|
||||
|
||||
$( document ).ready(function() {
|
||||
var search_terms = [ "!main-tests", "!main-distribution" ];
|
||||
|
||||
function addfilterlink ( text, term ) {
|
||||
return [$('<a>', { text: text,
|
||||
href: "javascript:void(0)",
|
||||
click: function () {
|
||||
search_terms.push(term);
|
||||
evaluate_search();
|
||||
} } ),
|
||||
" "
|
||||
];
|
||||
};
|
||||
function removefilterlink ( text, term ) {
|
||||
return [$('<a>', { text: text,
|
||||
href: "javascript:void(0)",
|
||||
click: function () {
|
||||
search_terms = $.grep( search_terms, function (v) { return v != term } );
|
||||
evaluate_search();
|
||||
} } ),
|
||||
" "
|
||||
];
|
||||
};
|
||||
|
||||
$.getJSON( "/pkgs-all.json", function( resp ) {
|
||||
var names = [];
|
||||
$.each(resp, function(key, value) { names.push(key) });
|
||||
var snames = names.sort(function(a,b) {
|
||||
return ((a < b) ? -1 : ((a > b) ? 1 : 0));
|
||||
})
|
||||
|
||||
var now = new Date().getTime() / 1000;
|
||||
|
||||
$.each( snames,
|
||||
function (name_i) {
|
||||
var name = snames[name_i];
|
||||
var value = resp[name];
|
||||
|
||||
$('<tr>',
|
||||
{ class: ((now - (60*60*24*2)) < value['last-updated'] ? "recent" : "old") }).
|
||||
data( "obj", value).append(
|
||||
$('<td>').html( $('<a>', { text: value['name'],
|
||||
href: "javascript:void(0)",
|
||||
click: function () {
|
||||
// XXX open up a subwindow
|
||||
console.log(value);
|
||||
} } ) ),
|
||||
$('<td>').append( $.map( value['authors'], function ( author, i ) {
|
||||
return addfilterlink ( author, "author:" + author );
|
||||
} ) ),
|
||||
$('<td>').text( value['description'] ),
|
||||
$('<td>').append( $.map( value['tags'], function ( tag, i ) {
|
||||
return addfilterlink ( tag, tag );
|
||||
} ) )).appendTo('#packages_table');
|
||||
});
|
||||
|
||||
evaluate_search();
|
||||
});
|
||||
|
||||
function evaluate_search_term( value, term ) {
|
||||
if ( term == ":error:") {
|
||||
return value['checksum-error'];
|
||||
} else if ( term == ":no-tag:") {
|
||||
return value['tags'].length == 0;
|
||||
} else if ( term.substring(0, 5) == "ring:") {
|
||||
return value['ring'] == term.substring(5);
|
||||
} else if ( term.substring(0, 7) == "author:") {
|
||||
return ($.inArray( term.substring(7), value['authors'] ) != -1);
|
||||
} else if ( term.charAt(0) == "!" ) {
|
||||
return ! evaluate_search_term( value, term.substring(1) );
|
||||
} else if ( $.inArray( term, value['tags']) != -1 ) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function evaluate_search () {
|
||||
$.each( $('#packages_table tr'), function (key, dom) {
|
||||
var value = $(dom).data("obj");
|
||||
var show = true;
|
||||
|
||||
for (termi in search_terms) {
|
||||
var term = search_terms[termi];
|
||||
if ( ! evaluate_search_term( value, term ) ) {
|
||||
show = false;
|
||||
}
|
||||
}
|
||||
|
||||
if ( show ) {
|
||||
$(dom).show();
|
||||
} else {
|
||||
$(dom).hide();
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
// xxx handle search button
|
||||
|
||||
// xxx update menu available
|
||||
$("#search_menu").html("").append( $.map( search_terms, function ( term, i ) {
|
||||
return removefilterlink ( term, term );
|
||||
} ) );
|
||||
|
||||
$("#packages_table tr:visible:even").removeClass("even");
|
||||
$("#packages_table tr:visible:odd").addClass("even");
|
||||
};
|
||||
|
||||
});
|
|
@ -1,42 +1,21 @@
|
|||
function TocviewToggle(glyphid, id) {
|
||||
var glyph = document.getElementById(glyphid);
|
||||
var s = document.getElementById(id).style;
|
||||
var expand = s.display == "none";
|
||||
s.display = expand ? "block" : "none";
|
||||
glyph.innerHTML = expand ? "▼" : "►";
|
||||
}
|
||||
|
||||
function ToggleOn(id) {
|
||||
var s = document.getElementById(id).style;
|
||||
var li = document.getElementById("li" + id);
|
||||
s.display = "block";
|
||||
li.setAttribute("class", "tab-selected");
|
||||
}
|
||||
function ToggleOff(id) {
|
||||
var s = document.getElementById(id).style;
|
||||
var li = document.getElementById("li" + id);
|
||||
s.display = "none";
|
||||
li.setAttribute("class", "");
|
||||
}
|
||||
|
||||
/*
|
||||
SortTable
|
||||
version 2
|
||||
7th April 2007
|
||||
Stuart Langridge, http://www.kryogenix.org/code/browser/sorttable/
|
||||
|
||||
|
||||
Instructions:
|
||||
Download this file
|
||||
Add <script src="sorttable.js"></script> to your HTML
|
||||
Add class="sortable" to any table you'd like to make sortable
|
||||
Click on the headers to sort
|
||||
|
||||
|
||||
Thanks to many, many people for contributions and suggestions.
|
||||
Licenced as X11: http://www.kryogenix.org/code/browser/licence.html
|
||||
This basically means: do what you want with it.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
var stIsIE = /*@cc_on!@*/false;
|
||||
|
||||
sorttable = {
|
||||
|
@ -47,19 +26,19 @@ sorttable = {
|
|||
arguments.callee.done = true;
|
||||
// kill the timer
|
||||
if (_timer) clearInterval(_timer);
|
||||
|
||||
|
||||
if (!document.createElement || !document.getElementsByTagName) return;
|
||||
|
||||
|
||||
sorttable.DATE_RE = /^(\d\d?)[\/\.-](\d\d?)[\/\.-]((\d\d)?\d\d)$/;
|
||||
|
||||
|
||||
forEach(document.getElementsByTagName('table'), function(table) {
|
||||
if (table.className.search(/\bsortable\b/) != -1) {
|
||||
sorttable.makeSortable(table);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
},
|
||||
|
||||
|
||||
makeSortable: function(table) {
|
||||
if (table.getElementsByTagName('thead').length == 0) {
|
||||
// table doesn't have a tHead. Since it should have, create one and
|
||||
|
@ -70,9 +49,9 @@ sorttable = {
|
|||
}
|
||||
// Safari doesn't support table.tHead, sigh
|
||||
if (table.tHead == null) table.tHead = table.getElementsByTagName('thead')[0];
|
||||
|
||||
|
||||
if (table.tHead.rows.length != 1) return; // can't cope with two header rows
|
||||
|
||||
|
||||
// Sorttable v1 put rows with a class of "sortbottom" at the bottom (as
|
||||
// "total" rows, for example). This is B&R, since what you're supposed
|
||||
// to do is put them in a tfoot. So, if there are sortbottom rows,
|
||||
|
@ -94,7 +73,7 @@ sorttable = {
|
|||
}
|
||||
delete sortbottomrows;
|
||||
}
|
||||
|
||||
|
||||
// work through each column and calculate its type
|
||||
headrow = table.tHead.rows[0].cells;
|
||||
for (var i=0; i<headrow.length; i++) {
|
||||
|
@ -110,10 +89,10 @@ sorttable = {
|
|||
// make it clickable to sort
|
||||
headrow[i].sorttable_columnindex = i;
|
||||
headrow[i].sorttable_tbody = table.tBodies[0];
|
||||
dean_addEvent(headrow[i],"click", function(e) {
|
||||
dean_addEvent(headrow[i],"click", sorttable.innerSortFunction = function(e) {
|
||||
|
||||
if (this.className.search(/\bsorttable_sorted\b/) != -1) {
|
||||
// if we're already sorted by this column, just
|
||||
// if we're already sorted by this column, just
|
||||
// reverse the table, which is quicker
|
||||
sorttable.reverse(this.sorttable_tbody);
|
||||
this.className = this.className.replace('sorttable_sorted',
|
||||
|
@ -126,7 +105,7 @@ sorttable = {
|
|||
return;
|
||||
}
|
||||
if (this.className.search(/\bsorttable_sorted_reverse\b/) != -1) {
|
||||
// if we're already sorted by this column in reverse, just
|
||||
// if we're already sorted by this column in reverse, just
|
||||
// re-reverse the table, which is quicker
|
||||
sorttable.reverse(this.sorttable_tbody);
|
||||
this.className = this.className.replace('sorttable_sorted_reverse',
|
||||
|
@ -138,7 +117,7 @@ sorttable = {
|
|||
this.appendChild(sortfwdind);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// remove sorttable_sorted classes
|
||||
theadrow = this.parentNode;
|
||||
forEach(theadrow.childNodes, function(cell) {
|
||||
|
@ -151,7 +130,7 @@ sorttable = {
|
|||
if (sortfwdind) { sortfwdind.parentNode.removeChild(sortfwdind); }
|
||||
sortrevind = document.getElementById('sorttable_sortrevind');
|
||||
if (sortrevind) { sortrevind.parentNode.removeChild(sortrevind); }
|
||||
|
||||
|
||||
this.className += ' sorttable_sorted';
|
||||
sortfwdind = document.createElement('span');
|
||||
sortfwdind.id = "sorttable_sortfwdind";
|
||||
|
@ -173,18 +152,18 @@ sorttable = {
|
|||
/* and comment out this one */
|
||||
row_array.sort(this.sorttable_sortfunction);
|
||||
row_array.reverse();
|
||||
|
||||
|
||||
tb = this.sorttable_tbody;
|
||||
for (var j=0; j<row_array.length; j++) {
|
||||
tb.appendChild(row_array[j][1]);
|
||||
}
|
||||
|
||||
|
||||
delete row_array;
|
||||
});
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
guessType: function(table, column) {
|
||||
// guess the type of a column based on its first non-blank row
|
||||
sortfn = sorttable.sort_alpha;
|
||||
|
@ -194,7 +173,7 @@ sorttable = {
|
|||
if (text.match(/^-?[£$¤]?[\d,.]+%?$/)) {
|
||||
return sorttable.sort_numeric;
|
||||
}
|
||||
// check for a date: dd/mm/yyyy or dd/mm/yy
|
||||
// check for a date: dd/mm/yyyy or dd/mm/yy
|
||||
// can have / or . or - as separator
|
||||
// can be mm/dd as well
|
||||
possdate = text.match(sorttable.DATE_RE)
|
||||
|
@ -217,17 +196,19 @@ sorttable = {
|
|||
}
|
||||
return sortfn;
|
||||
},
|
||||
|
||||
|
||||
getInnerText: function(node) {
|
||||
// gets the text we want to use for sorting for a cell.
|
||||
// strips leading and trailing whitespace.
|
||||
// this is *not* a generic getInnerText function; it's special to sorttable.
|
||||
// for example, you can override the cell text with a customkey attribute.
|
||||
// it also gets .value for <input> fields.
|
||||
|
||||
|
||||
if (!node) return "";
|
||||
|
||||
hasInputs = (typeof node.getElementsByTagName == 'function') &&
|
||||
node.getElementsByTagName('input').length;
|
||||
|
||||
|
||||
if (node.getAttribute("sorttable_customkey") != null) {
|
||||
return node.getAttribute("sorttable_customkey");
|
||||
}
|
||||
|
@ -262,7 +243,7 @@ sorttable = {
|
|||
}
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
reverse: function(tbody) {
|
||||
// reverse the rows in a tbody
|
||||
newrows = [];
|
||||
|
@ -274,14 +255,14 @@ sorttable = {
|
|||
}
|
||||
delete newrows;
|
||||
},
|
||||
|
||||
|
||||
/* sort functions
|
||||
each sort function takes two parameters, a and b
|
||||
you are comparing a[0] and b[0] */
|
||||
sort_numeric: function(a,b) {
|
||||
aa = parseFloat(a[0].replace(/[^0-9.-]/g,''));
|
||||
if (isNaN(aa)) aa = 0;
|
||||
bb = parseFloat(b[0].replace(/[^0-9.-]/g,''));
|
||||
bb = parseFloat(b[0].replace(/[^0-9.-]/g,''));
|
||||
if (isNaN(bb)) bb = 0;
|
||||
return aa-bb;
|
||||
},
|
||||
|
@ -320,7 +301,7 @@ sorttable = {
|
|||
if (dt1<dt2) return -1;
|
||||
return 1;
|
||||
},
|
||||
|
||||
|
||||
shaker_sort: function(list, comp_func) {
|
||||
// A stable sort function to allow multi-level sorting of data
|
||||
// see: http://en.wikipedia.org/wiki/Cocktail_sort
|
||||
|
@ -350,7 +331,7 @@ sorttable = {
|
|||
b++;
|
||||
|
||||
} // while(swap)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ******************************************************************
|
||||
|
|
|
@ -51,7 +51,7 @@ table.packages thead tr {
|
|||
background: #FFCC66;
|
||||
}
|
||||
|
||||
table.packages tbody tr:nth-child(2n) {
|
||||
table.packages tbody tr.even {
|
||||
background: #F5F5DC;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue
Block a user