Skip to content

Instantly share code, notes, and snippets.

@thedeemon
Created January 2, 2014 05:39
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save thedeemon/8215463 to your computer and use it in GitHub Desktop.
Save thedeemon/8215463 to your computer and use it in GitHub Desktop.
import std.stdio, std.net.curl, std.algorithm, std.range, std.array, std.string, std.typecons, std.conv, std.math;
enum choco_xml = "choco.xml";
struct TagReader {
string data, start, end, cur;
bool empty() { return data is null; }
string front() { return cur; }
TagReader popFront()
{
if (findSkip(data, start)) {
auto a = findSplit(data, end);
if (!a[1].empty) {
cur = a[0]; data = a[2]; return this;
}
}
data = null; cur = null; return this;
}
TagReader save() { return TagReader(data, start, end, cur); }
}
TagReader readTags(string text, string startTag, string endTag)
{
return TagReader(text, startTag, endTag).popFront;
}
string getNextUrl(string text)
{
auto urls = readTags(text, "<link rel=\"next\" href=\"", "\"");
return urls.empty ? null : urls.front.replace("&amp;", "&");
}
void downloadXML()
{
auto f = File(choco_xml, "w");
string url = "http://chocolatey.org/api/v2/Packages?&$filter=IsLatestVersion";
while(url !is null) {
writeln(url, "...");
string text = cast(string)get(url);
f.rawWrite(text);
url = getNextUrl(text);
}
}
void outputCloud(R)(R list) // range of tuples (name, fontSize)
{
writeln("<html>");
foreach(t; list)
writeln("<font size=\"", t[1],"\"> <a href=\"http://chocolatey.org/packages?q=", t[0], "\">", t[0], "</a> </font>&nbsp;");
writeln("</html>");
}
class Tag {
string tag;
string[] packages;
this(string name) { tag = name; }
}
void showTags()
{
Tag[string] allTags;
auto entries = std.file.readText(choco_xml).readTags("<entry>", "</entry>");
foreach(entry; entries) {
auto title = readTags(entry, "<title type=\"text\">", "</title>");
auto tagz = readTags(entry, "<d:Tags xml:space=\"preserve\">", "</d:Tags>");
if (title.empty || tagz.empty) continue;
foreach(tag; tagz.front.strip.splitter(' ').map!(s => s[$-1] == ',' ? s[0..$-1] : s)) {
auto taglc = toLower(tag);
if (taglc !in allTags)
allTags[taglc] = new Tag(tag);
allTags[taglc].packages ~= title.front;
}
}
auto tags = allTags.values;
sort!("a.tag.toLower < b.tag.toLower")(tags);
tags.map!(t => tuple(t.tag, 3 + cast(int) sqrt(cast(real)t.packages.length))).outputCloud;
}
void showPackages()
{
auto entries = std.file.readText(choco_xml).readTags("<entry>", "</entry>").map!((entry)
{
auto title = readTags(entry, "<title type=\"text\">", "</title>");
auto num = readTags(entry, "<d:DownloadCount m:type=\"Edm.Int32\">", "</d:D");
return tuple(title.front, num.front.to!real);
});
auto k = entries.map!(e => e[1]).reduce!max / 256.0;
entries.map!(e => tuple(e[0], 3 + cast(int)sqrt(e[1]/k))).outputCloud;
}
void main(string[] argv)
{
if (argv.length < 2) return writeln("choco {load|tags|names}");
switch(argv[1]) {
case "load": return downloadXML();
case "tags": return showTags();
case "names": return showPackages();
default: writeln("unknown command");
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment