File chromium-enable-vaapi.patch of Package chromium.openSUSE_13.1_Update
diff -urNB chromium-48.0.2564.82/chrome/browser/about_flags.cc new/chrome/browser/about_flags.cc
--- chromium-48.0.2564.82/chrome/browser/about_flags.cc 2016-01-20 21:01:19.000000000 +0100
+++ new/chrome/browser/about_flags.cc 2016-01-23 17:52:38.785820994 +0100
@@ -1017,7 +1017,7 @@
"disable-accelerated-video-decode",
IDS_FLAGS_DISABLE_ACCELERATED_VIDEO_DECODE_NAME,
IDS_FLAGS_DISABLE_ACCELERATED_VIDEO_DECODE_DESCRIPTION,
- kOsMac | kOsWin | kOsCrOS,
+ kOsMac | kOsWin | kOsCrOS | kOsLinux,
SINGLE_VALUE_TYPE(switches::kDisableAcceleratedVideoDecode),
},
#if defined(USE_ASH)
diff -urNB chromium-48.0.2564.82/content/common/gpu/media/gpu_jpeg_decode_accelerator.cc new/content/common/gpu/media/gpu_jpeg_decode_accelerator.cc
--- chromium-48.0.2564.82/content/common/gpu/media/gpu_jpeg_decode_accelerator.cc 2016-01-20 21:01:21.000000000 +0100
+++ new/content/common/gpu/media/gpu_jpeg_decode_accelerator.cc 2016-01-23 17:51:10.502723081 +0100
@@ -20,7 +20,7 @@
#include "media/filters/jpeg_parser.h"
#include "ui/gfx/geometry/size.h"
-#if defined(OS_CHROMEOS)
+#if defined(OS_CHROMEOS) || defined(OS_LINUX)
#if defined(ARCH_CPU_X86_FAMILY)
#include "content/common/gpu/media/vaapi_jpeg_decode_accelerator.h"
#endif
@@ -402,7 +402,7 @@
GpuJpegDecodeAccelerator::CreateV4L2JDA(
const scoped_refptr<base::SingleThreadTaskRunner>& io_task_runner) {
scoped_ptr<media::JpegDecodeAccelerator> decoder;
-#if defined(OS_CHROMEOS) && defined(USE_V4L2_CODEC)
+#if (defined(OS_CHROMEOS) || defined(OS_LINUX)) && defined(USE_V4L2_CODEC)
scoped_refptr<V4L2Device> device = V4L2Device::Create(
V4L2Device::kJpegDecoder);
if (device)
@@ -416,7 +416,7 @@
GpuJpegDecodeAccelerator::CreateVaapiJDA(
const scoped_refptr<base::SingleThreadTaskRunner>& io_task_runner) {
scoped_ptr<media::JpegDecodeAccelerator> decoder;
-#if defined(OS_CHROMEOS) && defined(ARCH_CPU_X86_FAMILY)
+#if (defined(OS_CHROMEOS) || defined(OS_LINUX)) && defined(ARCH_CPU_X86_FAMILY)
decoder.reset(new VaapiJpegDecodeAccelerator(io_task_runner));
#endif
return decoder.Pass();
diff -urNB chromium-48.0.2564.82/content/common/gpu/media/gpu_video_decode_accelerator.cc new/content/common/gpu/media/gpu_video_decode_accelerator.cc
--- chromium-48.0.2564.82/content/common/gpu/media/gpu_video_decode_accelerator.cc 2016-01-20 21:01:21.000000000 +0100
+++ new/content/common/gpu/media/gpu_video_decode_accelerator.cc 2016-01-23 17:55:00.068430421 +0100
@@ -33,7 +33,7 @@
#include "content/common/gpu/media/dxva_video_decode_accelerator.h"
#elif defined(OS_MACOSX)
#include "content/common/gpu/media/vt_video_decode_accelerator.h"
-#elif defined(OS_CHROMEOS)
+#elif defined(OS_CHROMEOS) || defined(OS_LINUX)
#if defined(USE_V4L2_CODEC)
#include "content/common/gpu/media/v4l2_device.h"
#include "content/common/gpu/media/v4l2_slice_video_decode_accelerator.h"
@@ -164,7 +164,7 @@
// can be initialized by corresponding VDA successfully.
#if defined(OS_WIN)
profiles = DXVAVideoDecodeAccelerator::GetSupportedProfiles();
-#elif defined(OS_CHROMEOS)
+#elif defined(OS_CHROMEOS) || defined(OS_LINUX)
media::VideoDecodeAccelerator::SupportedProfiles vda_profiles;
#if defined(USE_V4L2_CODEC)
vda_profiles = V4L2VideoDecodeAccelerator::GetSupportedProfiles();
@@ -389,7 +389,7 @@
scoped_ptr<media::VideoDecodeAccelerator>
GpuVideoDecodeAccelerator::CreateV4L2VDA() {
scoped_ptr<media::VideoDecodeAccelerator> decoder;
-#if defined(OS_CHROMEOS) && defined(USE_V4L2_CODEC)
+#if (defined(OS_CHROMEOS) || defined(OS_LINUX)) && defined(USE_V4L2_CODEC)
scoped_refptr<V4L2Device> device = V4L2Device::Create(V4L2Device::kDecoder);
if (device.get()) {
decoder.reset(new V4L2VideoDecodeAccelerator(
@@ -407,7 +407,7 @@
scoped_ptr<media::VideoDecodeAccelerator>
GpuVideoDecodeAccelerator::CreateV4L2SliceVDA() {
scoped_ptr<media::VideoDecodeAccelerator> decoder;
-#if defined(OS_CHROMEOS) && defined(USE_V4L2_CODEC)
+#if (defined(OS_CHROMEOS) || defined(OS_LINUX)) && defined(USE_V4L2_CODEC)
scoped_refptr<V4L2Device> device = V4L2Device::Create(V4L2Device::kDecoder);
if (device.get()) {
decoder.reset(new V4L2SliceVideoDecodeAccelerator(
@@ -438,7 +438,7 @@
scoped_ptr<media::VideoDecodeAccelerator>
GpuVideoDecodeAccelerator::CreateVaapiVDA() {
scoped_ptr<media::VideoDecodeAccelerator> decoder;
-#if defined(OS_CHROMEOS) && defined(ARCH_CPU_X86_FAMILY)
+#if (defined(OS_CHROMEOS) || defined(OS_LINUX)) && defined(ARCH_CPU_X86_FAMILY)
decoder.reset(new VaapiVideoDecodeAccelerator(
make_context_current_, base::Bind(&GpuVideoDecodeAccelerator::BindImage,
base::Unretained(this))));
diff -urNB chromium-48.0.2564.82/content/common/gpu/media/gpu_video_encode_accelerator.cc new/content/common/gpu/media/gpu_video_encode_accelerator.cc
--- chromium-48.0.2564.82/content/common/gpu/media/gpu_video_encode_accelerator.cc 2016-01-20 21:01:21.000000000 +0100
+++ new/content/common/gpu/media/gpu_video_encode_accelerator.cc 2016-01-23 17:51:10.506723039 +0100
@@ -20,7 +20,7 @@
#include "media/base/limits.h"
#include "media/base/video_frame.h"
-#if defined(OS_CHROMEOS)
+#if defined(OS_CHROMEOS) || defined(OS_LINUX)
#if defined(USE_V4L2_CODEC)
#include "content/common/gpu/media/v4l2_video_encode_accelerator.h"
#endif
@@ -197,7 +197,7 @@
scoped_ptr<media::VideoEncodeAccelerator>
GpuVideoEncodeAccelerator::CreateV4L2VEA() {
scoped_ptr<media::VideoEncodeAccelerator> encoder;
-#if defined(OS_CHROMEOS) && defined(USE_V4L2_CODEC)
+#if (defined(OS_CHROMEOS) || defined(OS_LINUX)) && defined(USE_V4L2_CODEC)
scoped_refptr<V4L2Device> device = V4L2Device::Create(V4L2Device::kEncoder);
if (device)
encoder.reset(new V4L2VideoEncodeAccelerator(device));
@@ -209,7 +209,7 @@
scoped_ptr<media::VideoEncodeAccelerator>
GpuVideoEncodeAccelerator::CreateVaapiVEA() {
scoped_ptr<media::VideoEncodeAccelerator> encoder;
-#if defined(OS_CHROMEOS) && defined(ARCH_CPU_X86_FAMILY)
+#if (defined(OS_CHROMEOS) || defined(OS_LINUX)) && defined(ARCH_CPU_X86_FAMILY)
const base::CommandLine* cmd_line = base::CommandLine::ForCurrentProcess();
if (!cmd_line->HasSwitch(switches::kDisableVaapiAcceleratedVideoEncode))
encoder.reset(new VaapiVideoEncodeAccelerator());
diff -urNB chromium-48.0.2564.82/content/common/gpu/media/vaapi_wrapper.cc new/content/common/gpu/media/vaapi_wrapper.cc
--- chromium-48.0.2564.82/content/common/gpu/media/vaapi_wrapper.cc 2016-01-20 21:01:21.000000000 +0100
+++ new/content/common/gpu/media/vaapi_wrapper.cc 2016-01-23 17:51:10.506723039 +0100
@@ -312,7 +312,9 @@
static bool vaapi_functions_initialized = PostSandboxInitialization();
if (!vaapi_functions_initialized) {
bool running_on_chromeos = false;
-#if defined(OS_CHROMEOS)
+#if defined(OS_LINUX)
+ running_on_chromeos = true;
+#elif defined(OS_CHROMEOS)
// When chrome runs on linux with chromeos=1, do not log error message
// without VAAPI libraries.
running_on_chromeos = base::SysInfo::IsRunningOnChromeOS();
diff -urNB chromium-48.0.2564.82/content/common/sandbox_linux/bpf_gpu_policy_linux.cc new/content/common/sandbox_linux/bpf_gpu_policy_linux.cc
--- chromium-48.0.2564.82/content/common/sandbox_linux/bpf_gpu_policy_linux.cc 2016-01-20 21:01:21.000000000 +0100
+++ new/content/common/sandbox_linux/bpf_gpu_policy_linux.cc 2016-01-23 17:51:10.506723039 +0100
@@ -21,6 +21,8 @@
#include "base/logging.h"
#include "base/memory/scoped_ptr.h"
#include "build/build_config.h"
+// Auto-generated for dlopen libva libraries
+#include "content/common/gpu/media/va_stubs.h"
#include "content/common/sandbox_linux/sandbox_bpf_base_policy_linux.h"
#include "content/common/sandbox_linux/sandbox_seccomp_bpf_linux.h"
#include "content/common/set_process_title.h"
@@ -31,6 +33,8 @@
#include "sandbox/linux/syscall_broker/broker_file_permission.h"
#include "sandbox/linux/syscall_broker/broker_process.h"
#include "sandbox/linux/system_headers/linux_syscalls.h"
+#include "third_party/libva/va/va.h"
+#include "third_party/libva/va/va_x11.h"
using sandbox::arch_seccomp_data;
using sandbox::bpf_dsl::Allow;
@@ -40,6 +44,11 @@
using sandbox::syscall_broker::BrokerProcess;
using sandbox::SyscallSets;
+using content_common_gpu_media::kModuleVa;
+using content_common_gpu_media::kModuleVa_x11;
+using content_common_gpu_media::InitializeStubs;
+using content_common_gpu_media::StubPathMap;
+
namespace content {
namespace {
@@ -94,7 +103,7 @@
bool IsAcceleratedVaapiVideoEncodeEnabled() {
bool accelerated_encode_enabled = false;
-#if defined(OS_CHROMEOS)
+#if defined(OS_CHROMEOS) || defined(OS_LINUX)
const base::CommandLine& command_line =
*base::CommandLine::ForCurrentProcess();
accelerated_encode_enabled =
@@ -299,27 +308,41 @@
// inside the sandbox, so preload them now.
if (IsAcceleratedVaapiVideoEncodeEnabled() ||
IsAcceleratedVideoDecodeEnabled()) {
- const char* I965DrvVideoPath = NULL;
- const char* I965HybridDrvVideoPath = NULL;
+ DVLOG(1) << "Attempting to enable hardware video acceleration.";
+ StubPathMap paths;
+ paths[kModuleVa].push_back("libva.so.1");
+ paths[kModuleVa_x11].push_back("libva-x11.so.1");
+ if (!InitializeStubs(paths)) {
+ DVLOG(1) << "Failed to initialize stubs";
+ return false;
+ }
- if (IsArchitectureX86_64()) {
- I965DrvVideoPath = "/usr/lib64/va/drivers/i965_drv_video.so";
- I965HybridDrvVideoPath = "/usr/lib64/va/drivers/hybrid_drv_video.so";
- } else if (IsArchitectureI386()) {
- I965DrvVideoPath = "/usr/lib/va/drivers/i965_drv_video.so";
+ // libva drivers won't get loaded even above two libraries get dlopened.
+ // Thus, libva calls will fail after post sandbox stage.
+ //
+ // To get the va driver loaded before sandboxing, upstream simply dlopen
+ // the hard-coded va driver path because ChromeOS is the only platform
+ // that Google want to support libva.
+ //
+ // While generic linux distros ship va driver as anywhere they want.
+ // Fortunately, the va driver will be loadded when vaInitialize() get
+ // called.
+ // So the following code is to call vaInitialize() before sandboxing.
+ Display* x_display = XOpenDisplay(NULL);
+ VADisplay va_display = vaGetDisplay(x_display);
+ if (!vaDisplayIsValid(va_display)) {
+ DVLOG(1) << "Failed to call vaGetDisplay()";
+ return false;
}
- dlopen(I965DrvVideoPath, RTLD_NOW|RTLD_GLOBAL|RTLD_NODELETE);
- if (I965HybridDrvVideoPath)
- dlopen(I965HybridDrvVideoPath, RTLD_NOW|RTLD_GLOBAL|RTLD_NODELETE);
- dlopen("libva.so.1", RTLD_NOW|RTLD_GLOBAL|RTLD_NODELETE);
-#if defined(USE_OZONE)
- dlopen("libva-drm.so.1", RTLD_NOW|RTLD_GLOBAL|RTLD_NODELETE);
-#elif defined(USE_X11)
- dlopen("libva-x11.so.1", RTLD_NOW|RTLD_GLOBAL|RTLD_NODELETE);
-#endif
- }
- }
+ int major_version, minor_version;
+ if (vaInitialize(va_display, &major_version, &minor_version)
+ != VA_STATUS_SUCCESS) {
+ DVLOG(1) << "Failed to call vaInitialize()";
+ return false;
+ }
+ } // end of IsAcceleratedVaapiVideoEncodeEnabled() || IsAcceleratedVideoDecodeEnabled()
+ } // end of IsArchitectureX86_64() || IsArchitectureI386()
return true;
}
diff -urNB chromium-48.0.2564.82/content/content_common.gypi new/content/content_common.gypi
--- chromium-48.0.2564.82/content/content_common.gypi 2016-01-20 21:01:21.000000000 +0100
+++ new/content/content_common.gypi 2016-01-23 17:51:10.510722998 +0100
@@ -821,7 +821,7 @@
'public/common/webrtc_ip_handling_policy.h',
],
}],
- ['use_v4lplugin==1 and chromeos==1', {
+ ['use_v4lplugin==1 and (chromeos==1 or desktop_linux==1)', {
'defines': [
'USE_LIBV4L2'
],
@@ -865,7 +865,7 @@
},
],
}],
- ['chromeos==1', {
+ ['chromeos==1 or desktop_linux==1', {
'sources': [
'common/gpu/media/accelerated_video_decoder.h',
'common/gpu/media/h264_decoder.cc',
@@ -882,7 +882,7 @@
'common/gpu/media/vp9_picture.h',
],
}],
- ['chromeos==1 and use_v4l2_codec==1', {
+ ['(chromeos==1 or desktop_linux==1) and use_v4l2_codec==1', {
'direct_dependent_settings': {
'defines': [
'USE_V4L2_CODEC'
@@ -915,13 +915,13 @@
'<(DEPTH)/third_party/khronos',
],
}],
- ['target_arch == "arm" and chromeos == 1', {
+ ['target_arch == "arm" and (chromeos == 1 or desktop_linux==1)', {
'sources': [
'common/gpu/media/tegra_v4l2_device.cc',
'common/gpu/media/tegra_v4l2_device.h',
],
}],
- ['target_arch != "arm" and chromeos == 1', {
+ ['target_arch != "arm" and (chromeos == 1 or desktop_linux==1)', {
'dependencies': [
'../media/media.gyp:media',
'../third_party/libyuv/libyuv.gyp:libyuv',
diff -urNB chromium-48.0.2564.82/content/content_gpu.gypi new/content/content_gpu.gypi
--- chromium-48.0.2564.82/content/content_gpu.gypi 2016-01-14 02:49:23.000000000 +0100
+++ new/content/content_gpu.gypi 2016-01-23 17:51:10.510722998 +0100
@@ -38,7 +38,7 @@
],
},
}],
- ['target_arch!="arm" and chromeos == 1', {
+ ['target_arch!="arm" and (chromeos == 1 or desktop_linux==1)', {
'include_dirs': [
'<(DEPTH)/third_party/libva',
],
diff -urNB chromium-48.0.2564.82/content/content_tests.gypi new/content/content_tests.gypi
--- chromium-48.0.2564.82/content/content_tests.gypi 2016-01-20 21:01:21.000000000 +0100
+++ new/content/content_tests.gypi 2016-01-23 17:51:10.510722998 +0100
@@ -1652,7 +1652,7 @@
},
],
}],
- ['chromeos==1 or OS=="win" or OS=="android"', {
+ ['(chromeos==1 or desktop_linux==1) or OS=="win" or OS=="android"', {
'targets': [
{
'target_name': 'video_decode_accelerator_unittest',
@@ -1721,7 +1721,7 @@
'../ui/gfx/x/gfx_x11.gyp:gfx_x11',
],
}],
- ['use_ozone==1 and chromeos==1', {
+ ['use_ozone==1 and (chromeos==1 or desktop_linux==1)', {
'dependencies': [
'../ui/display/display.gyp:display', # Used by rendering_helper.cc
'../ui/ozone/ozone.gyp:ozone', # Used by rendering_helper.cc
@@ -1733,7 +1733,7 @@
},
]
}],
- ['chromeos==1 and target_arch != "arm"', {
+ ['(chromeos==1 or desktop_linux==1) and target_arch != "arm"', {
'targets': [
{
'target_name': 'vaapi_jpeg_decoder_unittest',
@@ -1765,7 +1765,7 @@
}
]
}],
- ['chromeos==1', {
+ ['chromeos==1 or desktop_linux==1', {
'targets': [
{
'target_name': 'video_encode_accelerator_unittest',
diff -urNB chromium-48.0.2564.82/content/gpu/gpu_main.cc new/content/gpu/gpu_main.cc
--- chromium-48.0.2564.82/content/gpu/gpu_main.cc 2016-01-20 21:01:21.000000000 +0100
+++ new/content/gpu/gpu_main.cc 2016-01-23 17:51:10.510722998 +0100
@@ -72,7 +72,7 @@
#include "content/common/sandbox_mac.h"
#endif
-#if defined(OS_CHROMEOS) && defined(ARCH_CPU_X86_FAMILY)
+#if (defined(OS_CHROMEOS) || defined(OS_LINUX)) && defined(ARCH_CPU_X86_FAMILY)
#include "content/common/gpu/media/vaapi_wrapper.h"
#endif
@@ -237,7 +237,7 @@
GetGpuInfoFromCommandLine(gpu_info, command_line);
gpu_info.in_process_gpu = false;
-#if defined(OS_CHROMEOS) && defined(ARCH_CPU_X86_FAMILY)
+#if (defined(OS_CHROMEOS) || defined(OS_LINUX)) && defined(ARCH_CPU_X86_FAMILY)
VaapiWrapper::PreSandboxInitialization();
#endif
diff -urNB chromium-48.0.2564.82/content/public/common/content_switches.cc new/content/public/common/content_switches.cc
--- chromium-48.0.2564.82/content/public/common/content_switches.cc 2016-01-20 21:01:21.000000000 +0100
+++ new/content/public/common/content_switches.cc 2016-01-23 17:51:10.510722998 +0100
@@ -931,7 +931,9 @@
#if defined(OS_CHROMEOS)
// Disables panel fitting (used for mirror mode).
const char kDisablePanelFitting[] = "disable-panel-fitting";
+#endif
+#if defined(OS_CHROMEOS) || defined(OS_LINUX)
// Disables VA-API accelerated video encode.
const char kDisableVaapiAcceleratedVideoEncode[] =
"disable-vaapi-accelerated-video-encode";
diff -urNB chromium-48.0.2564.82/content/public/common/content_switches.h new/content/public/common/content_switches.h
--- chromium-48.0.2564.82/content/public/common/content_switches.h 2016-01-20 21:01:21.000000000 +0100
+++ new/content/public/common/content_switches.h 2016-01-23 17:51:10.514722956 +0100
@@ -275,6 +275,8 @@
#if defined(OS_CHROMEOS)
CONTENT_EXPORT extern const char kDisablePanelFitting[];
+#endif
+#if defined(OS_CHROMEOS) || defined(OS_LINUX)
CONTENT_EXPORT extern const char kDisableVaapiAcceleratedVideoEncode[];
#endif
diff -urNB chromium-48.0.2564.82/gpu/config/software_rendering_list_json.cc new/gpu/config/software_rendering_list_json.cc
--- chromium-48.0.2564.82/gpu/config/software_rendering_list_json.cc 2016-01-20 21:01:22.000000000 +0100
+++ new/gpu/config/software_rendering_list_json.cc 2016-01-23 17:51:10.514722956 +0100
@@ -481,17 +481,6 @@
]
},
{
- "id": 48,
- "description": "Accelerated video decode is unavailable on Linux",
- "cr_bugs": [137247],
- "os": {
- "type": "linux"
- },
- "features": [
- "accelerated_video_decode"
- ]
- },
- {
"id": 49,
"description": "NVidia GeForce GT 650M can cause the system to hang with flash 3D",
"cr_bugs": [140175],
@@ -1041,6 +1030,11 @@
}
},
{
+ "os": {
+ "type": "linux"
+ }
+ },
+ {
"os": {
"type": "android"
},
diff -urNB chromium-48.0.2564.82/media/media.gyp new/media/media.gyp
--- chromium-48.0.2564.82/media/media.gyp 2016-01-20 21:01:22.000000000 +0100
+++ new/media/media.gyp 2016-01-23 17:51:10.514722956 +0100
@@ -764,7 +764,7 @@
],
}],
# For VaapiVideoEncodeAccelerator.
- ['target_arch != "arm" and chromeos == 1', {
+ ['target_arch != "arm" and (chromeos == 1 or desktop_linux==1)', {
'sources': [
'filters/h264_bitstream_buffer.cc',
'filters/h264_bitstream_buffer.h',
@@ -1398,7 +1398,7 @@
'cdm/cdm_adapter_unittest.cc',
],
}],
- ['target_arch != "arm" and chromeos == 1 and use_x11 == 1', {
+ ['target_arch != "arm" and (chromeos == 1 or desktop_linux==1) and use_x11 == 1', {
'sources': [
'filters/h264_bitstream_buffer_unittest.cc',
],
diff -urNB chromium-48.0.2564.82/third_party/catapult/third_party/Paste/paste/urlmap.py.orig new/third_party/catapult/third_party/Paste/paste/urlmap.py.orig
--- chromium-48.0.2564.82/third_party/catapult/third_party/Paste/paste/urlmap.py.orig 2016-01-20 21:01:58.000000000 +0100
+++ new/third_party/catapult/third_party/Paste/paste/urlmap.py.orig 1970-01-01 01:00:00.000000000 +0100
@@ -1,263 +0,0 @@
-# (c) 2005 Ian Bicking and contributors; written for Paste (http://pythonpaste.org)
-# Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php
-"""
-Map URL prefixes to WSGI applications. See ``URLMap``
-"""
-
-import re
-import os
-import cgi
-try:
- # Python 3
- from collections import MutableMapping as DictMixin
-except ImportError:
- # Python 2
- from UserDict import DictMixin
-
-from paste import httpexceptions
-
-__all__ = ['URLMap', 'PathProxyURLMap']
-
-def urlmap_factory(loader, global_conf, **local_conf):
- if 'not_found_app' in local_conf:
- not_found_app = local_conf.pop('not_found_app')
- else:
- not_found_app = global_conf.get('not_found_app')
- if not_found_app:
- not_found_app = loader.get_app(not_found_app, global_conf=global_conf)
- urlmap = URLMap(not_found_app=not_found_app)
- for path, app_name in local_conf.items():
- path = parse_path_expression(path)
- app = loader.get_app(app_name, global_conf=global_conf)
- urlmap[path] = app
- return urlmap
-
-def parse_path_expression(path):
- """
- Parses a path expression like 'domain foobar.com port 20 /' or
- just '/foobar' for a path alone. Returns as an address that
- URLMap likes.
- """
- parts = path.split()
- domain = port = path = None
- while parts:
- if parts[0] == 'domain':
- parts.pop(0)
- if not parts:
- raise ValueError("'domain' must be followed with a domain name")
- if domain:
- raise ValueError("'domain' given twice")
- domain = parts.pop(0)
- elif parts[0] == 'port':
- parts.pop(0)
- if not parts:
- raise ValueError("'port' must be followed with a port number")
- if port:
- raise ValueError("'port' given twice")
- port = parts.pop(0)
- else:
- if path:
- raise ValueError("more than one path given (have %r, got %r)"
- % (path, parts[0]))
- path = parts.pop(0)
- s = ''
- if domain:
- s = 'http://%s' % domain
- if port:
- if not domain:
- raise ValueError("If you give a port, you must also give a domain")
- s += ':' + port
- if path:
- if s:
- s += '/'
- s += path
- return s
-
-class URLMap(DictMixin):
-
- """
- URLMap instances are dictionary-like object that dispatch to one
- of several applications based on the URL.
-
- The dictionary keys are URLs to match (like
- ``PATH_INFO.startswith(url)``), and the values are applications to
- dispatch to. URLs are matched most-specific-first, i.e., longest
- URL first. The ``SCRIPT_NAME`` and ``PATH_INFO`` environmental
- variables are adjusted to indicate the new context.
-
- URLs can also include domains, like ``http://blah.com/foo``, or as
- tuples ``('blah.com', '/foo')``. This will match domain names; without
- the ``http://domain`` or with a domain of ``None`` any domain will be
- matched (so long as no other explicit domain matches). """
-
- def __init__(self, not_found_app=None):
- self.applications = []
- if not not_found_app:
- not_found_app = self.not_found_app
- self.not_found_application = not_found_app
-
- def __len__(self):
- return len(self.applications)
-
- def __iter__(self):
- for app_url, app in self.applications:
- yield app_url
-
- norm_url_re = re.compile('//+')
- domain_url_re = re.compile('^(http|https)://')
-
- def not_found_app(self, environ, start_response):
- mapper = environ.get('paste.urlmap_object')
- if mapper:
- matches = [p for p, a in mapper.applications]
- extra = 'defined apps: %s' % (
- ',\n '.join(map(repr, matches)))
- else:
- extra = ''
- extra += '\nSCRIPT_NAME: %r' % cgi.escape(environ.get('SCRIPT_NAME'))
- extra += '\nPATH_INFO: %r' % cgi.escape(environ.get('PATH_INFO'))
- extra += '\nHTTP_HOST: %r' % cgi.escape(environ.get('HTTP_HOST'))
- app = httpexceptions.HTTPNotFound(
- environ['PATH_INFO'],
- comment=cgi.escape(extra)).wsgi_application
- return app(environ, start_response)
-
- def normalize_url(self, url, trim=True):
- if isinstance(url, (list, tuple)):
- domain = url[0]
- url = self.normalize_url(url[1])[1]
- return domain, url
- assert (not url or url.startswith('/')
- or self.domain_url_re.search(url)), (
- "URL fragments must start with / or http:// (you gave %r)" % url)
- match = self.domain_url_re.search(url)
- if match:
- url = url[match.end():]
- if '/' in url:
- domain, url = url.split('/', 1)
- url = '/' + url
- else:
- domain, url = url, ''
- else:
- domain = None
- url = self.norm_url_re.sub('/', url)
- if trim:
- url = url.rstrip('/')
- return domain, url
-
- def sort_apps(self):
- """
- Make sure applications are sorted with longest URLs first
- """
- def key(app_desc):
- (domain, url), app = app_desc
- if not domain:
- # Make sure empty domains sort last:
- return '\xff', -len(url)
- else:
- return domain, -len(url)
- apps = [(key(desc), desc) for desc in self.applications]
- apps.sort()
- self.applications = [desc for (sortable, desc) in apps]
-
- def __setitem__(self, url, app):
- if app is None:
- try:
- del self[url]
- except KeyError:
- pass
- return
- dom_url = self.normalize_url(url)
- if dom_url in self:
- del self[dom_url]
- self.applications.append((dom_url, app))
- self.sort_apps()
-
- def __getitem__(self, url):
- dom_url = self.normalize_url(url)
- for app_url, app in self.applications:
- if app_url == dom_url:
- return app
- raise KeyError(
- "No application with the url %r (domain: %r; existing: %s)"
- % (url[1], url[0] or '*', self.applications))
-
- def __delitem__(self, url):
- url = self.normalize_url(url)
- for app_url, app in self.applications:
- if app_url == url:
- self.applications.remove((app_url, app))
- break
- else:
- raise KeyError(
- "No application with the url %r" % (url,))
-
- def keys(self):
- return [app_url for app_url, app in self.applications]
-
- def __call__(self, environ, start_response):
- host = environ.get('HTTP_HOST', environ.get('SERVER_NAME')).lower()
- if ':' in host:
- host, port = host.split(':', 1)
- else:
- if environ['wsgi.url_scheme'] == 'http':
- port = '80'
- else:
- port = '443'
- path_info = environ.get('PATH_INFO')
- path_info = self.normalize_url(path_info, False)[1]
- for (domain, app_url), app in self.applications:
- if domain and domain != host and domain != host+':'+port:
- continue
- if (path_info == app_url
- or path_info.startswith(app_url + '/')):
- environ['SCRIPT_NAME'] += app_url
- environ['PATH_INFO'] = path_info[len(app_url):]
- return app(environ, start_response)
- environ['paste.urlmap_object'] = self
- return self.not_found_application(environ, start_response)
-
-
-class PathProxyURLMap(object):
-
- """
- This is a wrapper for URLMap that catches any strings that
- are passed in as applications; these strings are treated as
- filenames (relative to `base_path`) and are passed to the
- callable `builder`, which will return an application.
-
- This is intended for cases when configuration files can be
- treated as applications.
-
- `base_paste_url` is the URL under which all applications added through
- this wrapper must go. Use ``""`` if you want this to not
- change incoming URLs.
- """
-
- def __init__(self, map, base_paste_url, base_path, builder):
- self.map = map
- self.base_paste_url = self.map.normalize_url(base_paste_url)
- self.base_path = base_path
- self.builder = builder
-
- def __setitem__(self, url, app):
- if isinstance(app, (str, unicode)):
- app_fn = os.path.join(self.base_path, app)
- app = self.builder(app_fn)
- url = self.map.normalize_url(url)
- # @@: This means http://foo.com/bar will potentially
- # match foo.com, but /base_paste_url/bar, which is unintuitive
- url = (url[0] or self.base_paste_url[0],
- self.base_paste_url[1] + url[1])
- self.map[url] = app
-
- def __getattr__(self, attr):
- return getattr(self.map, attr)
-
- # This is really the only settable attribute
- def not_found_application__get(self):
- return self.map.not_found_application
- def not_found_application__set(self, value):
- self.map.not_found_application = value
- not_found_application = property(not_found_application__get,
- not_found_application__set)
diff -urNB chromium-48.0.2564.82/third_party/catapult/third_party/Paste/paste/util/template.py.orig new/third_party/catapult/third_party/Paste/paste/util/template.py.orig
--- chromium-48.0.2564.82/third_party/catapult/third_party/Paste/paste/util/template.py.orig 2016-01-20 21:01:58.000000000 +0100
+++ new/third_party/catapult/third_party/Paste/paste/util/template.py.orig 1970-01-01 01:00:00.000000000 +0100
@@ -1,762 +0,0 @@
-"""
-A small templating language
-
-This implements a small templating language for use internally in
-Paste and Paste Script. This language implements if/elif/else,
-for/continue/break, expressions, and blocks of Python code. The
-syntax is::
-
- {{any expression (function calls etc)}}
- {{any expression | filter}}
- {{for x in y}}...{{endfor}}
- {{if x}}x{{elif y}}y{{else}}z{{endif}}
- {{py:x=1}}
- {{py:
- def foo(bar):
- return 'baz'
- }}
- {{default var = default_value}}
- {{# comment}}
-
-You use this with the ``Template`` class or the ``sub`` shortcut.
-The ``Template`` class takes the template string and the name of
-the template (for errors) and a default namespace. Then (like
-``string.Template``) you can call the ``tmpl.substitute(**kw)``
-method to make a substitution (or ``tmpl.substitute(a_dict)``).
-
-``sub(content, **kw)`` substitutes the template immediately. You
-can use ``__name='tmpl.html'`` to set the name of the template.
-
-If there are syntax errors ``TemplateError`` will be raised.
-"""
-
-import re
-import six
-import sys
-import cgi
-from six.moves.urllib.parse import quote
-from paste.util.looper import looper
-
-__all__ = ['TemplateError', 'Template', 'sub', 'HTMLTemplate',
- 'sub_html', 'html', 'bunch']
-
-token_re = re.compile(r'\{\{|\}\}')
-in_re = re.compile(r'\s+in\s+')
-var_re = re.compile(r'^[a-z_][a-z0-9_]*$', re.I)
-
-class TemplateError(Exception):
- """Exception raised while parsing a template
- """
-
- def __init__(self, message, position, name=None):
- self.message = message
- self.position = position
- self.name = name
-
- def __str__(self):
- msg = '%s at line %s column %s' % (
- self.message, self.position[0], self.position[1])
- if self.name:
- msg += ' in %s' % self.name
- return msg
-
-class _TemplateContinue(Exception):
- pass
-
-class _TemplateBreak(Exception):
- pass
-
-class Template(object):
-
- default_namespace = {
- 'start_braces': '{{',
- 'end_braces': '}}',
- 'looper': looper,
- }
-
- default_encoding = 'utf8'
-
- def __init__(self, content, name=None, namespace=None):
- self.content = content
- self._unicode = isinstance(content, six.text_type)
- self.name = name
-
- if not self._unicode:
- content = content.decode(self.default_encoding)
- self._unicode = True
-
- self._parsed = parse(content, name=name)
- if namespace is None:
- namespace = {}
- self.namespace = namespace
-
- def from_filename(cls, filename, namespace=None, encoding=None):
- f = open(filename, 'rb')
- c = f.read()
- f.close()
- if encoding:
- c = c.decode(encoding)
- return cls(content=c, name=filename, namespace=namespace)
-
- from_filename = classmethod(from_filename)
-
- def __repr__(self):
- return '<%s %s name=%r>' % (
- self.__class__.__name__,
- hex(id(self))[2:], self.name)
-
- def substitute(self, *args, **kw):
- if args:
- if kw:
- raise TypeError(
- "You can only give positional *or* keyword arguments")
- if len(args) > 1:
- raise TypeError(
- "You can only give on positional argument")
- kw = args[0]
- ns = self.default_namespace.copy()
- ns.update(self.namespace)
- ns.update(kw)
- result = self._interpret(ns)
- return result
-
- def _interpret(self, ns):
- __traceback_hide__ = True
- parts = []
- self._interpret_codes(self._parsed, ns, out=parts)
- return ''.join(parts)
-
- def _interpret_codes(self, codes, ns, out):
- __traceback_hide__ = True
- for item in codes:
- if isinstance(item, six.string_types):
- out.append(item)
- else:
- self._interpret_code(item, ns, out)
-
- def _interpret_code(self, code, ns, out):
- __traceback_hide__ = True
- name, pos = code[0], code[1]
- if name == 'py':
- self._exec(code[2], ns, pos)
- elif name == 'continue':
- raise _TemplateContinue()
- elif name == 'break':
- raise _TemplateBreak()
- elif name == 'for':
- vars, expr, content = code[2], code[3], code[4]
- expr = self._eval(expr, ns, pos)
- self._interpret_for(vars, expr, content, ns, out)
- elif name == 'cond':
- parts = code[2:]
- self._interpret_if(parts, ns, out)
- elif name == 'expr':
- parts = code[2].split('|')
- base = self._eval(parts[0], ns, pos)
- for part in parts[1:]:
- func = self._eval(part, ns, pos)
- base = func(base)
- out.append(self._repr(base, pos))
- elif name == 'default':
- var, expr = code[2], code[3]
- if var not in ns:
- result = self._eval(expr, ns, pos)
- ns[var] = result
- elif name == 'comment':
- return
- else:
- assert 0, "Unknown code: %r" % name
-
- def _interpret_for(self, vars, expr, content, ns, out):
- __traceback_hide__ = True
- for item in expr:
- if len(vars) == 1:
- ns[vars[0]] = item
- else:
- if len(vars) != len(item):
- raise ValueError(
- 'Need %i items to unpack (got %i items)'
- % (len(vars), len(item)))
- for name, value in zip(vars, item):
- ns[name] = value
- try:
- self._interpret_codes(content, ns, out)
- except _TemplateContinue:
- continue
- except _TemplateBreak:
- break
-
- def _interpret_if(self, parts, ns, out):
- __traceback_hide__ = True
- # @@: if/else/else gets through
- for part in parts:
- assert not isinstance(part, six.string_types)
- name, pos = part[0], part[1]
- if name == 'else':
- result = True
- else:
- result = self._eval(part[2], ns, pos)
- if result:
- self._interpret_codes(part[3], ns, out)
- break
-
- def _eval(self, code, ns, pos):
- __traceback_hide__ = True
- try:
- value = eval(code, ns)
- return value
- except:
- exc_info = sys.exc_info()
- e = exc_info[1]
- if getattr(e, 'args'):
- arg0 = e.args[0]
- else:
- arg0 = str(e)
- e.args = (self._add_line_info(arg0, pos),)
- six.reraise(exc_info[0], e, exc_info[2])
-
- def _exec(self, code, ns, pos):
- __traceback_hide__ = True
- try:
- six.exec_(code, ns)
- except:
- exc_info = sys.exc_info()
- e = exc_info[1]
- e.args = (self._add_line_info(e.args[0], pos),)
- six.reraise(exc_info[0], e, exc_info[2])
-
- def _repr(self, value, pos):
- __traceback_hide__ = True
- try:
- if value is None:
- return ''
- if self._unicode:
- try:
- value = six.text_type(value)
- except UnicodeDecodeError:
- value = str(value)
- else:
- value = str(value)
- except:
- exc_info = sys.exc_info()
- e = exc_info[1]
- e.args = (self._add_line_info(e.args[0], pos),)
- six.reraise(exc_info[0], e, exc_info[2])
- else:
- if self._unicode and isinstance(value, six.binary_type):
- if not self.default_encoding:
- raise UnicodeDecodeError(
- 'Cannot decode str value %r into unicode '
- '(no default_encoding provided)' % value)
- value = value.decode(self.default_encoding)
- elif not self._unicode and isinstance(value, six.text_type):
- if not self.default_encoding:
- raise UnicodeEncodeError(
- 'Cannot encode unicode value %r into str '
- '(no default_encoding provided)' % value)
- value = value.encode(self.default_encoding)
- return value
-
-
- def _add_line_info(self, msg, pos):
- msg = "%s at line %s column %s" % (
- msg, pos[0], pos[1])
- if self.name:
- msg += " in file %s" % self.name
- return msg
-
-def sub(content, **kw):
- name = kw.get('__name')
- tmpl = Template(content, name=name)
- return tmpl.substitute(kw)
-
-def paste_script_template_renderer(content, vars, filename=None):
- tmpl = Template(content, name=filename)
- return tmpl.substitute(vars)
-
-class bunch(dict):
-
- def __init__(self, **kw):
- for name, value in kw.items():
- setattr(self, name, value)
-
- def __setattr__(self, name, value):
- self[name] = value
-
- def __getattr__(self, name):
- try:
- return self[name]
- except KeyError:
- raise AttributeError(name)
-
- def __getitem__(self, key):
- if 'default' in self:
- try:
- return dict.__getitem__(self, key)
- except KeyError:
- return dict.__getitem__(self, 'default')
- else:
- return dict.__getitem__(self, key)
-
- def __repr__(self):
- items = [
- (k, v) for k, v in self.items()]
- items.sort()
- return '<%s %s>' % (
- self.__class__.__name__,
- ' '.join(['%s=%r' % (k, v) for k, v in items]))
-
-############################################################
-## HTML Templating
-############################################################
-
-class html(object):
- def __init__(self, value):
- self.value = value
- def __str__(self):
- return self.value
- def __repr__(self):
- return '<%s %r>' % (
- self.__class__.__name__, self.value)
-
-def html_quote(value):
- if value is None:
- return ''
- if not isinstance(value, six.string_types):
- if hasattr(value, '__unicode__'):
- value = unicode(value)
- else:
- value = str(value)
- value = cgi.escape(value, 1)
- if isinstance(value, unicode):
- value = value.encode('ascii', 'xmlcharrefreplace')
- return value
-
-def url(v):
- if not isinstance(v, six.string_types):
- if hasattr(v, '__unicode__'):
- v = unicode(v)
- else:
- v = str(v)
- if isinstance(v, unicode):
- v = v.encode('utf8')
- return quote(v)
-
-def attr(**kw):
- kw = kw.items()
- kw.sort()
- parts = []
- for name, value in kw:
- if value is None:
- continue
- if name.endswith('_'):
- name = name[:-1]
- parts.append('%s="%s"' % (html_quote(name), html_quote(value)))
- return html(' '.join(parts))
-
-class HTMLTemplate(Template):
-
- default_namespace = Template.default_namespace.copy()
- default_namespace.update(dict(
- html=html,
- attr=attr,
- url=url,
- ))
-
- def _repr(self, value, pos):
- plain = Template._repr(self, value, pos)
- if isinstance(value, html):
- return plain
- else:
- return html_quote(plain)
-
-def sub_html(content, **kw):
- name = kw.get('__name')
- tmpl = HTMLTemplate(content, name=name)
- return tmpl.substitute(kw)
-
-
-############################################################
-## Lexing and Parsing
-############################################################
-
-def lex(s, name=None, trim_whitespace=True):
- """
- Lex a string into chunks:
-
- >>> lex('hey')
- ['hey']
- >>> lex('hey {{you}}')
- ['hey ', ('you', (1, 7))]
- >>> lex('hey {{')
- Traceback (most recent call last):
- ...
- TemplateError: No }} to finish last expression at line 1 column 7
- >>> lex('hey }}')
- Traceback (most recent call last):
- ...
- TemplateError: }} outside expression at line 1 column 7
- >>> lex('hey {{ {{')
- Traceback (most recent call last):
- ...
- TemplateError: {{ inside expression at line 1 column 10
-
- """
- in_expr = False
- chunks = []
- last = 0
- last_pos = (1, 1)
- for match in token_re.finditer(s):
- expr = match.group(0)
- pos = find_position(s, match.end())
- if expr == '{{' and in_expr:
- raise TemplateError('{{ inside expression', position=pos,
- name=name)
- elif expr == '}}' and not in_expr:
- raise TemplateError('}} outside expression', position=pos,
- name=name)
- if expr == '{{':
- part = s[last:match.start()]
- if part:
- chunks.append(part)
- in_expr = True
- else:
- chunks.append((s[last:match.start()], last_pos))
- in_expr = False
- last = match.end()
- last_pos = pos
- if in_expr:
- raise TemplateError('No }} to finish last expression',
- name=name, position=last_pos)
- part = s[last:]
- if part:
- chunks.append(part)
- if trim_whitespace:
- chunks = trim_lex(chunks)
- return chunks
-
-statement_re = re.compile(r'^(?:if |elif |else |for |py:)')
-single_statements = ['endif', 'endfor', 'continue', 'break']
-trail_whitespace_re = re.compile(r'\n[\t ]*$')
-lead_whitespace_re = re.compile(r'^[\t ]*\n')
-
-def trim_lex(tokens):
- r"""
- Takes a lexed set of tokens, and removes whitespace when there is
- a directive on a line by itself:
-
- >>> tokens = lex('{{if x}}\nx\n{{endif}}\ny', trim_whitespace=False)
- >>> tokens
- [('if x', (1, 3)), '\nx\n', ('endif', (3, 3)), '\ny']
- >>> trim_lex(tokens)
- [('if x', (1, 3)), 'x\n', ('endif', (3, 3)), 'y']
- """
- for i in range(len(tokens)):
- current = tokens[i]
- if isinstance(tokens[i], six.string_types):
- # we don't trim this
- continue
- item = current[0]
- if not statement_re.search(item) and item not in single_statements:
- continue
- if not i:
- prev = ''
- else:
- prev = tokens[i-1]
- if i+1 >= len(tokens):
- next = ''
- else:
- next = tokens[i+1]
- if (not isinstance(next, six.string_types)
- or not isinstance(prev, six.string_types)):
- continue
- if ((not prev or trail_whitespace_re.search(prev))
- and (not next or lead_whitespace_re.search(next))):
- if prev:
- m = trail_whitespace_re.search(prev)
- # +1 to leave the leading \n on:
- prev = prev[:m.start()+1]
- tokens[i-1] = prev
- if next:
- m = lead_whitespace_re.search(next)
- next = next[m.end():]
- tokens[i+1] = next
- return tokens
-
-
-def find_position(string, index):
- """Given a string and index, return (line, column)"""
- leading = string[:index].splitlines()
- return (len(leading), len(leading[-1])+1)
-
-def parse(s, name=None):
- r"""
- Parses a string into a kind of AST
-
- >>> parse('{{x}}')
- [('expr', (1, 3), 'x')]
- >>> parse('foo')
- ['foo']
- >>> parse('{{if x}}test{{endif}}')
- [('cond', (1, 3), ('if', (1, 3), 'x', ['test']))]
- >>> parse('series->{{for x in y}}x={{x}}{{endfor}}')
- ['series->', ('for', (1, 11), ('x',), 'y', ['x=', ('expr', (1, 27), 'x')])]
- >>> parse('{{for x, y in z:}}{{continue}}{{endfor}}')
- [('for', (1, 3), ('x', 'y'), 'z', [('continue', (1, 21))])]
- >>> parse('{{py:x=1}}')
- [('py', (1, 3), 'x=1')]
- >>> parse('{{if x}}a{{elif y}}b{{else}}c{{endif}}')
- [('cond', (1, 3), ('if', (1, 3), 'x', ['a']), ('elif', (1, 12), 'y', ['b']), ('else', (1, 23), None, ['c']))]
-
- Some exceptions::
-
- >>> parse('{{continue}}')
- Traceback (most recent call last):
- ...
- TemplateError: continue outside of for loop at line 1 column 3
- >>> parse('{{if x}}foo')
- Traceback (most recent call last):
- ...
- TemplateError: No {{endif}} at line 1 column 3
- >>> parse('{{else}}')
- Traceback (most recent call last):
- ...
- TemplateError: else outside of an if block at line 1 column 3
- >>> parse('{{if x}}{{for x in y}}{{endif}}{{endfor}}')
- Traceback (most recent call last):
- ...
- TemplateError: Unexpected endif at line 1 column 25
- >>> parse('{{if}}{{endif}}')
- Traceback (most recent call last):
- ...
- TemplateError: if with no expression at line 1 column 3
- >>> parse('{{for x y}}{{endfor}}')
- Traceback (most recent call last):
- ...
- TemplateError: Bad for (no "in") in 'x y' at line 1 column 3
- >>> parse('{{py:x=1\ny=2}}')
- Traceback (most recent call last):
- ...
- TemplateError: Multi-line py blocks must start with a newline at line 1 column 3
- """
- tokens = lex(s, name=name)
- result = []
- while tokens:
- next, tokens = parse_expr(tokens, name)
- result.append(next)
- return result
-
-def parse_expr(tokens, name, context=()):
- if isinstance(tokens[0], six.string_types):
- return tokens[0], tokens[1:]
- expr, pos = tokens[0]
- expr = expr.strip()
- if expr.startswith('py:'):
- expr = expr[3:].lstrip(' \t')
- if expr.startswith('\n'):
- expr = expr[1:]
- else:
- if '\n' in expr:
- raise TemplateError(
- 'Multi-line py blocks must start with a newline',
- position=pos, name=name)
- return ('py', pos, expr), tokens[1:]
- elif expr in ('continue', 'break'):
- if 'for' not in context:
- raise TemplateError(
- 'continue outside of for loop',
- position=pos, name=name)
- return (expr, pos), tokens[1:]
- elif expr.startswith('if '):
- return parse_cond(tokens, name, context)
- elif (expr.startswith('elif ')
- or expr == 'else'):
- raise TemplateError(
- '%s outside of an if block' % expr.split()[0],
- position=pos, name=name)
- elif expr in ('if', 'elif', 'for'):
- raise TemplateError(
- '%s with no expression' % expr,
- position=pos, name=name)
- elif expr in ('endif', 'endfor'):
- raise TemplateError(
- 'Unexpected %s' % expr,
- position=pos, name=name)
- elif expr.startswith('for '):
- return parse_for(tokens, name, context)
- elif expr.startswith('default '):
- return parse_default(tokens, name, context)
- elif expr.startswith('#'):
- return ('comment', pos, tokens[0][0]), tokens[1:]
- return ('expr', pos, tokens[0][0]), tokens[1:]
-
-def parse_cond(tokens, name, context):
- start = tokens[0][1]
- pieces = []
- context = context + ('if',)
- while 1:
- if not tokens:
- raise TemplateError(
- 'Missing {{endif}}',
- position=start, name=name)
- if (isinstance(tokens[0], tuple)
- and tokens[0][0] == 'endif'):
- return ('cond', start) + tuple(pieces), tokens[1:]
- next, tokens = parse_one_cond(tokens, name, context)
- pieces.append(next)
-
-def parse_one_cond(tokens, name, context):
- (first, pos), tokens = tokens[0], tokens[1:]
- content = []
- if first.endswith(':'):
- first = first[:-1]
- if first.startswith('if '):
- part = ('if', pos, first[3:].lstrip(), content)
- elif first.startswith('elif '):
- part = ('elif', pos, first[5:].lstrip(), content)
- elif first == 'else':
- part = ('else', pos, None, content)
- else:
- assert 0, "Unexpected token %r at %s" % (first, pos)
- while 1:
- if not tokens:
- raise TemplateError(
- 'No {{endif}}',
- position=pos, name=name)
- if (isinstance(tokens[0], tuple)
- and (tokens[0][0] == 'endif'
- or tokens[0][0].startswith('elif ')
- or tokens[0][0] == 'else')):
- return part, tokens
- next, tokens = parse_expr(tokens, name, context)
- content.append(next)
-
-def parse_for(tokens, name, context):
- first, pos = tokens[0]
- tokens = tokens[1:]
- context = ('for',) + context
- content = []
- assert first.startswith('for ')
- if first.endswith(':'):
- first = first[:-1]
- first = first[3:].strip()
- match = in_re.search(first)
- if not match:
- raise TemplateError(
- 'Bad for (no "in") in %r' % first,
- position=pos, name=name)
- vars = first[:match.start()]
- if '(' in vars:
- raise TemplateError(
- 'You cannot have () in the variable section of a for loop (%r)'
- % vars, position=pos, name=name)
- vars = tuple([
- v.strip() for v in first[:match.start()].split(',')
- if v.strip()])
- expr = first[match.end():]
- while 1:
- if not tokens:
- raise TemplateError(
- 'No {{endfor}}',
- position=pos, name=name)
- if (isinstance(tokens[0], tuple)
- and tokens[0][0] == 'endfor'):
- return ('for', pos, vars, expr, content), tokens[1:]
- next, tokens = parse_expr(tokens, name, context)
- content.append(next)
-
-def parse_default(tokens, name, context):
- first, pos = tokens[0]
- assert first.startswith('default ')
- first = first.split(None, 1)[1]
- parts = first.split('=', 1)
- if len(parts) == 1:
- raise TemplateError(
- "Expression must be {{default var=value}}; no = found in %r" % first,
- position=pos, name=name)
- var = parts[0].strip()
- if ',' in var:
- raise TemplateError(
- "{{default x, y = ...}} is not supported",
- position=pos, name=name)
- if not var_re.search(var):
- raise TemplateError(
- "Not a valid variable name for {{default}}: %r"
- % var, position=pos, name=name)
- expr = parts[1].strip()
- return ('default', pos, var, expr), tokens[1:]
-
-_fill_command_usage = """\
-%prog [OPTIONS] TEMPLATE arg=value
-
-Use py:arg=value to set a Python value; otherwise all values are
-strings.
-"""
-
-def fill_command(args=None):
- import sys, optparse, pkg_resources, os
- if args is None:
- args = sys.argv[1:]
- dist = pkg_resources.get_distribution('Paste')
- parser = optparse.OptionParser(
- version=str(dist),
- usage=_fill_command_usage)
- parser.add_option(
- '-o', '--output',
- dest='output',
- metavar="FILENAME",
- help="File to write output to (default stdout)")
- parser.add_option(
- '--html',
- dest='use_html',
- action='store_true',
- help="Use HTML style filling (including automatic HTML quoting)")
- parser.add_option(
- '--env',
- dest='use_env',
- action='store_true',
- help="Put the environment in as top-level variables")
- options, args = parser.parse_args(args)
- if len(args) < 1:
- print('You must give a template filename')
- print(dir(parser))
- assert 0
- template_name = args[0]
- args = args[1:]
- vars = {}
- if options.use_env:
- vars.update(os.environ)
- for value in args:
- if '=' not in value:
- print('Bad argument: %r' % value)
- sys.exit(2)
- name, value = value.split('=', 1)
- if name.startswith('py:'):
- name = name[:3]
- value = eval(value)
- vars[name] = value
- if template_name == '-':
- template_content = sys.stdin.read()
- template_name = '<stdin>'
- else:
- f = open(template_name, 'rb')
- template_content = f.read()
- f.close()
- if options.use_html:
- TemplateClass = HTMLTemplate
- else:
- TemplateClass = Template
- template = TemplateClass(template_content, name=template_name)
- result = template.substitute(vars)
- if options.output:
- f = open(options.output, 'wb')
- f.write(result)
- f.close()
- else:
- sys.stdout.write(result)
-
-if __name__ == '__main__':
- from paste.util.template import fill_command
- fill_command()
-
-