You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@vcl.apache.org by jf...@apache.org on 2012/07/18 22:49:01 UTC

svn commit: r826248 - in /websites/production/vcl/content: download.cgi download.html ezt.py ezt.pyc mirrors.cgi

Author: jfthomps
Date: Wed Jul 18 20:49:01 2012
New Revision: 826248

Log:
initial add of download scripts


Added:
    websites/production/vcl/content/download.cgi   (with props)
    websites/production/vcl/content/download.html
    websites/production/vcl/content/ezt.py
    websites/production/vcl/content/ezt.pyc   (with props)
    websites/production/vcl/content/mirrors.cgi   (with props)

Added: websites/production/vcl/content/download.cgi
==============================================================================
--- websites/production/vcl/content/download.cgi (added)
+++ websites/production/vcl/content/download.cgi Wed Jul 18 20:49:01 2012
@@ -0,0 +1,6 @@
+#!/bin/sh
+# Wrapper script around mirrors.cgi script
+# (we must change to that directory in order for python to pick up the
+#  python includes correctly)
+cd /www/vcl.apache.org/content
+/www/vcl.apache.org/content/mirrors.cgi $*

Propchange: websites/production/vcl/content/download.cgi
------------------------------------------------------------------------------
    svn:executable = *

Added: websites/production/vcl/content/download.html
==============================================================================
--- websites/production/vcl/content/download.html (added)
+++ websites/production/vcl/content/download.html Wed Jul 18 20:49:01 2012
@@ -0,0 +1,195 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<HTML>
+  <HEAD>
+    <LINK type="text/css" rel="stylesheet" href="http://cwiki.apache.org/VCL/resources/space.css">
+    <STYLE type="text/css">
+      .footer {
+        background-image:      url('https://cwiki.apache.org/confluence/images/border/border_bottom.gif');
+        background-repeat:     repeat-x;
+        background-position:   left top;
+        padding-top:           4px;
+        color:                 #666;
+      }
+      .todo {
+        color: red;
+      }
+    </STYLE>
+    <TITLE>Apache VCL Downloads</TITLE>
+  <META http-equiv="Content-Type" content="text/html;charset=UTF-8"></HEAD>
+  
+
+  <BODY>
+    <TABLE border="0" cellpadding="2" cellspacing="0" width="100%">
+
+      <TR class="topBar">
+        <TD valign="middle" class="topBarDiv" align="left" nowrap>
+          &nbsp;<A href="apache-vcl.html" title="Apache VCL">Apache VCL</A>&nbsp;&gt;&nbsp;<A href="apache-vcl.html" title="Apache VCL">Apache VCL</A>&nbsp;&gt;&nbsp;<A href="releases.html" title="Releases">Releases</A>&nbsp;&gt;&nbsp;<A href="" title="Apache VCL Downloads">Apache VCL Downloads</A>
+        </TD>
+      </TR> 
+    </TABLE>
+
+    <DIV id="PageContent">
+
+      <DIV class="pageheader" style="padding: 6px 0px 0px 0px;">
+        <DIV style="margin: 0px 10px 8px 10px" class="pagetitle"><img src="vcllogo.png" alt="">Apache VCL Downloads</DIV>
+      </DIV>
+      <DIV class="pagesubheading" style="margin: 0px 10px 0px 10px;">
+              </DIV>
+
+      <DIV class="pagecontent">
+        <DIV class="wiki-content">
+
+<H2>Download Links</H2>
+Use the links below to download Apache VCL from one of our mirrors. You <strong>must
+</strong> <a href="downloadvcl.cgi#verify">verify the integrity</a> of the downloaded files using signatures downloaded
+from our main distribution directory, <strong>not</strong> from a mirror.<br>
+<br>
+Only current recommended releases are available on the main distribution site and
+its mirrors. Older releases are available from the archive download site.<br>
+<br>
+Stable Release - Latest Version:
+
+<ul><li>
+  
+<a href="[location]?Preferred=[preferred]&action=download&filename=%2Fvcl%2Fapache-VCL-2.3.tar.bz2">apache-VCL-2.3.tar.bz2</a>
+
+[ <a href="http://www.apache.org/dist/vcl/apache-VCL-2.3.tar.bz2.asc">GPG</a> ]
+[ <a href="http://www.apache.org/dist/vcl/apache-VCL-2.3.tar.bz2.sha1">SHA1</a> ]
+[ <a href="http://www.apache.org/dist/vcl/apache-VCL-2.3.tar.bz2.md5">MD5</a> ]
+(released <strong>UNRELEASED - coming soon</strong>)
+
+</li></ul>
+Previous Releases:
+<ul>
+<li>
+  
+<a href="[location]?Preferred=http://archive.apache.org/dist/&action=download&filename=%2Fincubator%2Fvcl%2Fapache-VCL-2.2.1-incubating.tar.bz2">apache-VCL-2.2.1-incubating.tar.bz2</a>
+
+[ <a href="http://archive.apache.org/dist/incubator/vcl/apache-VCL-2.2.1-incubating.tar.bz2.asc">GPG</a> ]
+[ <a href="http://archive.apache.org/dist/incubator/vcl/apache-VCL-2.2.1-incubating.tar.bz2.sha1">SHA1</a> ]
+[ <a href="http://archive.apache.org/dist/incubator/vcl/apache-VCL-2.2.1-incubating.tar.bz2.md5">MD5</a> ]
+(released 2011-04-08)
+
+</li>
+<li>
+  
+<a href="[location]?Preferred=http://archive.apache.org/dist/&action=download&filename=%2Fincubator%2Fvcl%2Fapache-VCL-2.2-incubating.tar.bz2">apache-VCL-2.2-incubating.tar.bz2</a>
+
+[ <a href="http://archive.apache.org/dist/incubator/vcl/apache-VCL-2.2-incubating.tar.bz2.asc">GPG</a> ]
+[ <a href="http://archive.apache.org/dist/incubator/vcl/apache-VCL-2.2-incubating.tar.bz2.sha1">SHA1</a> ]
+[ <a href="http://archive.apache.org/dist/incubator/vcl/apache-VCL-2.2-incubating.tar.bz2.md5">MD5</a> ]
+(released 2010-10-05)
+</li>
+
+<li>
+  
+<a href="[location]?Preferred=http://archive.apache.org/dist/&action=download&filename=%2Fincubator%2Fvcl%2Fapache-VCL-2.1-incubating.tar.bz2">apache-VCL-2.1-incubating.tar.bz2</a>
+
+[ <a href="http://archive.apache.org/dist/incubator/vcl/apache-VCL-2.1-incubating.tar.bz2.asc">GPG</a> ]
+[ <a href="http://archive.apache.org/dist/incubator/vcl/apache-VCL-2.1-incubating.tar.bz2.sha1">SHA1</a> ]
+[ <a href="http://archive.apache.org/dist/incubator/vcl/apache-VCL-2.1-incubating.tar.bz2.md5">MD5</a> ]
+(released 2009-12-04)
+</li>
+</ul>
+
+<h2>Mirror</h2>
+The currently selected mirror is <strong>[preferred]</strong>.
+
+ If you encounter a problem with this mirror, please select another mirror. If all
+mirrors are failing, there are backup mirrors (at the end of the mirrors list)
+that should be available.<br><br>
+
+<form name="setmirror" method="get" action="[location]">
+Other mirrors: 
+<select name="Preferred">
+[if-any http]
+  [for http]
+    <option value="[http]">[http]</option>
+  [end]
+[end]
+[if-any ftp]
+  [for ftp]
+    <option value="[ftp]">[ftp]</option>
+  [end]
+[end]
+[if-any backup]
+  [for backup]
+    <option value="[backup]">[backup] (backup)</option>
+  [end]
+[end]
+</select>
+<input type="submit" value="Change"></input>
+</form>
+
+<br>
+You may also consult the <a href="http://www.apache.org/mirrors/">complete list of mirrors</a>.
+
+<a name="verify"></a>
+<h2>Verifying the integrity of the files</h2>
+
+<p>It is essential that you verify the integrity of the downloaded files using
+the PGP or MD5 signatures. Security of the mirrors cannot be guaranteed, which means malicious code could be added to the downloads from the mirrors. By verifying the integrity of downloaded release files, you ensure they have not been tainted.</p>
+
+<p>Run the following command to verify the MD5 sum. It should give output similar to "apache-VCL-2.3-incubating.tar.bz2: OK":</p>
+<pre>
+md5sum &#45;c apache-VCL-2.3-incubating.tar.bz2.md5
+</pre
+
+<p>Similarly, Run the following command to verify the SHA1 sum. You should get output similar to "apache-VCL-2.3-incubating.tar.bz2: OK":</p>
+<pre>
+sha1sum &#45;c apache-VCL-2.3-incubating.tar.bz2.sha1
+</pre
+
+<p>To verify the GPG signature (you'll need to have <a href="http://www.gnupg.org/" class="external-link" rel="nofollow">GnuPG</a> installed):</p>
+
+<ol>
+   <li>download and import the VCL KEYS file (if you've imported the KEYS file for previously releases, you do not need to import it again):<br>
+gpg &#45;-import KEYS</li>
+   <li>download the GPG Signature to the same location as the release file</li>
+   <li>from the directory containing both the release file and the GPG signature, run<br>
+gpg &#45;-verify apache-VCL-2.3-incubating.tar.bz2.asc</li>
+
+</ol>
+
+
+<h2>Installation</h2>
+For new installs, visit the on-line installation guide:<br><br>
+Latest Version:
+<ul>
+<li><a href="http://cwiki.apache.org/confluence/display/VCL/VCL+2.3+Installation">Apache VCL 2.3 Installation Guide</a></li>
+</ul>
+<br>
+Previous Versions:
+<ul>
+<li><a href="http://cwiki.apache.org/confluence/display/VCL/VCL+2.3+Installation">Apache VCL 2.2.1 Installation Guide</a></li>
+
+<li><a href="http://cwiki.apache.org/confluence/display/VCL/VCL+2.3+Installation">Apache VCL 2.2 Installation Guide</a></li>
+<li><a href="http://cwiki.apache.org/confluence/display/VCL/VCL+2.3+Installation">Apache VCL 2.1 Installation Guide</a></li>
+</ul>
+
+<h2>Upgrading</h2>
+For upgrades, visit the on-line upgrade guide:<br><br>
+Upgrade to latest version:
+<ul>
+<li><a href="http://cwiki.apache.org/confluence/display/VCL/Upgrade+From+Previous+Version+%282.2.1+to+2.3%29">upgrade 2.2.1 to 2.3</a></li>
+<li><a href="http://cwiki.apache.org/confluence/display/VCL/Upgrade+From+Previous+Version+%282.2+to+2.3%29">upgrade 2.2 to 2.3</a></li>
+<li><a href="http://cwiki.apache.org/confluence/display/VCL/Upgrade+From+Previous+Version+%282.1+to+2.3%29">upgrade 2.1 to 2.3</a></li>
+
+</ul>
+Upgrade really old versions to older versions:
+<ul>
+<li><a href="http://cwiki.apache.org/confluence/display/VCL/Upgrade+From+Previous+Version+%282.2+to+2.2.1%29">upgrade 2.2 to 2.2.1</a></li>
+<li><a href="http://cwiki.apache.org/confluence/display/VCL/Upgrade+From+Previous+Version+%282.1+to+2.2.1%29">upgrade 2.1 to 2.2.1</a></li>
+<li><a href="http://cwiki.apache.org/confluence/display/VCL/Upgrade+From+Previous+Version">upgrade 2.1 to 2.2</a></li>
+</ul>
+
+
+
+        
+        </DIV>
+      </DIV>
+
+    </DIV>
+  </BODY>
+  
+</HTML>

Added: websites/production/vcl/content/ezt.py
==============================================================================
--- websites/production/vcl/content/ezt.py (added)
+++ websites/production/vcl/content/ezt.py Wed Jul 18 20:49:01 2012
@@ -0,0 +1,653 @@
+#!/usr/bin/env python
+"""ezt.py -- EaZy Templating
+
+For documentation, please see: http://code.google.com/p/ezt/wiki/Syntax
+"""
+#
+# Copyright (C) 2001-2011 Greg Stein. All Rights Reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * Redistributions of source code must retain the above copyright
+#   notice, this list of conditions and the following disclaimer.
+#
+# * Redistributions in binary form must reproduce the above copyright
+#   notice, this list of conditions and the following disclaimer in the
+#   documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+# IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+# THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
+# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+# POSSIBILITY OF SUCH DAMAGE.
+#
+#
+# This software is maintained by Greg and is available at:
+#    http://code.google.com/p/ezt/
+#
+
+__author__ = 'Greg Stein'
+__version__ = '1.0'
+__license__ = 'BSD'
+
+import re
+from types import StringType, IntType, FloatType, LongType
+import os
+import urllib
+try:
+  import cStringIO
+except ImportError:
+  import StringIO
+  cStringIO = StringIO
+
+#
+# Formatting types
+#
+FORMAT_RAW = 'raw'
+FORMAT_HTML = 'html'
+FORMAT_XML = 'xml'
+FORMAT_JS = 'js'
+FORMAT_URL = 'url'
+
+#
+# This regular expression matches three alternatives:
+#   expr: NEWLINE | DIRECTIVE | BRACKET | COMMENT
+#   DIRECTIVE: '[' ITEM (whitespace ITEM)* ']
+#   ITEM: STRING | NAME
+#   STRING: '"' (not-slash-or-dquote | '\' anychar)* '"'
+#   NAME: (alphanum | '_' | '-' | '.')+
+#   BRACKET: '[[]'
+#   COMMENT: '[#' not-rbracket* ']'
+#
+# When used with the split() method, the return value will be composed of
+# non-matching text and the three paren groups (NEWLINE, DIRECTIVE and
+# BRACKET). Since the COMMENT matches are not placed into a group, they are
+# considered a "splitting" value and simply dropped.
+#
+_item = r'(?:"(?:[^\\"]|\\.)*"|[-\w.]+)'
+_re_parse = re.compile(r'(\r?\n)|\[(%s(?: +%s)*)\]|(\[\[\])|\[#[^\]]*\]' %
+                       (_item, _item))
+
+_re_args = re.compile(r'"(?:[^\\"]|\\.)*"|[-\w.]+')
+
+# block commands and their argument counts
+_block_cmd_specs = { 'if-index':2, 'for':1, 'is':2, 'define':1, 'format':1 }
+_block_cmds = _block_cmd_specs.keys()
+
+# two regular expressions for compressing whitespace. the first is used to
+# compress any whitespace including a newline into a single newline. the
+# second regex is used to compress runs of whitespace into a single space.
+_re_newline = re.compile('[ \t\r\f\v]*\n\\s*')
+_re_whitespace = re.compile(r'\s\s+')
+
+# this regex is used to substitute arguments into a value. we split the value,
+# replace the relevant pieces, and then put it all back together. splitting
+# will produce a list of: TEXT ( splitter TEXT )*. splitter will be '%' or
+# an integer.
+_re_subst = re.compile('%(%|[0-9]+)')
+
+class Template:
+
+  def __init__(self, fname=None, compress_whitespace=1,
+               base_format=FORMAT_RAW):
+    self.compress_whitespace = compress_whitespace
+    if fname:
+      self.parse_file(fname, base_format)
+
+  def parse_file(self, fname, base_format=FORMAT_RAW):
+    "fname -> a string object with pathname of file containg an EZT template."
+
+    self.parse(_FileReader(fname), base_format)
+
+  def parse(self, text_or_reader, base_format=FORMAT_RAW):
+    """Parse the template specified by text_or_reader.
+
+    The argument should be a string containing the template, or it should
+    specify a subclass of ezt.Reader which can read templates. The base
+    format for printing values is given by base_format.
+    """
+    if not isinstance(text_or_reader, Reader):
+      # assume the argument is a plain text string
+      text_or_reader = _TextReader(text_or_reader)
+
+    self.program = self._parse(text_or_reader,
+                               base_printer=_parse_format(base_format))
+
+  def generate(self, fp, data):
+    if hasattr(data, '__getitem__') or callable(getattr(data, 'keys', None)):
+      # a dictionary-like object was passed. convert it to an
+      # attribute-based object.
+      class _data_ob:
+        def __init__(self, d):
+          vars(self).update(d)
+      data = _data_ob(data)
+
+    ctx = _context()
+    ctx.data = data
+    ctx.for_index = { }
+    ctx.defines = { }
+    self._execute(self.program, fp, ctx)
+
+  def _parse(self, reader, for_names=None, file_args=(), base_printer=None):
+    """text -> string object containing the template.
+
+    This is a private helper function doing the real work for method parse.
+    It returns the parsed template as a 'program'.  This program is a sequence
+    made out of strings or (function, argument) 2-tuples.
+
+    Note: comment directives [# ...] are automatically dropped by _re_parse.
+    """
+
+    filename = reader.filename()
+    # parse the template program into: (TEXT NEWLINE DIRECTIVE BRACKET)* TEXT
+    parts = _re_parse.split(reader.text)
+
+    program = [ ]
+    stack = [ ]
+    if not for_names:
+      for_names = [ ]
+
+    if base_printer is None:
+      base_printer = ()
+    printers = [ base_printer ]
+
+    one_newline_copied = False
+    line_number = 1
+    for i in range(len(parts)):
+      piece = parts[i]
+      which = i % 4  # discriminate between: TEXT NEWLINE DIRECTIVE BRACKET
+      if which == 0:
+        # TEXT. append if non-empty.
+        if piece:
+          if self.compress_whitespace:
+            piece = _re_whitespace.sub(' ', piece)
+          program.append(piece)
+          one_newline_copied = False
+      elif which == 1:
+        # NEWLINE. append unless compress_whitespace requested
+        if piece:
+          line_number += 1
+          if self.compress_whitespace:
+            if not one_newline_copied:
+              program.append('\n')
+              one_newline_copied = True
+          else:
+            program.append(piece)
+      elif which == 3:
+        # BRACKET directive. append '[' if present.
+        if piece:
+          program.append('[')
+          one_newline_copied = False
+      elif piece:
+        # DIRECTIVE is present.
+        one_newline_copied = False
+        args = _re_args.findall(piece)
+        cmd = args[0]
+        if cmd == 'else':
+          if len(args) > 1:
+            raise ArgCountSyntaxError(str(args[1:]), filename, line_number)
+          ### check: don't allow for 'for' cmd
+          idx = stack[-1][1]
+          true_section = program[idx:]
+          del program[idx:]
+          stack[-1][3] = true_section
+        elif cmd == 'end':
+          if len(args) > 1:
+            raise ArgCountSyntaxError(str(args[1:]), filename, line_number)
+          # note: true-section may be None
+          try:
+            cmd, idx, args, true_section, start_line_number = stack.pop()
+          except IndexError:
+            raise UnmatchedEndError(None, filename, line_number)
+          else_section = program[idx:]
+          if cmd == 'format':
+            printers.pop()
+          else:
+            func = getattr(self, '_cmd_' + re.sub('-', '_', cmd))
+            program[idx:] = [ (func, (args, true_section, else_section),
+                               filename, line_number) ]
+            if cmd == 'for':
+              for_names.pop()
+        elif cmd in _block_cmds:
+          if len(args) > _block_cmd_specs[cmd] + 1:
+            raise ArgCountSyntaxError(str(args[1:]), filename, line_number)
+          ### this assumes arg1 is always a ref unless cmd is 'define'
+          if cmd != 'define':
+            args[1] = _prepare_ref(args[1], for_names, file_args)
+
+          # handle arg2 for the 'is' command
+          if cmd == 'is':
+            args[2] = _prepare_ref(args[2], for_names, file_args)
+          elif cmd == 'for':
+            for_names.append(args[1][0])  # append the refname
+          elif cmd == 'format':
+            if args[1][0]:
+              raise BadFormatConstantError(str(args[1:]), filename, line_number)
+            printers.append(_parse_format(args[1][1]))
+
+          # remember the cmd, current pos, args, and a section placeholder
+          stack.append([cmd, len(program), args[1:], None, line_number])
+        elif cmd == 'include' or cmd == 'insertfile':
+          is_insertfile = (cmd == 'insertfile')
+          # extra arguments are meaningless when using insertfile
+          if is_insertfile and len(args) != 2:
+            raise ArgCountSyntaxError(str(args), filename, line_number)
+          if args[1][0] == '"':
+            include_filename = args[1][1:-1]
+            if is_insertfile:
+              program.append(reader.read_other(include_filename).text)
+            else:
+              f_args = [ ]
+              for arg in args[2:]:
+                f_args.append(_prepare_ref(arg, for_names, file_args))
+              program.extend(self._parse(reader.read_other(include_filename),
+                                         for_names, f_args, printers[-1]))
+          else:
+            if len(args) != 2:
+              raise ArgCountSyntaxError(str(args), filename, line_number)
+            if is_insertfile:
+              cmd = self._cmd_insertfile
+            else:
+              cmd = self._cmd_include
+            program.append((cmd,
+                            (_prepare_ref(args[1], for_names, file_args),
+                             reader, printers[-1]), filename, line_number))
+        elif cmd == 'if-any':
+          f_args = [ ]
+          for arg in args[1:]:
+            f_args.append(_prepare_ref(arg, for_names, file_args))
+          stack.append(['if-any', len(program), f_args, None, line_number])
+        else:
+          # implied PRINT command
+          if len(args) > 1:
+            f_args = [ ]
+            for arg in args:
+              f_args.append(_prepare_ref(arg, for_names, file_args))
+            program.append((self._cmd_subst,
+                            (printers[-1], f_args[0], f_args[1:]),
+                            filename, line_number))
+          else:
+            valref = _prepare_ref(args[0], for_names, file_args)
+            program.append((self._cmd_print, (printers[-1], valref),
+                            filename, line_number))
+
+    if stack:
+      raise UnclosedBlocksError('Block opened at line %s' % stack[-1][4],
+                                filename=filename)
+    return program
+
+  def _execute(self, program, fp, ctx):
+    """This private helper function takes a 'program' sequence as created
+    by the method '_parse' and executes it step by step.  strings are written
+    to the file object 'fp' and functions are called.
+    """
+    for step in program:
+      if isinstance(step, StringType):
+        fp.write(step)
+      else:
+        method, method_args, filename, line_number = step
+        method(method_args, fp, ctx, filename, line_number)
+
+  def _cmd_print(self, (transforms, valref), fp, ctx, filename, line_number):
+    value = _get_value(valref, ctx, filename, line_number)
+    # if the value has a 'read' attribute, then it is a stream: copy it
+    if hasattr(value, 'read'):
+      while 1:
+        chunk = value.read(16384)
+        if not chunk:
+          break
+        for t in transforms:
+          chunk = t(chunk)
+        fp.write(chunk)
+    else:
+      for t in transforms:
+        value = t(value)
+      fp.write(value)
+
+  def _cmd_subst(self, (transforms, valref, args), fp, ctx, filename,
+                 line_number):
+    fmt = _get_value(valref, ctx, filename, line_number)
+    parts = _re_subst.split(fmt)
+    for i in range(len(parts)):
+      piece = parts[i]
+      if i%2 == 1 and piece != '%':
+        idx = int(piece)
+        if idx < len(args):
+          piece = _get_value(args[idx], ctx, filename, line_number)
+        else:
+          piece = '<undef>'
+      for t in transforms:
+        piece = t(piece)
+      fp.write(piece)
+
+  def _cmd_include(self, (valref, reader, printer), fp, ctx, filename,
+                   line_number):
+    fname = _get_value(valref, ctx, filename, line_number)
+    ### note: we don't have the set of for_names to pass into this parse.
+    ### I don't think there is anything to do but document it
+    self._execute(self._parse(reader.read_other(fname), base_printer=printer),
+                  fp, ctx)
+
+  def _cmd_insertfile(self, (valref, reader, printer), fp, ctx, filename,
+                      line_number):
+    fname = _get_value(valref, ctx, filename, line_number)
+    fp.write(reader.read_other(fname).text)
+
+  def _cmd_if_any(self, args, fp, ctx, filename, line_number):
+    "If any value is a non-empty string or non-empty list, then T else F."
+    (valrefs, t_section, f_section) = args
+    value = 0
+    for valref in valrefs:
+      if _get_value(valref, ctx, filename, line_number):
+        value = 1
+        break
+    self._do_if(value, t_section, f_section, fp, ctx)
+
+  def _cmd_if_index(self, args, fp, ctx, filename, line_number):
+    ((valref, value), t_section, f_section) = args
+    list, idx = ctx.for_index[valref[0]]
+    if value == 'even':
+      value = idx % 2 == 0
+    elif value == 'odd':
+      value = idx % 2 == 1
+    elif value == 'first':
+      value = idx == 0
+    elif value == 'last':
+      value = idx == len(list)-1
+    else:
+      value = idx == int(value)
+    self._do_if(value, t_section, f_section, fp, ctx)
+
+  def _cmd_is(self, args, fp, ctx, filename, line_number):
+    ((left_ref, right_ref), t_section, f_section) = args
+    right_value = _get_value(right_ref, ctx, filename, line_number)
+    left_value = _get_value(left_ref, ctx, filename, line_number)
+    value = left_value.lower() == right_value.lower()
+    self._do_if(value, t_section, f_section, fp, ctx)
+
+  def _do_if(self, value, t_section, f_section, fp, ctx):
+    if t_section is None:
+      t_section = f_section
+      f_section = None
+    if value:
+      section = t_section
+    else:
+      section = f_section
+    if section is not None:
+      self._execute(section, fp, ctx)
+
+  def _cmd_for(self, args, fp, ctx, filename, line_number):
+    ((valref,), unused, section) = args
+    list = _get_value(valref, ctx, filename, line_number)
+    refname = valref[0]
+    if isinstance(list, StringType):
+      raise NeedSequenceError(refname, filename, line_number)
+    ctx.for_index[refname] = idx = [ list, 0 ]
+    for item in list:
+      self._execute(section, fp, ctx)
+      idx[1] = idx[1] + 1
+    del ctx.for_index[refname]
+
+  def _cmd_define(self, args, fp, ctx, filename, line_number):
+    ((name,), unused, section) = args
+    valfp = cStringIO.StringIO()
+    if section is not None:
+      self._execute(section, valfp, ctx)
+    ctx.defines[name] = valfp.getvalue()
+
+def boolean(value):
+  "Return a value suitable for [if-any bool_var] usage in a template."
+  if value:
+    return 'yes'
+  return None
+
+
+def _prepare_ref(refname, for_names, file_args):
+  """refname -> a string containing a dotted identifier. example:"foo.bar.bang"
+  for_names -> a list of active for sequences.
+
+  Returns a `value reference', a 3-tuple made out of (refname, start, rest),
+  for fast access later.
+  """
+  # is the reference a string constant?
+  if refname[0] == '"':
+    return None, refname[1:-1], None
+
+  parts = refname.split('.')
+  start = parts[0]
+  rest = parts[1:]
+
+  # if this is an include-argument, then just return the prepared ref
+  if start[:3] == 'arg':
+    try:
+      idx = int(start[3:])
+    except ValueError:
+      pass
+    else:
+      if idx < len(file_args):
+        orig_refname, start, more_rest = file_args[idx]
+        if more_rest is None:
+          # the include-argument was a string constant
+          return None, start, None
+
+        # prepend the argument's "rest" for our further processing
+        rest[:0] = more_rest
+
+        # rewrite the refname to ensure that any potential 'for' processing
+        # has the correct name
+        ### this can make it hard for debugging include files since we lose
+        ### the 'argNNN' names
+        if not rest:
+          return start, start, [ ]
+        refname = start + '.' + '.'.join(rest)
+
+  if for_names:
+    # From last to first part, check if this reference is part of a for loop
+    for i in range(len(parts), 0, -1):
+      name = '.'.join(parts[:i])
+      if name in for_names:
+        return refname, name, parts[i:]
+
+  return refname, start, rest
+
+def _get_value((refname, start, rest), ctx, filename, line_number):
+  """(refname, start, rest) -> a prepared `value reference' (see above).
+  ctx -> an execution context instance.
+
+  Does a name space lookup within the template name space.  Active
+  for blocks take precedence over data dictionary members with the
+  same name.
+  """
+  if rest is None:
+    # it was a string constant
+    return start
+
+  # get the starting object
+  if ctx.for_index.has_key(start):
+    list, idx = ctx.for_index[start]
+    ob = list[idx]
+  elif ctx.defines.has_key(start):
+    ob = ctx.defines[start]
+  elif hasattr(ctx.data, start):
+    ob = getattr(ctx.data, start)
+  else:
+    raise UnknownReference(refname, filename, line_number)
+
+  # walk the rest of the dotted reference
+  for attr in rest:
+    try:
+      ob = getattr(ob, attr)
+    except AttributeError:
+      raise UnknownReference(refname, filename, line_number)
+
+  # make sure we return a string instead of some various Python types
+  if isinstance(ob, (IntType, FloatType, LongType)):
+    return str(ob)
+  if ob is None:
+    return ''
+
+  # string or a sequence
+  return ob
+
+def _replace(s, replace_map):
+  for orig, repl in replace_map:
+    s = s.replace(orig, repl)
+  return s
+
+REPLACE_JS_MAP = (
+  ('\\', r'\\'), ('\t', r'\t'), ('\n', r'\n'), ('\r', r'\r'),
+  ('"', r'\x22'), ('\'', r'\x27'), ('&', r'\x26'),
+  ('<', r'\x3c'), ('>', r'\x3e'), ('=', r'\x3d'),
+)
+
+# Various unicode whitespace
+REPLACE_JS_UNICODE_MAP = (
+  (u'\u0085', r'\u0085'), (u'\u2028', r'\u2028'), (u'\u2029', r'\u2029'),
+)
+
+# Why not cgi.escape? It doesn't do single quotes which are occasionally
+# used to contain HTML attributes and event handler definitions (unfortunately)
+REPLACE_HTML_MAP = (
+  ('&', '&amp;'), ('<', '&lt;'), ('>', '&gt;'),
+  ('"', '&quot;'), ('\'', '&#39;'),
+)
+
+def _js_escape(s):
+  s = _replace(s, REPLACE_JS_MAP)
+  ### perhaps attempt to coerce the string to unicode and then replace?
+  if isinstance(s, unicode):
+    s = _replace(s, REPLACE_JS_UNICODE_MAP)
+  return s
+
+def _html_escape(s):
+  return _replace(s, REPLACE_HTML_MAP)
+
+def _url_escape(s):
+  ### quote_plus barfs on non-ASCII characters. According to
+  ### http://www.w3.org/International/O-URL-code.html URIs should be
+  ### UTF-8 encoded first.
+  if isinstance(s, unicode):
+    s = s.encode('utf8')
+  return urllib.quote_plus(s)
+
+FORMATTERS = {
+  FORMAT_RAW: None,
+  FORMAT_HTML: _html_escape,
+  FORMAT_XML: _html_escape,   ### use the same quoting as HTML for now
+  FORMAT_JS: _js_escape,
+  FORMAT_URL: _url_escape,
+}
+
+def _parse_format(format_string=FORMAT_RAW):
+  format_funcs = []
+  try:
+    for fspec in format_string.split(','):
+      format_func = FORMATTERS[fspec]
+      if format_func is not None:
+        format_funcs.append(format_func)
+  except KeyError:
+    raise UnknownFormatConstantError(format_string)
+  return format_funcs
+
+class _context:
+  """A container for the execution context"""
+
+
+class Reader:
+  """Abstract class which allows EZT to detect Reader objects."""
+  def filename(self):
+    return '(%s does not provide filename() method)' % repr(self)
+
+class _FileReader(Reader):
+  """Reads templates from the filesystem."""
+  def __init__(self, fname):
+    self.text = open(fname, 'rb').read()
+    self._dir = os.path.dirname(fname)
+    self.fname = fname
+  def read_other(self, relative):
+    return _FileReader(os.path.join(self._dir, relative))
+  def filename(self):
+    return self.fname
+
+class _TextReader(Reader):
+  """'Reads' a template from provided text."""
+  def __init__(self, text):
+    self.text = text
+  def read_other(self, relative):
+    raise BaseUnavailableError()
+  def filename(self):
+    return '(text)'
+
+
+class EZTException(Exception):
+  """Parent class of all EZT exceptions."""
+  def __init__(self, message=None, filename=None, line_number=None):
+    self.message = message
+    self.filename = filename
+    self.line_number = line_number
+  def __str__(self):
+    ret = []
+    if self.message is not None:
+      ret.append(self.message)
+    if self.filename is not None:
+      ret.append('in file ' + str(self.filename))
+    if self.line_number is not None:
+      ret.append('at line ' + str(self.line_number))
+    return ' '.join(ret)
+
+class ArgCountSyntaxError(EZTException):
+  """A bracket directive got the wrong number of arguments."""
+
+class UnknownReference(EZTException):
+  """The template references an object not contained in the data dictionary."""
+
+class NeedSequenceError(EZTException):
+  """The object dereferenced by the template is no sequence (tuple or list)."""
+
+class UnclosedBlocksError(EZTException):
+  """This error may be simply a missing [end]."""
+
+class UnmatchedEndError(EZTException):
+  """This error may be caused by a misspelled if directive."""
+
+class BaseUnavailableError(EZTException):
+  """Base location is unavailable, which disables includes."""
+
+class BadFormatConstantError(EZTException):
+  """Format specifiers must be string constants."""
+
+class UnknownFormatConstantError(EZTException):
+  """The format specifier is an unknown value."""
+
+
+# --- standard test environment ---
+def test_parse():
+  assert _re_parse.split('[a]') == ['', '[a]', None, '']
+  assert _re_parse.split('[a] [b]') == \
+         ['', '[a]', None, ' ', '[b]', None, '']
+  assert _re_parse.split('[a c] [b]') == \
+         ['', '[a c]', None, ' ', '[b]', None, '']
+  assert _re_parse.split('x [a] y [b] z') == \
+         ['x ', '[a]', None, ' y ', '[b]', None, ' z']
+  assert _re_parse.split('[a "b" c "d"]') == \
+         ['', '[a "b" c "d"]', None, '']
+  assert _re_parse.split(r'["a \"b[foo]" c.d f]') == \
+         ['', '["a \\"b[foo]" c.d f]', None, '']
+
+def _test(argv):
+  import doctest, ezt
+  verbose = "-v" in argv
+  return doctest.testmod(ezt, verbose=verbose)
+
+if __name__ == "__main__":
+  # invoke unit test for this module:
+  import sys
+  sys.exit(_test(sys.argv)[0])

Added: websites/production/vcl/content/ezt.pyc
==============================================================================
Binary file - no diff available.

Propchange: websites/production/vcl/content/ezt.pyc
------------------------------------------------------------------------------
    svn:mime-type = application/octet-stream

Added: websites/production/vcl/content/mirrors.cgi
==============================================================================
--- websites/production/vcl/content/mirrors.cgi (added)
+++ websites/production/vcl/content/mirrors.cgi Wed Jul 18 20:49:01 2012
@@ -0,0 +1,274 @@
+#!/usr/local/bin/python2.7
+# -*- python -*-
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+#
+# This is a Python CGI script that uses EZT to produce templated
+# mirror content and GeoIP to choose the appropriate mirror
+#
+
+import sys
+import os
+import cgi
+import stat
+import random
+import time
+import traceback
+import cStringIO
+
+# Should be installed in the main system library
+import GeoIP
+
+# Insert this directory into PATH so that we can import ezt
+this_dir = os.path.dirname(__file__) or '.'
+sys.path.insert(0, this_dir)
+
+import ezt
+
+
+# Configurable stuff
+MIRRORS_LIST = "/x1/www/www.apache.org/mirrors/mirrors.list"
+DEFAULT_REGION = "us"
+DEFAULT_TEMPLATE = "/x1/www/www.apache.org/dyn/closer.html"
+DEFAULT_LOCATION = "http://www.apache.org/dyn/closer.cgi"
+
+
+def get_region(environ):
+  """Use GeoIP to find the client's country, falling back to
+     DEFAULT_REGION on failure."""
+  try:
+    remote_ip = environ['REMOTE_ADDR'];
+    gi = GeoIP.new(GeoIP.GEOIP_STANDARD)
+    region = gi.country_code_by_addr(remote_ip).lower().strip()
+    if region == 'gb':
+      return 'uk'
+    else:
+      return region
+  except:
+    ### should we log an error here? absorbing without reporting is
+    ### generally bad form.
+    return DEFAULT_REGION
+
+
+def parse_mirrors(filename, country, preferred, mingood):
+  """Parse the mirror database to find the best mirrors for a client.
+
+  The Format of the mirror database is (last two fields are optional):
+  ftp au  ftp://ftp.planetmirror.com/pub/apache/dist/ 1117724635 http://example.com/logo.gif http://example.com/ """
+
+  output = { 'http'   : [ ],
+             'ftp'    : [ ],
+             'backup' : [ ],
+             'preferred' : None,
+             'logo' : None,
+             'link' : None,
+             }
+
+  # Read the mirror database and put it in a list of lists
+  # skip empty lines and comment
+  mirrors = [line.split() for line in open(filename).readlines()
+             if line.strip() and not line.startswith('#')]
+
+  #mirrors.append(['http', 'us', 'http://archive.apache.org/dist/', '9999999999'])
+
+  # Add trailing slashes where missing.  Otherwise,
+  # strcat("http://www.mirror.org", pathinfo=".foo.evil") would link to
+  # http://www.mirror.org.foo.evil
+  for mir in mirrors:
+    if not mir[2].endswith('/'):
+      mir[2] += '/'
+
+  # grab the backup mirrors
+  backupmirrors = [mir for mir in mirrors if mir[1] == 'Backup']
+
+  # Grab the mirrors for the requested country or, failing that,
+  # from the default region (us)
+  for region in (country, DEFAULT_REGION):
+    countrymirrors = [mir for mir in mirrors if mir[1] == region]
+    random.shuffle(countrymirrors)
+    goodmirror = None
+    for mir in countrymirrors:
+      if mir[0] == 'http' and int(mir[3]) > mingood:
+        goodmirror = mir
+        break
+    if goodmirror:
+      break
+
+  # Check if the requested Preferred mirror is in the list
+  # Note the user-requested mirror doesn't have a trailing-slash
+  prefmir = None
+  if preferred:
+    for mir in mirrors:
+      if mir[2] == preferred:
+        prefmir = mir
+        break
+  # Otherwise pick a preferred mirror from our country
+  if not prefmir and goodmirror:
+    prefmir = goodmirror
+  if not prefmir:  # In the worst case, choose a backup
+    prefmir = random.choice(backupmirrors)
+
+  # Record the preferred mirror and, if available, its logo and link
+  # Keep the trailing-slash on the URL (it is later joined to the path_info)
+  output['preferred'] = prefmir[2]
+  if len(prefmir) > 5:
+    output['logo'] = prefmir[4]
+    output['link'] = prefmir[5]
+
+  # Now assemble a list of all the other mirrors.
+  # Keep the trailing-slash on the URL (it is later joined to the path_info)
+  output['http'] = [mir[2] for mir in countrymirrors if mir[0] == 'http']
+  output['ftp'] = [mir[2] for mir in countrymirrors if mir[0] == 'ftp']
+  output['backup'] = [mir[2] for mir in backupmirrors]
+
+  return output
+
+
+def mirrorwrap(environ, start_response):
+  try:
+    return mirrorsapp(environ, start_response)
+  except:
+    status = "500 Oops"
+    response_headers = [("content-type","text/plain")]
+    start_response(status, response_headers, sys.exc_info())
+    return ["Problem running mirror.cgi, contact <in...@apache.org> "
+            "if it persists.\n\n"
+            + traceback.format_exc() ]
+
+
+def locate_template(environ):
+  # Determine the correct template by noting our filesystem location
+  if environ.has_key('ASF_MIRROR_FILENAME'):
+    template_file = environ['ASF_MIRROR_FILENAME'].replace(".cgi", ".html")
+  elif environ.has_key('SCRIPT_FILENAME'):
+    template_file = environ['SCRIPT_FILENAME'].replace(".cgi", ".html")
+  else:
+    template_file = sys.argv[0].replace(".cgi", ".html")
+
+  if not os.path.isfile(template_file):
+    # look in docroot instead if this is in a cgi-bin dir
+    template_file = template_file.replace("/cgi-bin/", "/content/")
+    if not os.path.isfile(template_file):
+      template_file = DEFAULT_TEMPLATE
+
+  return template_file
+
+
+def locate_mirrors(environ):
+  # Allow the MIRRORS_LIST environment variable to override the default
+  mirrors = environ.get('MIRRORS_LIST')
+  if mirrors and os.path.isfile(mirrors):
+    return mirrors
+  return MIRRORS_LIST  # the default
+
+
+def mirrorsapp(environ, start_response):
+  headers = [ ]
+  resp_code = '200 OK'
+
+  # Where is the client coming from
+  region = get_region(environ)
+
+  # Was there a preferred mirror or update requirement?
+  form = cgi.FieldStorage(fp=environ['wsgi.input'],
+                          environ=environ,
+                          keep_blank_values=True)
+  preferred = form.getfirst("Preferred", "")
+  update = form.getfirst("update", "")
+
+  # Get the last update time of the mirror database
+  mirrors = locate_mirrors(environ)
+  base_time = os.path.getmtime(mirrors)
+
+  # convert from YYYYMMDDhhmm to time-since-unix-epoch
+  try:
+    mingood = time.mktime(time.strptime(update, "%Y%m%d%H%M"))
+    # Never use a mirror more than a week old
+    mingood = max(mingood, base_time - 7*24*60*60)
+  except:
+    # if we didn't get a time, or we can't convert it, then
+    # use the time the mirror database was last updated minus 24 hours
+    mingood = base_time - 24*60*60
+
+  # Load the mirrors file and parse it out
+  data = parse_mirrors(mirrors, region, preferred, mingood)
+
+  # ======== new download tracking code ==========
+  action = form.getfirst("action", "")
+  filename = form.getfirst("filename", "")
+  if action == 'download' and filename != '':
+    url = "%s%s" % (data['preferred'][:-1], filename)
+    headers.append(('Location', url))
+    start_response(resp_code, headers)
+    #log_download(url, data['preferred'], environ, region)
+    return ''
+  # ====== end new download tracking code ========
+
+  # Note location to self
+  data['location'] = environ.get('SCRIPT_NAME', DEFAULT_LOCATION)
+
+  path_param = form.getfirst("path", None)
+  if path_param:
+    path_info = cgi.escape(path_param, 1)
+  else:
+    # Note any PATH_INFO
+    if environ.has_key('PATH_INFO'):
+      path_info = cgi.escape(environ['PATH_INFO'], 1)
+      if environ.has_key('SCRIPT_NAME'):
+        if environ['PATH_INFO'] == environ['SCRIPT_NAME']:
+          path_info = ''
+    else:
+      path_info = ''
+  # The mirror URL already has a trailing slash. Avoid doubling it up.
+  if path_info.startswith('/'):
+    path_info = path_info[1:]
+  data['path_info'] = path_info
+
+  template_file = locate_template(environ)
+
+  # Print out the CGI header component
+  # using xml if the filename ends with the magic '--xml' string
+  if template_file.endswith('--xml.html'):
+    headers.append(('Content-type', 'text/xml'))
+  else:
+    headers.append(('Content-type', 'text/html'))
+
+  start_response(resp_code, headers)
+
+  output = cStringIO.StringIO()
+  template = ezt.Template(template_file)
+  template.generate(output, data)
+  return [ output.getvalue() ]
+
+# ======== new download tracking code ==========
+def log_download(url, preferred, environ, region):
+  timestamp = int(time.time())
+  # format: timestamp,url,mirror,IP,region,"useragent"
+  try:
+    fh = open('/home/jfthomps/debug', 'a')
+    fh.write('%s,%s,%s,%s,%s,"%s"\n' % (timestamp, url, preferred, environ['REMOTE_ADDR'], region, environ['HTTP_USER_AGENT']))
+    fh.close
+  except:
+    pass
+# ====== end new download tracking code ========
+
+if __name__ == '__main__':
+  #from flup.server.fcgi import WSGIServer
+  from flup.server.cgi import WSGIServer
+  WSGIServer(mirrorwrap).run()

Propchange: websites/production/vcl/content/mirrors.cgi
------------------------------------------------------------------------------
    svn:executable = *