Skip to content


Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
tree: 4e4233bd73
Fetching contributors…

Cannot retrieve contributors at this time

executable file 304 lines (244 sloc) 8.679 kb
#!/usr/bin/env python
import sys
import os.path
from subprocess import Popen, PIPE
import re
import json
from r2.lib.translation import iter_langs
if __name__ != "__main__":
from pylons import g, c
STATIC_ROOT = g.paths["static_files"]
REDDIT_ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
STATIC_ROOT = os.path.join(REDDIT_ROOT, "public")
script_tag = '<script type="text/javascript" src="{src}"></script>\n'
inline_script_tag = '<script type="text/javascript">{content}</script>\n'
class ClosureError(Exception): pass
class ClosureCompiler(object):
def __init__(self, jarpath, args=None):
self.jarpath = jarpath
self.args = args or []
def _run(self, data, out=PIPE, args=None, expected_code=0):
args = args or []
p = Popen(["java", "-jar", self.jarpath] + self.args + args,
stdin=PIPE, stdout=out, stderr=PIPE)
out, msg = p.communicate(data)
if p.returncode != expected_code:
raise ClosureError(msg)
return out, msg
def compile(self, data, dest, args=None):
"""Run closure compiler on a string of source code `data`, writing the
result to output file `dest`. A ClosureError exception will be raised if
the operation is unsuccessful."""
return self._run(data, dest, args)[0]
class Source(object):
"""An abstract collection of JavaScript code."""
def get_source(self):
"""Return the full JavaScript source code."""
raise NotImplementedError
def use(self):
"""Return HTML to insert the JavaScript source inside a template."""
raise NotImplementedError
def dependencies(self):
raise NotImplementedError
def outputs(self):
raise NotImplementedError
class FileSource(Source):
"""A JavaScript source file on disk."""
def __init__(self, name): = name
def get_source(self):
return open(self.path).read()
def path(self):
"""The path to the source file on the filesystem."""
return os.path.join(STATIC_ROOT, "static", "js",
def use(self):
from r2.lib.template_helpers import static
path = [g.static_path,]
if g.uncompressedJS:
path.insert(1, "js")
return script_tag.format(src=static(os.path.join(*path)))
def dependencies(self):
return [self.path]
class Module(Source):
"""A module of JS code consisting of a collection of sources."""
def __init__(self, name, *sources): = name
self.sources = []
sources = sources or (name,)
for source in sources:
if not isinstance(source, Source):
source = FileSource(source)
def get_source(self):
return ";".join(s.get_source() for s in self.sources)
def path(self):
"""The destination path of the module file on the filesystem."""
return os.path.join(STATIC_ROOT, "static",
def build(self, closure):
print >> sys.stderr, "Compiling {0}...".format(,
with open(self.path, "w") as out:
closure.compile(self.get_source(), out)
print >> sys.stderr, " done."
def use(self):
from r2.lib.template_helpers import static
if g.uncompressedJS:
return "".join(source.use() for source in self.sources)
return script_tag.format(src=static(
def dependencies(self):
deps = []
for source in self.sources:
return deps
def outputs(self):
return [self.path]
class StringsSource(Source):
"""A virtual source consisting of localized strings from r2.lib.strings."""
def __init__(self, lang=None, keys=None, prepend="r.strings = "):
self.lang = lang
self.keys = keys
self.prepend = prepend
def get_source(self):
from pylons.i18n import get_lang
from r2.lib import strings, translation
if self.lang:
old_lang = get_lang()
data = {}
if self.keys is not None:
for key in self.keys:
data[key] = strings.strings[key]
data = dict(strings.strings)
output = self.prepend + json.dumps(data) + "\n"
if self.lang:
return output
def use(self):
return inline_script_tag.format(content=self.get_source())
class LocalizedModule(Module):
"""A module that is localized with r2.lib.strings.
References to `r.strings.<string>` are parsed out of the module source.
A StringsSource is created and included which contains localized versions
of the strings referenced in the module.
def languagize_path(path, lang):
path_name, path_ext = os.path.splitext(path)
return path_name + "." + lang + path_ext
def build(self, closure):, closure)
reddit_source = open(self.path).read()
string_keys = re.findall("r\.strings\.([\w$_]+)", reddit_source)
print >> sys.stderr, "Creating language-specific files:"
for lang, unused in iter_langs():
strings = StringsSource(lang, string_keys)
source = strings.get_source()
lang_path = LocalizedModule.languagize_path(self.path, lang)
# make sure we're not rewriting a different mangled file
# via symlink
if os.path.islink(lang_path):
with open(lang_path, "w") as out:
print >> sys.stderr, " " + lang_path
def use(self):
from pylons.i18n import get_lang
from r2.lib.template_helpers import static
embed = Module.use(self)
if g.uncompressedJS:
return embed + StringsSource().use()
url = LocalizedModule.languagize_path(, get_lang()[0])
return script_tag.format(src=static(url))
def outputs(self):
for lang, unused in iter_langs():
yield LocalizedModule.languagize_path(self.path, lang)
class JQuery(Module):
def __init__(self, cdn_src=None):
Module.__init__(self, os.path.join("js", "lib", "jquery.js"))
self.cdn_src = cdn_src or ""
def build(self, closure):
def use(self):
from r2.lib.template_helpers import static
if or c.user.pref_local_js:
return script_tag.format(src=static(
ext = ".js" if g.uncompressedJS else ".min.js"
return script_tag.format(src=self.cdn_src+ext)
def dependencies(self):
return []
def outputs(self):
return []
module = {}
module["jquery"] = JQuery()
module["reddit"] = LocalizedModule("reddit.js",
module["mobile"] = LocalizedModule("mobile.js",
module["button"] = Module("button.js",
module["sponsored"] = Module("sponsored.js",
module["flot"] = Module("jquery.flot.js",
def use(*names):
return "\n".join(module[name].use() for name in names)
commands = {}
def build_command(fn):
commands[fn.__name__] = fn
return fn
def enumerate_modules():
for m in module:
print m
def dependencies(name):
for dep in module[name].dependencies:
print dep
def enumerate_outputs():
for m in module.itervalues():
for output in m.outputs:
print output
def build_module(name):
closure = ClosureCompiler("r2/lib/contrib/closure_compiler/compiler.jar")
if __name__ == "__main__":
Jump to Line
Something went wrong with that request. Please try again.