summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLuke Shumaker <LukeShu@sbcglobal.net>2013-07-14 15:04:01 -0600
committerLuke Shumaker <lukeshu@parabola.nu>2018-01-15 21:37:30 -0500
commit5a29ccbc78b8a222c16840ae067ce64f60507539 (patch)
treecd821c326e6c1cc51dc5013b7ea2c79eefe60174
parent72ddf3b134a21896f40c94e8a9c7173f4274b7fe (diff)
Add a Makefile to download 3rd-party assets, and generate derived files
The goal is to generate the *exact* files that are already in git. This is important, because it lets us verify that minified files that are checked in truly are created from the sources that they claim to be. Reproducible builds, yo. I ran `make clean && make && git add .` before committing this. And none of the files changed! Long-term, it might be better to build this into the normal Django staticfiles pipeline. But for now, I wanted to be able to identify exactly how everything was created, as it is now.
-rw-r--r--Makefile161
-rw-r--r--Makefile.d/bootstrap-typeahead.js.patch38
-rw-r--r--Makefile.d/homepage.js.in36
-rw-r--r--Makefile.d/jquery-1.8.3.min.js.preamble1
-rw-r--r--Makefile.d/jquery.tablesorter-2.7.min.js.preamble4
-rw-r--r--Makefile.d/konami.js.patch46
6 files changed, 286 insertions, 0 deletions
diff --git a/Makefile b/Makefile
new file mode 100644
index 00000000..1a077637
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,161 @@
+# The idea here is to be able to re-generate the exact Javascript
+# files as they exist in git. This means munging whitespace in weird
+# ways, using specific versions of various JS minimizers...
+
+# Dependencies:
+# - bsdtar
+# - coreutils
+# - gitget <https://git.parabola.nu/packages/libretools.git/tree/src/gitget/gitget>
+# - java (for closure-compiler)
+# - node (for UglifyJS 1)
+# - npm (for UglifyJS 2)
+# - patch
+# - perl
+# - pngcrush
+# - sed
+# - wget
+
+# Where are we?
+dl-cache = ../download-cache
+www = $(dl-cache)/www
+bin = $(dl-cache)/bin
+
+# What versions of 3rd party libraries are we using?
+jquery-ver=1.8.3
+bootstrap-ver=2.1.1
+tablesorter-ver=2.7
+d3-ver=3.0.6
+konami-ver=c0f686e647765860ff4d2fcb7b48122785432b75
+
+targets = \
+ sitestatic/rss.png \
+ sitestatic/rss@2x.png \
+ sitestatic/bootstrap-typeahead.js \
+ sitestatic/homepage.js \
+ sitestatic/jquery-$(jquery-ver).min.js \
+ sitestatic/jquery.tablesorter-$(tablesorter-ver).js \
+ sitestatic/jquery.tablesorter-$(tablesorter-ver).min.js \
+ sitestatic/konami.min.js \
+ visualize/static/d3-$(d3-ver).js \
+ visualize/static/d3-$(d3-ver).min.js \
+ retro/static/2013/bootstrap-typeahead.min.1aacd3d7f4db.js \
+ retro/static/2013/konami.min.e165c814457d.js
+
+
+# The base rules
+
+all: $(targets)
+.PHONY: all
+
+js-basenames = $(sort $(patsubst %.min,%,$(patsubst %.js,%,$(filter %.js,$(targets)))))
+generated = $(sort $(targets) $(foreach f,$(js-basenames),$f.js $f.min.js))
+clean:
+ rm -f -- $(generated)
+.PHONY: clean
+
+# Make directories
+$(dl-cache) $(bin):
+ mkdir -p '$@'
+
+# Don't have non-minimized .js stick around unless we asked for them.
+.INTERMEDIATE: $(filter-out $(targets),$(generated))
+
+# Turn on sane error handling
+.DELETE_ON_ERROR:
+
+
+# How to download files
+
+ mangle = $(subst %,^25,$(subst :,^3A,$(subst =,^3D,$(subst ^,^5E,$1))))
+unmangle = $(subst ^5E,^,$(subst ^3D,=,$(subst ^3A,:,$(subst ^25,%,$1))))
+
+$(www)/http/%:
+ mkdir -p '$(@D)'
+ wget 'http://$(call unmangle,$*)' -O '$@'
+ test -f '$@' && touch '$@'
+
+$(www)/https/%:
+ mkdir -p '$(@D)'
+ wget 'https://$(call unmangle,$*)' -O '$@'
+ test -f '$@' && touch '$@'
+
+$(www)/git/%:
+ mkdir -p '$(@D)'
+ gitget checkout 'git://$(call unmangle,$*)' '$@' || { rm -rf -- '$@'; false; }
+ test -d '$@' && touch '$@' || { rm -rf -- '$@'; false; }
+
+
+# How to install any of the minifiers in use
+
+# Any of the UglifyJS 1.3.x releases will produce the same output for these inputs
+$(bin)/uglifyjs-1.3: $(www)/git/github.com/mishoo/UglifyJS.git\#tag=v1.3.5 | $(bin)
+ printf '%s\n' '#!/bin/sh' 'exec $</bin/uglifyjs --no-copyright --ascii --max-line-len 0 "$$@"' | install -m755 /dev/stdin '$@'
+
+# Any of the UglifyJS 2.2.x releases will produce the same output for these inputs
+$(dl-cache)/uglifyjs-2.2: $(www)/git/github.com/mishoo/UglifyJS2.git\#tag=v2.2.5 | $(dl-cache)
+ cp -r $< $@ || { rm -rf -- '$@'; false; }
+ cd $@ && npm install || { rm -rf -- '$@'; false; }
+$(bin)/uglifyjs-2.2: $(dl-cache)/uglifyjs-2.2 | $(bin)
+ printf '%s\n' '#!/bin/sh' 'exec $</bin/uglifyjs --mangle --compress -- "$$@"' | install -m755 /dev/stdin '$@'
+
+# Closure compiler 20121212 produces the same output
+$(dl-cache)/unzip/compiler-20121212/%: $(www)/https/web.archive.org/web/20151226141014/https^3A//closure-compiler.googlecode.com/files/compiler-20121212.tar.gz
+ mkdir -p '$(@D)'
+ bsdtar xfO '$<' '$*' > '$@'
+$(bin)/closure-compiler: $(dl-cache)/unzip/compiler-20121212/compiler.jar | $(bin)
+ printf '%s\n' '#!/bin/sh' 'exec java -jar $< "$$@"' | install -m755 /dev/stdin '$@'
+
+
+# The meat of the Makefile
+
+# Downloaded images
+$(dl-cache)/unzip/Feedicons_v.2/%: $(www)/https/web.archive.org/web/20120514074507/http^3A//www.zeusboxstudio.com/file_download/1/Feedicons_v.2.zip
+ mkdir -p '$(@D)'
+ bsdtar xfO $< 'Feedicons v.2/$*' > '$@'
+sitestatic/rss.png: $(dl-cache)/unzip/Feedicons_v.2/RSS_16.png
+ cp $< $@
+sitestatic/rss@2x.png: $(dl-cache)/unzip/Feedicons_v.2/RSS_32.png
+ pngcrush $< $@
+
+# Non-minified JavaScript
+sitestatic/bootstrap-typeahead.js: sitestatic/%: $(www)/https/raw.github.com/twitter/bootstrap/v$(bootstrap-ver)/js/% Makefile.d/%.patch
+ cp $< $@
+ patch -i Makefile.d/$*.patch $@
+sitestatic/jquery-$(jquery-ver).js: sitestatic/%: $(www)/http/code.jquery.com/%
+ cp $< $@
+sitestatic/jquery.tablesorter-$(tablesorter-ver).js: $(www)/https/raw.github.com/Mottie/tablesorter/v$(tablesorter-ver)/js/jquery.tablesorter.js
+ cp $< $@
+sitestatic/konami.js: sitestatic/%: $(www)/https/raw.github.com/snaptortoise/konami-js/$(konami-ver)/% Makefile.d/%.patch
+ cp $< $@
+ patch -i Makefile.d/$*.patch $@
+visualize/static/d3-$(d3-ver).js: %: $(www)/https/raw.github.com/mbostock/d3/v$(d3-ver)/d3.js
+ cp $< $@
+
+# JavaScript minification
+sitestatic/bootstrap-typeahead.min.js: %.min.js: $(bin)/uglifyjs-1.3 %.js
+ $^ > $@
+sitestatic/jquery-$(jquery-ver).min.js: sitestatic/%.min.js: sitestatic/%.js Makefile.d/%.min.js.preamble
+ { cat Makefile.d/$*.min.js.preamble && $(bin)/uglifyjs-1.3 $<; } > $@
+sitestatic/jquery.tablesorter-$(tablesorter-ver).min.js: sitestatic/%.min.js: sitestatic/%.js Makefile.d/%.min.js.preamble $(bin)/closure-compiler
+ @# The tr/sed is to turn all of the newlines except for the last one into spaces
+ { cat Makefile.d/$*.min.js.preamble && $(bin)/closure-compiler $< | tr '\n' ' ' | sed 's, $$,\n,'; } > $@
+sitestatic/konami.min.js: %.min.js: $(bin)/uglifyjs-2.2 %.js
+ @# The sed is to insert newlines and whitespace at the correct places; presumably to match Dan copy/pasting into an editor.
+ $^ | sed -r -e 's:e\.iphone\.stop_x|s=this\.tap===:\n\t&:g' -e 's,return"string",\n&,' | sed -e 's,;$$,,' -e '$$s,$$,\n,' > $@
+visualize/static/d3-$(d3-ver).min.js: %.min.js: $(bin)/uglifyjs-2.2 %.js
+ $^ > $@
+
+# Files that make use of that minified JavaScript
+retro/static/2013/konami.min.e165c814457d.js: sitestatic/konami.min.js
+ cp $< $@
+retro/static/2013/bootstrap-typeahead.min.1aacd3d7f4db.js: sitestatic/bootstrap-typeahead.min.js
+ @# Trim trailing semicolon and newline
+ < $< sed 's/;$$//' | perl -pe 'chomp if eof' > $@
+sitestatic/homepage.js: sitestatic/bootstrap-typeahead.min.js sitestatic/konami.min.js Makefile.d/homepage.js.in
+ { \
+ cat sitestatic/bootstrap-typeahead.min.js && \
+ echo && \
+ sed -e 's,^\s*,,' -e 's,^return.*,&;,' sitestatic/konami.min.js && \
+ echo && \
+ cat Makefile.d/homepage.js.in ; \
+ } > $@
diff --git a/Makefile.d/bootstrap-typeahead.js.patch b/Makefile.d/bootstrap-typeahead.js.patch
new file mode 100644
index 00000000..dfbab80b
--- /dev/null
+++ b/Makefile.d/bootstrap-typeahead.js.patch
@@ -0,0 +1,38 @@
+commit f3e23371fa0473c82c28932e85570d94e5fc232a
+Author: Dan McGee <dan@archlinux.org>
+Date: Mon Sep 24 20:21:15 2012 -0500
+
+ Don't auto-select the first item in typeahead
+
+ This assumption was baked into the Twitter bootstrap JS; kill it so it
+ is still easy to do a freeform search if wanted.
+
+ Signed-off-by: Dan McGee <dan@archlinux.org>
+
+diff --git a/sitestatic/bootstrap-typeahead.js b/sitestatic/bootstrap-typeahead.js
+index c2ccdea..3d355ae 100644
+--- a/sitestatic/bootstrap-typeahead.js
++++ b/sitestatic/bootstrap-typeahead.js
+@@ -45,9 +45,11 @@
+
+ , select: function () {
+ var val = this.$menu.find('.active').attr('data-value')
+- this.$element
+- .val(this.updater(val))
+- .change()
++ if (val) {
++ this.$element
++ .val(this.updater(val))
++ .change()
++ }
+ return this.hide()
+ }
+
+@@ -141,7 +143,6 @@
+ return i[0]
+ })
+
+- items.first().addClass('active')
+ this.$menu.html(items)
+ return this
+ }
diff --git a/Makefile.d/homepage.js.in b/Makefile.d/homepage.js.in
new file mode 100644
index 00000000..2d6f7910
--- /dev/null
+++ b/Makefile.d/homepage.js.in
@@ -0,0 +1,36 @@
+function setupTypeahead() {
+ $('#pkgsearch-field').typeahead({
+ source: function(query, callback) {
+ $.getJSON('/opensearch/packages/suggest', {q: query}, function(data) {
+ callback(data[1]);
+ });
+ },
+ matcher: function(item) { return true; },
+ sorter: function(items) { return items; },
+ menu: '<ul class="pkgsearch-typeahead"></ul>',
+ items: 10,
+ updater: function(item) {
+ $('#pkgsearch-field').val(item);
+ $('#pkgsearch-form').submit();
+ return item;
+ }
+ }).attr('autocomplete', 'off');
+ $('#pkgsearch-field').keyup(function(e) {
+ if (e.keyCode === 13 &&
+ $('ul.pkgsearch-typeahead li.active').size() === 0) {
+ $('#pkgsearch-form').submit();
+ }
+ });
+}
+
+function setupKonami(image_src) {
+ var konami = new Konami(function() {
+ $('#konami').html('<img src="' + image_src + '" alt=""/>');
+ setTimeout(function() {
+ $('#konami').fadeIn(500);
+ }, 500);
+ $('#konami').click(function() {
+ $('#konami').fadeOut(500);
+ });
+ });
+}
diff --git a/Makefile.d/jquery-1.8.3.min.js.preamble b/Makefile.d/jquery-1.8.3.min.js.preamble
new file mode 100644
index 00000000..ae08a973
--- /dev/null
+++ b/Makefile.d/jquery-1.8.3.min.js.preamble
@@ -0,0 +1 @@
+/*! jQuery v1.8.3 jquery.com | jquery.org/license */
diff --git a/Makefile.d/jquery.tablesorter-2.7.min.js.preamble b/Makefile.d/jquery.tablesorter-2.7.min.js.preamble
new file mode 100644
index 00000000..a6e11689
--- /dev/null
+++ b/Makefile.d/jquery.tablesorter-2.7.min.js.preamble
@@ -0,0 +1,4 @@
+/*!
+* TableSorter 2.7 min - Client-side table sorting with ease!
+* Copyright (c) 2007 Christian Bach
+*/
diff --git a/Makefile.d/konami.js.patch b/Makefile.d/konami.js.patch
new file mode 100644
index 00000000..f6df91c4
--- /dev/null
+++ b/Makefile.d/konami.js.patch
@@ -0,0 +1,46 @@
+--- ..//web-cache/www/https/raw.github.com/snaptortoise/konami-js/c0f686e647765860ff4d2fcb7b48122785432b75/konami.js 2015-04-14 17:46:09.372597458 -0400
++++ sitestatic/konami.js 2015-04-14 22:39:28.549281737 -0400
+@@ -56,7 +56,7 @@
+ load: function(link){
+ this.orig_keys = this.keys;
+ konami.addEvent(document,"touchmove",function(e){
+- if(e.touches.length == 1 && konami.iphone.capture==true){
++ if(e.touches.length == 1 && konami.iphone.capture===true){
+ var touch = e.touches[0];
+ konami.iphone.stop_x = touch.pageX;
+ konami.iphone.stop_y = touch.pageY;
+@@ -66,7 +66,7 @@
+ }
+ });
+ konami.addEvent(document,"touchend",function(evt){
+- if (konami.iphone.tap==true) konami.iphone.check_direction(link);
++ if (konami.iphone.tap===true) konami.iphone.check_direction(link);
+ },false);
+ konami.addEvent(document,"touchstart", function(evt){
+ konami.iphone.start_x = evt.changedTouches[0].pageX
+@@ -76,12 +76,12 @@
+ });
+ },
+ check_direction: function(link){
+- x_magnitude = Math.abs(this.start_x-this.stop_x)
+- y_magnitude = Math.abs(this.start_y-this.stop_y)
+- x = ((this.start_x-this.stop_x) < 0) ? "RIGHT" : "LEFT";
+- y = ((this.start_y-this.stop_y) < 0) ? "DOWN" : "UP";
+- result = (x_magnitude > y_magnitude) ? x : y;
+- result = (this.tap==true) ? "TAP" : result;
++ var x_magnitude = Math.abs(this.start_x-this.stop_x)
++ var y_magnitude = Math.abs(this.start_y-this.stop_y)
++ var x = ((this.start_x-this.stop_x) < 0) ? "RIGHT" : "LEFT";
++ var y = ((this.start_y-this.stop_y) < 0) ? "DOWN" : "UP";
++ var result = (x_magnitude > y_magnitude) ? x : y;
++ result = (this.tap===true) ? "TAP" : result;
+
+ if (result==this.keys[0]) this.keys = this.keys.slice(1,this.keys.length)
+ if (this.keys.length==0) {
+@@ -99,4 +99,4 @@
+ }
+
+ return konami;
+-}
+\ No newline at end of file
++}