initial import.

This commit is contained in:
ndparker 2013-10-13 17:24:23 +02:00
commit f7d6457e2d
78 changed files with 23299 additions and 0 deletions

13
.gitignore vendored Normal file
View File

@ -0,0 +1,13 @@
Makefile
*.py[cod]
*.so
dist
build
__pycache__
docs/_userdoc/_build/
docs/apidoc/
docs/userdoc/
_website/
*.ebuild
.*.sw?
MANIFEST

201
LICENSE Normal file
View File

@ -0,0 +1,201 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed 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.

127
README.rst Normal file
View File

@ -0,0 +1,127 @@
.. -*- coding: utf-8 -*-
TABLE OF CONTENTS
=================
1. Introduction
2. Copyright and License
3. System Requirements
4. Installation
5. Documentation
6. Bugs
7. Author Information
INTRODUCTION
============
rJSmin is a javascript minifier written in python.
The minifier is based on the semantics of `jsmin.c by Douglas Crockford`_\.
The module is a re-implementation aiming for speed, so it can be used at
runtime (rather than during a preprocessing step). Usually it produces the
same results as the original ``jsmin.c``. It differs in the following ways:
- there is no error detection: unterminated string, regex and comment
literals are treated as regular javascript code and minified as such.
- Control characters inside string and regex literals are left untouched; they
are not converted to spaces (nor to \n)
- Newline characters are not allowed inside string and regex literals, except
for line continuations in string literals (ECMA-5).
- "return /regex/" is recognized correctly.
- "+ +" and "- -" sequences are not collapsed to '++' or '--'
- Newlines before ! operators are removed more sensibly
- rJSmin does not handle streams, but only complete strings. (However, the
module provides a "streamy" interface).
Since most parts of the logic are handled by the regex engine it's way
faster than the original python port of ``jsmin.c`` by Baruch Even. The speed
factor varies between about 6 and 55 depending on input and python version
(it gets faster the more compressed the input already is). Compared to the
speed-refactored python port by Dave St.Germain the performance gain is less
dramatic but still between 1.2 and 7. See the docs/BENCHMARKS file for
details.
rjsmin.c is a reimplementation of rjsmin.py in C and speeds it up even more.
.. _jsmin.c by Douglas Crockford: http://www.crockford.com/javascript/jsmin.c
COPYRIGHT AND LICENSE
=====================
Copyright 2011 - 2013
André Malo or his licensors, as applicable.
The whole package (except for the files in the bench/ directory)
is distributed under the Apache License Version 2.0. You'll find a copy in the
root directory of the distribution or online at:
<http://www.apache.org/licenses/LICENSE-2.0>.
SYSTEM REQUIREMENTS
===================
Both python 2 (>=2.4) and python 3 are supported.
INSTALLATION
============
rJSmin is set up using the standard python distutils. So you can install
it using the usual command:
$ python setup.py install
The command above will install rJSmin into python's library path.
Additionally it will install the documentation. On unices it will be
installed by default into <prefix>/share/doc/rjsmin.
For customization options please study the output of
$ python setup.py --help
Especially the following options may be interesting for you:
--without-c-extensions Don't install C extensions
--without-docs Do not install documentation files
Alternatively just copy rjsmin.py into your project and use it.
DOCUMENTATION
=============
A generated API documentation is available in the docs/apidoc/ directory.
But you can just look into the module. It provides a simple function,
called jsmin which takes the script as a string and returns the minified
script as a string.
The module additionally provides a "streamy" interface similar to the one
jsmin.c provides:
$ python -mrjsmin <script >minified
The latest documentation is also available online at
<http://opensource.perlig.de/rjsmin/>.
BUGS
====
No bugs, of course. ;-)
But if you've found one or have an idea how to improve rjsmin,
please send a mail to <rjsmin-bugs@perlig.de>.
AUTHOR INFORMATION
==================
André "nd" Malo <nd@perlig.de>
GPG: 0x8103A37E
If God intended people to be naked, they would be born that way.
-- Oscar Wilde

View File

@ -0,0 +1,25 @@
# Copyright 2011-2013 Andr\xe9 Malo
# Distributed under the terms of the GNU General Public License v2
# $Header$
EAPI="5"
PYTHON_COMPAT=( python{2_5,2_6,2_7,3_1,3_2,3_3} pypy{1_9,2_0} jython{2_5,2_7} )
inherit distutils-r1
DESCRIPTION="Fast javascript minifier for python"
HOMEPAGE="http://opensource.perlig.de/rjsmin/"
SRC_URI="http://storage.perlig.de/rjsmin/${P}.tar.bz2"
RESTRICT="mirror"
LICENSE="Apache-2"
SLOT="0"
KEYWORDS="~amd64 ~ppc ~x86 ~x86-fbsd ~amd64-linux ~x86-linux ~ppc-macos ~x64-macos ~x86-macos"
IUSE="doc"
DOCS=( README.rst docs/CHANGES )
HTML_DOCS=( docs/apidoc )
python_install() {
distutils-r1_python_install --without-docs
}

243
_pkg/pylint.conf Normal file
View File

@ -0,0 +1,243 @@
# pylint-version: 0.21.0
[MASTER]
# Specify a configuration file.
#rcfile=
# Python code to execute, usually for sys.path manipulation such as
# pygtk.require().
#init-hook=
# Profiled execution.
profile=no
# Add <file or directory> to the black list. It should be a base name, not a
# path. You may set this option multiple times.
ignore=
.svn, _tdi_impl.so
# Pickle collected data for later comparisons.
persistent=no
# List of plugins (as comma separated values of python modules names) to load,
# usually to register additional checkers.
load-plugins=
[MESSAGES CONTROL]
# Enable the message, report, category or checker with the given id(s). You can
# either give multiple identifier separated by comma (,) or put this option
# multiple time.
#enable=
# Disable the message, report, category or checker with the given id(s). You
# can either give multiple identifier separated by comma (,) or put this option
# multiple time.
disable=
I0011,
W0142,
R0201, R0923,
[REPORTS]
# Set the output format. Available formats are text, parseable, colorized, msvs
# (visual studio) and html
output-format=parseable
# Include message's id in output
include-ids=yes
# Put messages in a separate file for each module / package specified on the
# command line instead of printing them on stdout. Reports (if any) will be
# written in a file name "pylint_global.[txt|html]".
files-output=no
# Tells whether to display a full report or only the messages
reports=no
# Python expression which should return a note less than 10 (10 is the highest
# note). You have access to the variables errors warning, statement which
# respectively contain the number of errors / warnings messages and the total
# number of statements analyzed. This is used by the global evaluation report
# (R0004).
evaluation=10.0 - ((float(5 * error + warning + refactor + convention) / statement) * 10)
# Add a comment according to your evaluation note. This is used by the global
# evaluation report (R0004).
comment=no
[FORMAT]
# Maximum number of characters on a single line.
max-line-length=78
# Maximum number of lines in a module
max-module-lines=1500
# String used as indentation unit. This is usually " " (4 spaces) or "\t" (1
# tab).
indent-string=' '
[VARIABLES]
# Tells whether we should check for unused import in __init__ files.
init-import=yes
# A regular expression matching names used for dummy variables (i.e. not used).
dummy-variables-rgx=_|dummy|(?:kw)?args
# List of additional names supposed to be defined in builtins. Remember that
# you should avoid to define new builtins when possible.
additional-builtins=
[TYPECHECK]
# Tells whether missing members accessed in mixin class should be ignored. A
# mixin class is detected if its name ends with "mixin" (case insensitive).
ignore-mixin-members=yes
# List of classes names for which member attributes should not be checked
# (useful for classes with attributes dynamically set).
ignored-classes=
# When zope mode is activated, add a predefined set of Zope acquired attributes
# to generated-members.
zope=no
# List of members which are set dynamically and missed by pylint inference
# system, and so shouldn't trigger E0201 when accessed.
generated-members=
[SIMILARITIES]
# Minimum lines number of a similarity.
min-similarity-lines=4
# Ignore comments when computing similarities.
ignore-comments=yes
# Ignore docstrings when computing similarities.
ignore-docstrings=yes
[MISCELLANEOUS]
# List of note tags to take in consideration, separated by a comma.
notes=FIXME,XXX,TODO
[BASIC]
# Required attributes for module, separated by a comma
required-attributes=
__author__, __docformat__
# List of builtins function names that should not be used, separated by a comma
bad-functions=
apply,input,exec,hasattr
# Regular expression which should only match correct module names
module-rgx=[a-z_][a-z0-9_]*$
# Regular expression which should only match correct module level names
const-rgx=(?:_?[A-Z][A-Z0-9_]{1,30}|_?[A-Z][a-zA-Z0-9]{2,30}|_?[a-z_][a-z0-9_]{2,30}|__.*__)$
# Regular expression which should only match correct class names
class-rgx=_?[A-Z][a-zA-Z0-9]+$
# Regular expression which should only match correct function names
function-rgx=(?:__[a-z]+__|_?[a-z_][a-z0-9_]*)$
# Regular expression which should only match correct method names
method-rgx=(?:__[a-z]+__|_?[a-z_][a-z0-9_]*)$
# Regular expression which should only match correct instance attribute names
attr-rgx=(?:[A-Z][A-Z0-9_]{2,30}|[a-z_][a-z0-9_]{2,30})$
# Regular expression which should only match correct argument names
argument-rgx=[a-z_][a-z0-9_]{2,30}$
# Regular expression which should only match correct variable names
variable-rgx=(?:[A-Z_][A-Z0-9_]{1,30}|[a-z_][a-z0-9_]{2,30})$
# Regular expression which should only match correct list comprehension /
# generator expression variable names
inlinevar-rgx=[A-Za-z_][A-Za-z0-9_]{,10}$
# Good variable names which should always be accepted, separated by a comma
good-names=_,j,e,c
# Bad variable names which should always be refused, separated by a comma
bad-names=foo,bar,baz,toto,tutu,tata
# Regular expression which should only match functions or classes name which do
# not require a docstring
no-docstring-rgx=__.*__
[DESIGN]
# Maximum number of arguments for function / method
max-args=10
# Argument names that match this expression will be ignored. Default to name
# with leading underscore
ignored-argument-names=_.*
# Maximum number of locals for function / method body
max-locals=20
# Maximum number of return / yield for function / method body
max-returns=6
# Maximum number of branch for function / method body
max-branchs=12
# Maximum number of statements in function / method body
max-statements=50
# Maximum number of parents for a class (see R0901).
max-parents=7
# Maximum number of attributes for a class (see R0902).
max-attributes=20
# Minimum number of public methods for a class (see R0903).
min-public-methods=0
# Maximum number of public methods for a class (see R0904).
max-public-methods=50
[IMPORTS]
# Deprecated modules which should not be used, separated by a comma
deprecated-modules=regsub,TERMIOS,Bastion,rexec
# Create a graph of every (i.e. internal and external) dependencies in the
# given file (report R0402 must not be disabled)
import-graph=
# Create a graph of external dependencies in the given file (report R0402 must
# not be disabled)
ext-import-graph=
# Create a graph of internal dependencies in the given file (report R0402 must
# not be disabled)
int-import-graph=
[CLASSES]
# List of interface methods to ignore, separated by a comma. This is used for
# instance to not check methods defines in Zope's Interface base class.
ignore-iface-methods=
# List of method names used to declare (i.e. assign) instance attributes.
defining-attr-methods=__init__,__new__

39
_setup/__init__.py Normal file
View File

@ -0,0 +1,39 @@
# -*- coding: ascii -*-
#
# Copyright 2007, 2008, 2009, 2010, 2011
# Andr\xe9 Malo or his licensors, as applicable
#
# Licensed 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.
"""
================
Package _setup
================
This package provides tools for main package setup.
"""
__author__ = "Andr\xe9 Malo"
__docformat__ = "restructuredtext en"
import os as _os
import sys as _sys
if _sys.version_info[0] == 2:
__path__ = [_os.path.join(__path__[0], 'py2')]
__author__ = __author__.decode('latin-1')
elif _sys.version_info[0] == 3:
__path__ = [_os.path.join(__path__[0], 'py3')]
else:
raise RuntimeError("Unsupported python version")
del _os, _sys
from _setup.setup import run # pylint: disable = W0611

244
_setup/include/cext.h Normal file
View File

@ -0,0 +1,244 @@
/*
* Copyright 2006, 2007, 2008, 2009, 2010, 2011
* Andr\xe9 Malo or his licensors, as applicable
*
* Licensed 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.
*/
/*
* central naming stuff
*/
#ifndef SETUP_CEXT_H
#define SETUP_CEXT_H
#ifndef EXT_MODULE
#error EXT_MODULE must be defined outside of this file (-DEXT_MODULE=...)
#endif
/*
* include core header files
*/
#define PY_SSIZE_T_CLEAN
#include "Python.h"
#include "structmember.h"
/*
* define our helper macros depending on the stuff above
*/
#define STRINGIFY(n) STRINGIFY_HELPER(n)
#define STRINGIFY_HELPER(n) #n
#define CONCATENATE(first, second) CONCATENATE_HELPER(first, second)
#define CONCATENATE_HELPER(first, second) first##second
#define EXT_MODULE_NAME STRINGIFY(EXT_MODULE)
#ifdef EXT_PACKAGE
#define EXT_PACKAGE_NAME STRINGIFY(EXT_PACKAGE)
#define EXT_MODULE_PATH EXT_PACKAGE_NAME "." EXT_MODULE_NAME
#else
#define EXT_PACKAGE_NAME ""
#define EXT_MODULE_PATH EXT_MODULE_NAME
#endif
#define EXT_DOCS_VAR CONCATENATE(var, CONCATENATE(EXT_MODULE, __doc__))
#define EXT_METHODS_VAR CONCATENATE(var, CONCATENATE(EXT_MODULE, _methods))
#define EXT_METHODS static PyMethodDef EXT_METHODS_VAR[]
#define EXT_DEFINE_VAR CONCATENATE(var, CONCATENATE(EXT_MODULE, _module))
/* Py3K Support */
#if PY_MAJOR_VERSION >= 3
#define EXT3
#ifndef PyMODINIT_FUNC
#define EXT_INIT_FUNC PyObject *CONCATENATE(PyInit_, EXT_MODULE)(void)
#else
#define EXT_INIT_FUNC PyMODINIT_FUNC CONCATENATE(PyInit_, EXT_MODULE)(void)
#endif
#define EXT_DEFINE(name, methods, doc) \
static struct PyModuleDef EXT_DEFINE_VAR = { \
PyModuleDef_HEAD_INIT, \
name, \
doc, \
-1, \
methods, \
NULL, \
NULL, \
NULL, \
NULL \
}
#define EXT_CREATE(def) (PyModule_Create(def))
#define EXT_INIT_ERROR(module) do {Py_XDECREF(module); return NULL;} while(0)
#define EXT_INIT_RETURN(module) return module
#else /* end py3k */
#define EXT2
#ifndef PyMODINIT_FUNC
#define EXT_INIT_FUNC void CONCATENATE(init, EXT_MODULE)(void)
#else
#define EXT_INIT_FUNC PyMODINIT_FUNC CONCATENATE(init, EXT_MODULE)(void)
#endif
#define EXT_DEFINE__STRUCT \
CONCATENATE(struct, CONCATENATE(EXT_MODULE, _module))
struct EXT_DEFINE__STRUCT {
char *m_name;
char *m_doc;
PyMethodDef *m_methods;
};
#define EXT_DEFINE(name, methods, doc) \
static struct EXT_DEFINE__STRUCT EXT_DEFINE_VAR = { \
name, \
doc, \
methods \
}
#define EXT_CREATE(def) ((def)->m_doc \
? Py_InitModule3((def)->m_name, (def)->m_methods, (def)->m_doc) \
: Py_InitModule((def)->m_name, (def)->m_methods) \
)
#define EXT_INIT_ERROR(module) return
#define EXT_INIT_RETURN(module) return
#endif /* end py2K */
#define EXT_INIT_TYPE(module, type) do { \
if (PyType_Ready(type) < 0) \
EXT_INIT_ERROR(module); \
} while (0)
#define EXT_ADD_TYPE(module, name, type) do { \
Py_INCREF(type); \
if (PyModule_AddObject(module, name, (PyObject *)(type)) < 0) \
EXT_INIT_ERROR(module); \
} while (0)
#define EXT_ADD_UNICODE(module, name, string, encoding) do { \
if (PyModule_AddObject( \
module, \
name, \
PyUnicode_Decode( \
string, \
sizeof(string) - 1, \
encoding, \
"strict" \
)) < 0) \
EXT_INIT_ERROR(module); \
} while (0)
#define EXT_ADD_STRING(module, name, string) do { \
if (PyModule_AddStringConstant(module, name, string) < 0) \
EXT_INIT_ERROR(module); \
} while (0)
#define EXT_ADD_INT(module, name, number) do { \
if (PyModule_AddIntConstant(module, name, number) < 0) \
EXT_INIT_ERROR(module); \
} while (0)
/* PEP 353 support, implemented as of python 2.5 */
#if PY_VERSION_HEX < 0x02050000
typedef int Py_ssize_t;
#define PyInt_FromSsize_t(arg) PyInt_FromLong((long)arg)
#define PyInt_AsSsize_t(arg) (int)PyInt_AsLong(arg)
#define PY_SSIZE_T_MAX ((Py_ssize_t)INT_MAX)
#endif
/*
* some helper macros (Python 2.4)
*/
#ifndef Py_VISIT
#define Py_VISIT(op) do { \
if (op) { \
int vret = visit((op), arg); \
if (vret) return vret; \
} \
} while (0)
#endif
#ifdef Py_CLEAR
#undef Py_CLEAR
#endif
#define Py_CLEAR(op) do { \
if (op) { \
PyObject *tmp__ = (PyObject *)(op); \
(op) = NULL; \
Py_DECREF(tmp__); \
} \
} while (0)
#ifndef Py_RETURN_NONE
#define Py_RETURN_NONE return Py_INCREF(Py_None), Py_None
#endif
#ifndef Py_RETURN_FALSE
#define Py_RETURN_FALSE return Py_INCREF(Py_False), Py_False
#endif
#ifndef Py_RETURN_TRUE
#define Py_RETURN_TRUE return Py_INCREF(Py_True), Py_True
#endif
/* Macros for inline documentation. (Python 2.3) */
#ifndef PyDoc_VAR
#define PyDoc_VAR(name) static char name[]
#endif
#ifndef PyDoc_STRVAR
#define PyDoc_STRVAR(name,str) PyDoc_VAR(name) = PyDoc_STR(str)
#endif
#ifndef PyDoc_STR
#ifdef WITH_DOC_STRINGS
#define PyDoc_STR(str) str
#else
#define PyDoc_STR(str) ""
#endif
#endif
/* Basestring check (basestring introduced in Python 2.3) */
#if PY_VERSION_HEX < 0x02030000
#define BaseString_Check(type) ( \
PyObject_TypeCheck((type), &PyString_Type) \
|| PyObject_TypeCheck((type), &PyUnicode_Type) \
)
#else
#define BaseString_Check(type) PyObject_TypeCheck((type), &PyBaseString_Type)
#endif
#define GENERIC_ALLOC(type) \
((void *)((PyTypeObject *)type)->tp_alloc(type, (Py_ssize_t)0))
/* PyPy doesn't define it */
#ifndef PyType_IS_GC
#define PyType_IS_GC(t) PyType_HasFeature((t), Py_TPFLAGS_HAVE_GC)
#endif
#define DEFINE_GENERIC_DEALLOC(prefix) \
static void prefix##_dealloc(void *self) \
{ \
if (PyType_IS_GC(((PyObject *)self)->ob_type)) \
PyObject_GC_UnTrack(self); \
(void)prefix##_clear(self); \
((PyObject *)self)->ob_type->tp_free((PyObject *)self); \
}
#endif /* SETUP_CEXT_H */

27
_setup/py2/__init__.py Normal file
View File

@ -0,0 +1,27 @@
# -*- coding: ascii -*-
#
# Copyright 2007, 2008, 2009, 2010, 2011
# Andr\xe9 Malo or his licensors, as applicable
#
# Licensed 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.
"""
================
Package _setup
================
This package provides tools for main package setup.
"""
__author__ = u"Andr\xe9 Malo"
__docformat__ = "restructuredtext en"
from _setup.setup import run # pylint: disable = W0611

267
_setup/py2/commands.py Normal file
View File

@ -0,0 +1,267 @@
# -*- coding: ascii -*-
#
# Copyright 2007, 2008, 2009, 2010, 2011
# Andr\xe9 Malo or his licensors, as applicable
#
# Licensed 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.
"""
===================
Command extenders
===================
Command extenders.
"""
__author__ = u"Andr\xe9 Malo"
__docformat__ = "restructuredtext en"
__test__ = False
from distutils import fancy_getopt as _fancy_getopt
from distutils.command import build as _build
from distutils.command import build_ext as _build_ext
from distutils.command import install as _install
from distutils.command import install_data as _install_data
from distutils.command import install_lib as _install_lib
import os as _os
from _setup.util import log
_option_defaults = {}
_option_inherits = {}
_option_finalizers = {}
_command_mapping = {
'install': 'Install',
'install_data': 'InstallData',
'install_lib': 'InstallLib',
'build': 'Build',
'build_ext': 'BuildExt',
}
def add_option(command, long_name, help_text, short_name=None, default=None,
inherit=None):
""" Add an option """
try:
command_class = globals()[_command_mapping[command]]
except KeyError:
raise ValueError("Unknown command %r" % (command,))
for opt in command_class.user_options:
if opt[0] == long_name:
break
else:
opt = (long_name, short_name, help_text)
command_class.user_options.append(opt)
if not long_name.endswith('='):
command_class.boolean_options.append(long_name)
attr_name = _fancy_getopt.translate_longopt(long_name)
else:
attr_name = _fancy_getopt.translate_longopt(long_name[:-1])
if not _option_defaults.has_key(command):
_option_defaults[command] = []
if inherit is not None:
if isinstance(inherit, (str, unicode)):
inherit = [inherit]
for i_inherit in inherit:
add_option(
i_inherit, long_name, help_text, short_name, default
)
default = None
if not _option_inherits.has_key(command):
_option_inherits[command] = []
for i_inherit in inherit:
for i_command, opt_name in _option_inherits[command]:
if i_command == i_inherit and opt_name == attr_name:
break
else:
_option_inherits[command].append((i_inherit, attr_name))
_option_defaults[command].append((attr_name, default))
def add_finalizer(command, key, func):
""" Add finalizer """
if not _option_finalizers.has_key(command):
_option_finalizers[command] = {}
if not _option_finalizers[command].has_key(key):
_option_finalizers[command][key] = func
class Install(_install.install):
""" Extended installer to reflect the additional data options """
user_options = _install.install.user_options + [
('single-version-externally-managed', None,
"Compat option. Does not a thing."),
]
boolean_options = _install.install.boolean_options + [
'single-version-externally-managed'
]
def initialize_options(self):
""" Prepare for new options """
_install.install.initialize_options(self)
self.single_version_externally_managed = None
if _option_defaults.has_key('install'):
for opt_name, default in _option_defaults['install']:
setattr(self, opt_name, default)
def finalize_options(self):
""" Finalize options """
_install.install.finalize_options(self)
if _option_inherits.has_key('install'):
for parent, opt_name in _option_inherits['install']:
self.set_undefined_options(parent, (opt_name, opt_name))
if _option_finalizers.has_key('install'):
for func in _option_finalizers['install'].values():
func(self)
class InstallData(_install_data.install_data):
""" Extended data installer """
user_options = _install_data.install_data.user_options + []
boolean_options = _install_data.install_data.boolean_options + []
def initialize_options(self):
""" Prepare for new options """
_install_data.install_data.initialize_options(self)
if _option_defaults.has_key('install_data'):
for opt_name, default in _option_defaults['install_data']:
setattr(self, opt_name, default)
def finalize_options(self):
""" Finalize options """
_install_data.install_data.finalize_options(self)
if _option_inherits.has_key('install_data'):
for parent, opt_name in _option_inherits['install_data']:
self.set_undefined_options(parent, (opt_name, opt_name))
if _option_finalizers.has_key('install_data'):
for func in _option_finalizers['install_data'].values():
func(self)
class InstallLib(_install_lib.install_lib):
""" Extended lib installer """
user_options = _install_lib.install_lib.user_options + []
boolean_options = _install_lib.install_lib.boolean_options + []
def initialize_options(self):
""" Prepare for new options """
_install_lib.install_lib.initialize_options(self)
if _option_defaults.has_key('install_lib'):
for opt_name, default in _option_defaults['install_lib']:
setattr(self, opt_name, default)
def finalize_options(self):
""" Finalize options """
_install_lib.install_lib.finalize_options(self)
if _option_inherits.has_key('install_lib'):
for parent, opt_name in _option_inherits['install_lib']:
self.set_undefined_options(parent, (opt_name, opt_name))
if _option_finalizers.has_key('install_lib'):
for func in _option_finalizers['install_lib'].values():
func(self)
class BuildExt(_build_ext.build_ext):
"""
Extended extension builder class
This class allows extensions to provide a ``check_prerequisites`` method
which is called before actually building it. The method takes the
`BuildExt` instance and returns whether the extension should be skipped or
not.
"""
def initialize_options(self):
""" Prepare for new options """
_build_ext.build_ext.initialize_options(self)
if _option_defaults.has_key('build_ext'):
for opt_name, default in _option_defaults['build_ext']:
setattr(self, opt_name, default)
def finalize_options(self):
""" Finalize options """
_build_ext.build_ext.finalize_options(self)
if _option_inherits.has_key('build_ext'):
for parent, opt_name in _option_inherits['build_ext']:
self.set_undefined_options(parent, (opt_name, opt_name))
if _option_finalizers.has_key('build_ext'):
for func in _option_finalizers['build_ext'].values():
func(self)
def build_extension(self, ext):
"""
Build C extension - with extended functionality
The following features are added here:
- ``ext.check_prerequisites`` is called before the extension is being
built. See `Extension` for details. If the method does not exist,
simply no check will be run.
- The macros ``EXT_PACKAGE`` and ``EXT_MODULE`` will be filled (or
unset) depending on the extensions name, but only if they are not
already defined.
:Parameters:
`ext` : `Extension`
The extension to build. If it's a pure
``distutils.core.Extension``, simply no prequisites check is
applied.
:Return: whatever ``distutils.command.build_ext.build_ext`` returns
:Rtype: any
"""
# handle name macros
macros = dict(ext.define_macros or ())
tup = ext.name.split('.')
if len(tup) == 1:
pkg, mod = None, tup[0]
else:
pkg, mod = '.'.join(tup[:-1]), tup[-1]
if pkg is not None and 'EXT_PACKAGE' not in macros:
ext.define_macros.append(('EXT_PACKAGE', pkg))
if 'EXT_MODULE' not in macros:
ext.define_macros.append(('EXT_MODULE', mod))
if pkg is None:
macros = dict(ext.undef_macros or ())
if 'EXT_PACKAGE' not in macros:
ext.undef_macros.append('EXT_PACKAGE')
# handle prereq checks
try:
checker = ext.check_prerequisites
except AttributeError:
pass
else:
if checker(self):
log.info("Skipping %s extension" % ext.name)
return
return _build_ext.build_ext.build_extension(self, ext)
class Build(_build.build):
def initialize_options(self):
""" Prepare for new options """
_build.build.initialize_options(self)
if _option_defaults.has_key('build'):
for opt_name, default in _option_defaults['build']:
setattr(self, opt_name, default)
def finalize_options(self):
""" Finalize options """
_build.build.finalize_options(self)
if _option_inherits.has_key('build'):
for parent, opt_name in _option_inherits['build']:
self.set_undefined_options(parent, (opt_name, opt_name))
if _option_finalizers.has_key('build'):
for func in _option_finalizers['build'].values():
func(self)

165
_setup/py2/data.py Normal file
View File

@ -0,0 +1,165 @@
# -*- coding: ascii -*-
#
# Copyright 2007, 2008, 2009, 2010, 2011
# Andr\xe9 Malo or his licensors, as applicable
#
# Licensed 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.
"""
===================
Data distribution
===================
This module provides tools to simplify data distribution.
"""
__author__ = u"Andr\xe9 Malo"
__docformat__ = "restructuredtext en"
from distutils import filelist as _filelist
import os as _os
import posixpath as _posixpath
import sys as _sys
from _setup import commands as _commands
def splitpath(path):
""" Split a path """
drive, path = '', _os.path.normpath(path)
try:
splitunc = _os.path.splitunc
except AttributeError:
pass
else:
drive, path = splitunc(path)
if not drive:
drive, path = _os.path.splitdrive(path)
elems = []
try:
sep = _os.path.sep
except AttributeError:
sep = _os.path.join('1', '2')[1:-1]
while 1:
prefix, path = _os.path.split(path)
elems.append(path)
if prefix in ('', sep):
drive = _os.path.join(drive, prefix)
break
path = prefix
elems.reverse()
return drive, elems
def finalizer(installer):
""" Finalize install_data """
data_files = []
for item in installer.data_files:
if not isinstance(item, Data):
data_files.append(item)
continue
data_files.extend(item.flatten(installer))
installer.data_files = data_files
class Data(object):
""" File list container """
def __init__(self, files, target=None, preserve=0, strip=0,
prefix=None):
""" Initialization """
self._files = files
self._target = target
self._preserve = preserve
self._strip = strip
self._prefix = prefix
self.fixup_commands()
def fixup_commands(self):
pass
def from_templates(cls, *templates, **kwargs):
""" Initialize from template """
files = _filelist.FileList()
for tpl in templates:
for line in tpl.split(';'):
files.process_template_line(line.strip())
files.sort()
files.remove_duplicates()
result = []
for filename in files.files:
_, elems = splitpath(filename)
if '.svn' in elems:
continue
result.append(filename)
return cls(result, **kwargs)
from_templates = classmethod(from_templates)
def flatten(self, installer):
""" Flatten the file list to (target, file) tuples """
# pylint: disable = W0613
if self._prefix:
_, prefix = splitpath(self._prefix)
telems = prefix
else:
telems = []
tmap = {}
for fname in self._files:
(_, name), target = splitpath(fname), telems
if self._preserve:
if self._strip:
name = name[max(0, min(self._strip, len(name) - 1)):]
if len(name) > 1:
target = telems + name[:-1]
tmap.setdefault(_posixpath.join(*target), []).append(fname)
return tmap.items()
class Documentation(Data):
""" Documentation container """
def fixup_commands(self):
_commands.add_option('install_data', 'without-docs',
help_text='Do not install documentation files',
inherit='install',
)
_commands.add_finalizer('install_data', 'documentation', finalizer)
def flatten(self, installer):
""" Check if docs should be installed at all """
if installer.without_docs:
return []
return Data.flatten(self, installer)
class Manpages(Documentation):
""" Manpages container """
def dispatch(cls, files):
""" Automatically dispatch manpages to their target directories """
mpmap = {}
for manpage in files:
normalized = _os.path.normpath(manpage)
_, ext = _os.path.splitext(normalized)
if ext.startswith(_os.path.extsep):
ext = ext[len(_os.path.extsep):]
mpmap.setdefault(ext, []).append(manpage)
return [cls(manpages, prefix=_posixpath.join(
'share', 'man', 'man%s' % section,
)) for section, manpages in mpmap.items()]
dispatch = classmethod(dispatch)
def flatten(self, installer):
""" Check if manpages are suitable """
if _sys.platform == 'win32':
return []
return Documentation.flatten(self, installer)

View File

@ -0,0 +1,25 @@
# -*- coding: ascii -*-
#
# Copyright 2009, 2010, 2011
# Andr\xe9 Malo or his licensors, as applicable
#
# Licensed 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.
"""
====================
Package _setup.dev
====================
Development tools, not distributed.
"""
__author__ = u"Andr\xe9 Malo"
__docformat__ = "restructuredtext en"

258
_setup/py2/dev/_pylint.py Normal file
View File

@ -0,0 +1,258 @@
# -*- coding: ascii -*-
#
# Copyright 2006, 2007, 2008, 2009, 2010, 2011
# Andr\xe9 Malo or his licensors, as applicable
#
# Licensed 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.
"""
=================================
Support for code analysis tools
=================================
Support for code analysis tools.
"""
__author__ = u"Andr\xe9 Malo"
__docformat__ = "restructuredtext en"
import re as _re
import sys as _sys
from _setup import term as _term
from _setup import shell as _shell
class NotFinished(Exception):
""" Exception used for message passing in the stream filter """
class NotParseable(Exception):
""" Exception used for message passing in the stream filter """
class SpecialMessage(Exception):
""" Exception used for message passing in the stream filter """
class FilterStream(object):
""" Stream filter """
_LINERE = _re.compile(r'''
(?P<name>[^:]+)
:
(?P<lineno>\d+)
:\s+
\[(?P<mid>[^\],]+)(?:,\s+(?P<func>[^\]]+))?\]
\s+
(?P<desc>.*)
''', _re.X)
_SIMRE = _re.compile(r'in (?P<number>\d+) files')
_CYCRE = _re.compile(r'\((?P<cycle>[^)]+)\)')
def __init__(self, term, stream=_sys.stdout):
self.written = False
self._stream = stream
self._lastname = None
self._cycled = False
self._term = dict(term)
self._buffer = ''
def write(self, towrite):
""" Stream write function """
self._buffer += towrite
term = self._term
while True:
try:
name, lineno, mid, func, desc = self._parse()
except NotFinished:
break
except SpecialMessage, e:
self._dospecial(e)
continue
except NotParseable, e:
self._print_literal(str(e.args[0]))
continue
if name != self._lastname:
if self._lastname is not None:
self._stream.write("\n")
term['path'] = name
self._stream.write(
"%(BOLD)s>>> %(path)s%(NORMAL)s\n" % term
)
self._lastname = name
self.written = True
term['mid'] = mid
if mid.startswith('E') or mid.startswith('F'):
self._stream.write("%(BOLD)s%(RED)s%(mid)s%(NORMAL)s" % term)
elif mid == 'W0511':
self._stream.write(
"%(BOLD)s%(GREEN)s%(mid)s%(NORMAL)s" % term
)
else:
self._stream.write(
"%(BOLD)s%(YELLOW)s%(mid)s%(NORMAL)s" % term
)
if int(lineno) != 0:
term['lineno'] = lineno
self._stream.write(" (%(lineno)s" % term)
if func:
term['func'] = func
self._stream.write(
", %(BOLD)s%(YELLOW)s%(func)s%(NORMAL)s" % term
)
self._stream.write(')')
self._stream.write(": %s\n" % desc)
self._stream.flush()
return
def _print_literal(self, line):
""" Print literal """
suppress = (
line.startswith('Unable to get imported names for ') or
line.startswith("Exception exceptions.RuntimeError: 'generator "
"ignored GeneratorExit' in <generator object at") or
line.startswith("Exception RuntimeError: 'generator "
"ignored GeneratorExit' in <generator object") or
not line.strip()
)
if not suppress:
self._stream.write("%s\n" % line)
self._stream.flush()
self.written = True
def _dospecial(self, e):
""" Deal with special messages """
if e.args[0] == 'R0401':
pos = self._buffer.find('\n')
line, self._buffer = (
self._buffer[:pos + 1], self._buffer[pos + 1:]
)
term = self._term
term['mid'] = e.args[0]
if not self._cycled:
self._cycled = True
self._stream.write('\n')
self._stream.write(
"%(BOLD)s%(YELLOW)s%(mid)s%(NORMAL)s" % term
)
self._stream.write(": Cyclic imports\n")
match = self._CYCRE.search(e.args[1])
term['cycle'] = match.group('cycle')
self._stream.write("%(BOLD)s@@@ %(NORMAL)s%(cycle)s\n" % term)
self._stream.flush()
self.written = True
elif e.args[0] == 'R0801':
match = self._SIMRE.search(e.args[1])
if not match:
raise AssertionError(
'Could not determine number of similar files'
)
numfiles = int(match.group('number'))
pos = -1
for _ in range(numfiles + 1):
pos = self._buffer.find('\n', pos + 1)
if pos >= 0:
lines = self._buffer[:pos + 1]
self._buffer = self._buffer[pos + 1:]
term = self._term
self._stream.write("\n")
for name in lines.splitlines()[1:]:
name = name.rstrip()[2:]
term['path'] = name
self._stream.write(
"%(BOLD)s=== %(path)s%(NORMAL)s\n" % term
)
self._lastname = name
term['mid'] = e.args[0]
self._stream.write(
"%(BOLD)s%(YELLOW)s%(mid)s%(NORMAL)s" % term
)
self._stream.write(": %s\n" % e.args[1])
self._stream.flush()
self.written = True
def _parse(self):
""" Parse output """
if '\n' not in self._buffer:
raise NotFinished()
line = self._buffer[:self._buffer.find('\n') + 1]
self._buffer = self._buffer[len(line):]
line = line.rstrip()
match = self._LINERE.match(line)
if not match:
raise NotParseable(line)
mid = match.group('mid')
if mid in ('R0801', 'R0401'):
self._buffer = "%s\n%s" % (line, self._buffer)
raise SpecialMessage(mid, match.group('desc'))
return match.group('name', 'lineno', 'mid', 'func', 'desc')
def run(config, *args):
""" Run pylint """
try:
from pylint import lint
from pylint.reporters import text
except ImportError:
return 2
if config is None:
config = _shell.native('pylint.conf')
argv = ['--rcfile', config,
'--reports', 'no',
'--output-format', 'parseable',
'--include-ids', 'yes'
]
stream = FilterStream(_term.terminfo())
old_stderr = _sys.stderr
try:
# pylint: disable = E1101
_sys.stderr = stream
from pylint import __pkginfo__
if __pkginfo__.numversion < (0, 13):
# The lint tool is not very user friendly, so we need a hack here.
lint.REPORTER_OPT_MAP['parseable'] = \
lambda: text.TextReporter2(stream)
reporter = text.TextReporter2(stream)
else:
reporter = text.ParseableTextReporter(stream)
lint.REPORTER_OPT_MAP['parseable'] = lambda: reporter
for path in args:
try:
try:
lint.Run(argv + [path], reporter=reporter)
except SystemExit:
pass # don't accept the exit. strange errors happen...
if stream.written:
print
stream.written = False
except KeyboardInterrupt:
print
raise
finally:
_sys.stderr = old_stderr
return 0

View File

@ -0,0 +1,31 @@
# -*- coding: ascii -*-
#
# Copyright 2006, 2007, 2008, 2009, 2010, 2011
# Andr\xe9 Malo or his licensors, as applicable
#
# Licensed 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.
"""
=================================
Support for code analysis tools
=================================
Support for code analysis tools.
"""
__author__ = u"Andr\xe9 Malo"
__docformat__ = "restructuredtext en"
def pylint(config, *args):
""" Run pylint """
from _setup.dev import _pylint
return _pylint.run(config, *args)

131
_setup/py2/dev/apidoc.py Normal file
View File

@ -0,0 +1,131 @@
# -*- coding: ascii -*-
#
# Copyright 2007, 2008, 2009, 2010, 2011
# Andr\xe9 Malo or his licensors, as applicable
#
# Licensed 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.
"""
==================
API doc builders
==================
API doc builders.
"""
__author__ = u"Andr\xe9 Malo"
__docformat__ = "restructuredtext en"
import os as _os
import re as _re
from _setup import shell as _shell
from _setup import term as _term
from _setup import util as _util
def _cleanup_epydoc(target):
"""
Cleanup epydoc generated files
This removes the epydoc-footer. It changes every release because of the
timestamp. That creates bad diffs (accidently it's also invalid html).
"""
search = _re.compile(r'<table[^<>]+width="100%%"').search
for filename in _shell.files(target, '*.html'):
fp = open(filename, 'r')
try:
html = fp.read()
finally:
fp.close()
match = search(html)
if match:
start = match.start()
end = html.find('</table>', start)
if end >= 0:
end += len('</table>') + 1
html = html[:start] + html[end:]
fp = open(filename, 'w')
try:
fp.write(html)
finally:
fp.close()
_VERSION_SEARCH = _re.compile(
r'\bversion\s+(?P<major>\d+)\.(?P<minor>\d+)'
).search
def epydoc(**kwargs):
""" Run epydoc """
# pylint: disable = R0912
prog = kwargs.get('epydoc') or 'epydoc'
if not _os.path.dirname(_os.path.normpath(prog)):
prog = _shell.frompath(prog)
if not prog:
_term.red("%(epydoc)s not found",
epydoc=kwargs.get('epydoc') or 'epydoc',
)
return False
version = _VERSION_SEARCH(_shell.spawn(prog, "--version", stdout=True))
if version is not None:
try:
version = tuple(map(int, version.group('major', 'minor')))
except (TypeError, ValueError):
version = None
if version is None:
_term.red("%(prog)s version not recognized" % locals())
return False
if version < (3, 0):
_term.red("%(prog)s is too old %(version)r < (3, 0)" % locals())
return False
env = dict(_os.environ)
prepend = kwargs.get('prepend')
if prepend:
toprepend = _os.pathsep.join(map(str, prepend))
if 'PYTHONPATH' in env:
env['PYTHONPATH'] = _os.pathsep.join((
toprepend, env['PYTHONPATH']
))
else:
env['PYTHONPATH'] = toprepend
append = kwargs.get('append')
if append:
toappend = _os.pathsep.join(map(str, append))
if 'PYTHONPATH' in env:
env['PYTHONPATH'] = _os.pathsep.join((
env['PYTHONPATH'], toappend
))
else:
env['PYTHONPATH'] = toappend
moreenv = kwargs.get('env')
if moreenv:
env.update(moreenv)
config = kwargs.get('config') or _shell.native('docs/epydoc.conf')
argv = [prog, '--config', config]
res = not _shell.spawn(*argv, **{'env': env})
if res:
cfg = _util.SafeConfigParser()
cfg.read(config)
try:
target = dict(cfg.items('epydoc'))['target']
except KeyError:
pass
else:
_cleanup_epydoc(target)
return res

50
_setup/py2/dev/userdoc.py Normal file
View File

@ -0,0 +1,50 @@
# -*- coding: ascii -*-
#
# Copyright 2009, 2010, 2011
# Andr\xe9 Malo or his licensors, as applicable
#
# Licensed 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.
"""
===================
User doc builders
===================
User doc builders.
"""
__author__ = u"Andr\xe9 Malo"
__docformat__ = "restructuredtext en"
import os as _os
from _setup import shell as _shell
from _setup import term as _term
def sphinx(**kwargs):
""" Run sphinx """
prog = _shell.frompath('sphinx-build')
if prog is None:
_term.red("sphinx-build not found")
return False
env = dict(_os.environ)
argv = [
prog, '-a',
'-d', _os.path.join(kwargs['build'], 'doctrees'),
'-b', 'html',
kwargs['source'],
kwargs['target'],
]
return not _shell.spawn(*argv, **{'env': env})

51
_setup/py2/dist.py Normal file
View File

@ -0,0 +1,51 @@
# -*- coding: ascii -*-
#
# Copyright 2007, 2008, 2009, 2010, 2011
# Andr\xe9 Malo or his licensors, as applicable
#
# Licensed 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.
"""
================
dist utilities
================
dist utilities.
"""
__author__ = u"Andr\xe9 Malo"
__docformat__ = "restructuredtext en"
import sys as _sys
from _setup import shell as _shell
def run_setup(*args, **kwargs):
""" Run setup """
if 'setup' in kwargs:
script = kwargs.get('setup') or 'setup.py'
del kwargs['setup']
else:
script = 'setup.py'
if 'fakeroot' in kwargs:
fakeroot = kwargs['fakeroot']
del kwargs['fakeroot']
else:
fakeroot = None
if kwargs:
raise TypeError("Unrecognized keyword parameters")
script = _shell.native(script)
argv = [_sys.executable, script] + list(args)
if fakeroot:
argv.insert(0, fakeroot)
return not _shell.spawn(*argv)

254
_setup/py2/ext.py Normal file
View File

@ -0,0 +1,254 @@
# -*- coding: ascii -*-
#
# Copyright 2007, 2008, 2009, 2010, 2011
# Andr\xe9 Malo or his licensors, as applicable
#
# Licensed 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.
"""
===================
C extension tools
===================
C extension tools.
"""
__author__ = u"Andr\xe9 Malo"
__docformat__ = "restructuredtext en"
__test__ = False
from distutils import core as _core
from distutils import errors as _distutils_errors
import os as _os
import posixpath as _posixpath
import shutil as _shutil
import tempfile as _tempfile
from _setup import commands as _commands
from _setup.util import log
def _install_finalizer(installer):
if installer.without_c_extensions:
installer.distribution.ext_modules = []
def _build_finalizer(builder):
if builder.without_c_extensions:
builder.extensions = []
class Extension(_core.Extension):
"""
Extension with prerequisite check interface
If your check is cacheable (during the setup run), override
`cached_check_prerequisites`, `check_prerequisites` otherwise.
:IVariables:
`cached_check` : ``bool``
The cached check result
"""
cached_check = None
def __init__(self, *args, **kwargs):
""" Initialization """
if kwargs.has_key('depends'):
self.depends = kwargs['depends'] or []
else:
self.depends = []
_core.Extension.__init__(self, *args, **kwargs)
# add include path
included = _posixpath.join('_setup', 'include')
if included not in self.include_dirs:
self.include_dirs.append(included)
# add cext.h to the dependencies
cext_h = _posixpath.join(included, 'cext.h')
if cext_h not in self.depends:
self.depends.append(cext_h)
_commands.add_option('install_lib', 'without-c-extensions',
help_text='Don\'t install C extensions',
inherit='install',
)
_commands.add_finalizer('install_lib', 'c-extensions',
_install_finalizer
)
_commands.add_option('build_ext', 'without-c-extensions',
help_text='Don\'t build C extensions',
inherit=('build', 'install_lib'),
)
_commands.add_finalizer('build_ext', 'c-extensions', _build_finalizer)
def check_prerequisites(self, build):
"""
Check prerequisites
The check should cover all dependencies needed for the extension to
be built and run. The method can do the following:
- return a false value: the extension will be built
- return a true value: the extension will be skipped. This is useful
for optional extensions
- raise an exception. This is useful for mandatory extensions
If the check result is cacheable (during the setup run), override
`cached_check_prerequisites` instead.
:Parameters:
`build` : `BuildExt`
The extension builder
:Return: Skip the extension?
:Rtype: ``bool``
"""
if self.cached_check is None:
log.debug("PREREQ check for %s" % self.name)
self.cached_check = self.cached_check_prerequisites(build)
else:
log.debug("PREREQ check for %s (cached)" % self.name)
return self.cached_check
def cached_check_prerequisites(self, build):
"""
Check prerequisites
The check should cover all dependencies needed for the extension to
be built and run. The method can do the following:
- return a false value: the extension will be built
- return a true value: the extension will be skipped. This is useful
for optional extensions
- raise an exception. This is useful for mandatory extensions
If the check result is *not* cacheable (during the setup run),
override `check_prerequisites` instead.
:Parameters:
`build` : `BuildExt`
The extension builder
:Return: Skip the extension?
:Rtype: ``bool``
"""
# pylint: disable = W0613
log.debug("Nothing to check for %s!" % self.name)
return False
class ConfTest(object):
"""
Single conftest abstraction
:IVariables:
`_tempdir` : ``str``
The tempdir created for this test
`src` : ``str``
Name of the source file
`target` : ``str``
Target filename
`compiler` : ``CCompiler``
compiler instance
`obj` : ``list``
List of object filenames (``[str, ...]``)
"""
_tempdir = None
def __init__(self, build, source):
"""
Initialization
:Parameters:
`build` : ``distuils.command.build_ext.build_ext``
builder instance
`source` : ``str``
Source of the file to compile
"""
self._tempdir = tempdir = _tempfile.mkdtemp()
src = _os.path.join(tempdir, 'conftest.c')
fp = open(src, 'w')
try:
fp.write(source)
finally:
fp.close()
self.src = src
self.compiler = compiler = build.compiler
self.target = _os.path.join(tempdir, 'conftest')
self.obj = compiler.object_filenames([src], output_dir=tempdir)
def __del__(self):
""" Destruction """
self.destroy()
def destroy(self):
""" Destroy the conftest leftovers on disk """
tempdir, self._tempdir = self._tempdir, None
if tempdir is not None:
_shutil.rmtree(tempdir)
def compile(self, **kwargs):
"""
Compile the conftest
:Parameters:
`kwargs` : ``dict``
Optional keyword parameters for the compiler call
:Return: Was the compilation successful?
:Rtype: ``bool``
"""
kwargs['output_dir'] = self._tempdir
try:
self.compiler.compile([self.src], **kwargs)
except _distutils_errors.CompileError:
return False
return True
def link(self, **kwargs):
r"""
Link the conftest
Before you can link the conftest objects they need to be `compile`\d.
:Parameters:
`kwargs` : ``dict``
Optional keyword parameters for the linker call
:Return: Was the linking successful?
:Rtype: ``bool``
"""
try:
self.compiler.link_executable(self.obj, self.target, **kwargs)
except _distutils_errors.LinkError:
return False
return True
def pipe(self, mode="r"):
r"""
Execute the conftest binary and connect to it using a pipe
Before you can pipe to or from the conftest binary it needs to
be `link`\ed.
:Parameters:
`mode` : ``str``
Pipe mode - r/w
:Return: The open pipe
:Rtype: ``file``
"""
return _os.popen(self.compiler.executable_filename(self.target), mode)

View File

@ -0,0 +1,28 @@
# -*- coding: ascii -*-
#
# Copyright 2010, 2011
# Andr\xe9 Malo or his licensors, as applicable
#
# Licensed 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.
"""
=====================
Package _setup.make
=====================
Make tools, not distributed.
"""
__author__ = u"Andr\xe9 Malo"
__docformat__ = "restructuredtext en"
# pylint: disable = W0611
from _setup.make._make import main, fail, warn, fatal, Target

338
_setup/py2/make/_make.py Normal file
View File

@ -0,0 +1,338 @@
# -*- coding: ascii -*-
#
# Copyright 2007, 2008, 2009, 2010, 2011
# Andr\xe9 Malo or his licensors, as applicable
#
# Licensed 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.
"""
==================
Simple make base
==================
Simple make base.
"""
__author__ = u"Andr\xe9 Malo"
__docformat__ = "restructuredtext en"
import sys as _sys
from _setup import term as _term
class Failure(SystemExit):
""" Failure exception """
def fail(reason):
""" Fail for a reason """
raise Failure(reason)
def warn(message, name=None):
""" Warn """
_term.red("%(NAME)sWarning: %(msg)s",
NAME=name and "%s:" % name or '', msg=message
)
def fatal(reason):
""" Fatal error, immediate stop """
print >> _sys.stderr, reason
_sys.exit(1)
class Target(object):
""" Target base class """
NAME = None
DEPS = None
HIDDEN = False
ERROR = None
def __init__(self, runner):
""" Base __init__ """
self.runner = runner
self.init()
def init(self):
""" Default init hook """
pass
def run(self):
""" Default run hook """
pass
def clean(self, scm=True, dist=False):
""" Default clean hook """
pass
class _Runner(object):
""" Runner """
def __init__(self, *targetscollection):
""" Initialization """
tdict = {}
if not targetscollection:
import __main__
targetscollection = [__main__]
from _setup.make import default_targets
if default_targets not in targetscollection:
targetscollection.append(default_targets)
for targets in targetscollection:
for value in vars(targets).values():
if isinstance(value, type) and issubclass(value, Target) and \
value.NAME is not None:
if value.NAME in tdict:
if issubclass(value, tdict[value.NAME]):
pass # override base target
elif issubclass(tdict[value.NAME], value):
continue # found base later. ignore
else:
warn('Ambiguous target name', value.NAME)
continue
tdict[value.NAME] = value
self._tdict = tdict
self._itdict = {}
def print_help(self):
""" Print make help """
import textwrap as _textwrap
targets = self.targetinfo()
keys = []
for key, info in targets.items():
if not info['hide']:
keys.append(key)
keys.sort()
length = max(map(len, keys))
info = []
for key in keys:
info.append("%s%s" % (
(key + " " * length)[:length + 2],
_textwrap.fill(
targets[key]['desc'].strip(),
subsequent_indent=" " * (length + 2)
),
))
print "Available targets:\n\n" + "\n".join(info)
def targetinfo(self):
""" Extract target information """
result = {}
for name, cls in self._tdict.items():
result[name] = {
'desc': cls.__doc__ or "no description",
'hide': cls.HIDDEN,
'deps': cls.DEPS or (),
}
return result
def _topleveltargets(self):
""" Find all top level targets """
rev = {} # key is a dep of [values]
all_ = self.targetinfo()
for target, info in all_.items():
for dep in info['deps']:
if dep not in all_:
fatal("Unknown target '%s' (dep of %s) -> exit" % (
dep, target
))
rev.setdefault(dep, []).append(target)
return [target for target, info in rev.items() if not info]
def _run(self, target, seen=None):
""" Run a target """
if target.DEPS:
self(*target.DEPS, **{'seen': seen})
if not target.HIDDEN:
_term.yellow(">>> %(name)s", name=target.NAME)
try:
result = target.run()
except KeyboardInterrupt:
result, target.ERROR = False, "^C -> exit"
except Failure, e:
result, target.ERROR = False, "%s: %s" % (target.NAME, e)
except (SystemExit, MemoryError):
raise
except:
import traceback
target.ERROR = "%s errored:\n%s" % (target.NAME, ''.join(
traceback.format_exception(*_sys.exc_info())
))
result = False
else:
if result is None:
result = True
return result
def _clean(self, target, scm, dist, seen=None):
""" Run a target """
if target.DEPS:
self.run_clean(
*target.DEPS, **{'scm': scm, 'dist': dist, 'seen': seen}
)
try:
result = target.clean(scm, dist)
except KeyboardInterrupt:
result, target.ERROR = False, "^C -> exit"
except Failure, e:
result, target.ERROR = False, "%s: %s" % (target.NAME, e)
except (SystemExit, MemoryError):
raise
except:
import traceback
target.ERROR = "%s errored:\n%s" % (target.NAME, ''.join(
traceback.format_exception(*_sys.exc_info())
))
result = False
else:
if result is None:
result = True
return result
def _make_init(self, seen):
""" Make init mapper """
def init(target):
""" Return initialized target """
if target not in seen:
try:
seen[target] = self._tdict[target](self)
except KeyError:
fatal("Unknown target '%s' -> exit" % target)
else:
seen[target] = None
return seen[target]
return init
def run_clean(self, *targets, **kwargs):
""" Run targets """
def pop(name, default=None):
""" Pop """
if name in kwargs:
value = kwargs[name]
del kwargs[name]
if value is None:
return default
return value
else:
return default
seen = pop('seen', {})
scm = pop('scm', True)
dist = pop('dist', False)
if kwargs:
raise TypeError('Unknown keyword parameters')
if not targets:
top_targets = self._topleveltargets()
targets = self.targetinfo()
for item in top_targets:
del targets[item]
targets = targets.keys()
targets.sort()
top_targets.sort()
targets = top_targets + targets
init = self._make_init(seen)
for name in targets:
target = init(name)
if target is not None:
if not self._clean(target, scm=scm, dist=dist, seen=seen):
msg = target.ERROR
if msg is None:
msg = "Clean target %s returned error -> exit" % name
fatal(msg)
def __call__(self, *targets, **kwargs):
""" Run targets """
if 'seen' in kwargs:
seen = kwargs['seen']
del kwargs['seen']
else:
seen = None
if seen is None:
seen = self._itdict
if kwargs:
raise TypeError('Unknown keyword parameters')
init = self._make_init(seen)
for name in targets:
target = init(name)
if target is not None:
if not self._run(target, seen):
msg = target.ERROR
if msg is None:
msg = "Target %s returned error -> exit" % name
fatal(msg)
def main(*args, **kwargs):
"""
main(argv=None, *args, name=None)
Main start point. This function parses the command line and executes the
targets given through `argv`. If there are no targets given, a help output
is generated.
:Parameters:
`argv` : sequence
Command line arguments. If omitted or ``None``, they are picked from
``sys.argv``.
`args` : ``tuple``
The list of modules with targets. If omitted, ``__main__``
is imported and treated as target module. Additionally the mechanism
always adds the `_setup.make` module (this one) to the list in order
to grab some default targets.
`name` : ``str``
Name of the executing module. If omitted or ``None``, ``'__main__'``
is assumed. If the final name is not ``'__main__'``, the function
returns immediately.
"""
try:
name = kwargs['name']
except KeyError:
name = '__main__'
else:
del kwargs['name']
if name is None:
name = '__main__'
try:
argv = kwargs['argv']
except KeyError:
if not args:
args = (None,)
else:
del kwargs['argv']
args = (argv,) + args
if kwargs:
raise TypeError("Unrecognized keyword arguments for main()")
if name == '__main__':
argv, args = args[0], args[1:]
if argv is None:
argv = _sys.argv[1:]
runner = _Runner(*args)
if argv:
runner(*argv)
else:
runner.print_help()

View File

@ -0,0 +1,110 @@
# -*- coding: ascii -*-
#
# Copyright 2007, 2008, 2009, 2010, 2011
# Andr\xe9 Malo or his licensors, as applicable
#
# Licensed 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.
"""
==================
Simple make base
==================
Simple make base.
"""
__author__ = u"Andr\xe9 Malo"
__docformat__ = "restructuredtext en"
import os as _os
import sys as _sys
from _setup import make as _make
from _setup import shell as _shell
class MakefileTarget(_make.Target):
""" Create a make file """
NAME = 'makefile'
def run(self):
def escape(value):
""" Escape for make and shell """
return '"%s"' % value.replace(
'\\', '\\\\').replace(
'"', '\\"').replace(
'$', '\\$$')
def decorate(line, prefix='# ', width=78, char='~', padding=' '):
""" Decorate a line """
line = line.center(width - len(prefix))
return '%s%s%s%s%s%s' % (
prefix,
char * (len(line) - len(line.lstrip()) - len(padding)),
padding,
line.strip(),
padding,
char * (len(line) - len(line.rstrip()) - len(padding)),
)
python = escape(_sys.executable)
script = escape(_sys.argv[0])
targets = self.runner.targetinfo()
names = []
for name, info in targets.items():
if not info['hide']:
names.append(name)
names.sort()
fp = open(_shell.native('Makefile'), 'w')
print >> fp, decorate("Generated Makefile, DO NOT EDIT")
print >> fp, decorate("python %s %s" % (
_os.path.basename(script), self.NAME
))
print >> fp
print >> fp, "_default_:"
print >> fp, "\t@%s %s" % (python, script)
for name in names:
print >> fp, "\n"
print >> fp, "# %s" % \
targets[name]['desc'].splitlines()[0].strip()
print >> fp, "%s:" % name
print >> fp, "\t@%s %s %s" % (python, script, escape(name))
print >> fp
extension = self.extend(names)
if extension is not None:
print >> fp, extension
print >> fp
print >> fp, ".PHONY: _default_ %s\n\n" % ' '.join(names)
fp.close()
def extend(self, names):
pass
class CleanTarget(_make.Target):
""" Clean the mess """
NAME = 'clean'
_scm, _dist = True, False
def run(self):
self.runner.run_clean(scm=self._scm, dist=self._dist)
class DistCleanTarget(CleanTarget):
""" Clean as freshly unpacked dist package """
NAME = 'distclean'
_scm, _dist = False, True
class ExtraCleanTarget(CleanTarget):
""" Clean everything """
NAME = 'extraclean'
_scm, _dist = True, True

324
_setup/py2/make/targets.py Normal file
View File

@ -0,0 +1,324 @@
# -*- coding: ascii -*-
#
# Copyright 2007 - 2013
# Andr\xe9 Malo or his licensors, as applicable
#
# Licensed 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.
"""
==================
Standard targets
==================
Standard targets.
"""
__author__ = u"Andr\xe9 Malo"
__docformat__ = "restructuredtext en"
import os as _os
import sys as _sys
from _setup import dist as _dist
from _setup import make as _make
from _setup import shell as _shell
from _setup import term as _term
class Distribution(_make.Target):
""" Build a distribution """
NAME = "dist"
DEPS = ["MANIFEST"]
_dist, _ebuilds, _changes = None, None, None
def init(self):
raise NotImplementedError()
def run(self):
exts = self.dist_pkg()
digests = self.digest_files(exts)
self.sign_digests(digests)
self.copy_ebuilds()
self.copy_changes()
def dist_pkg(self):
_term.green("Building package...")
_dist.run_setup("sdist", "--formats", "tar,zip",
fakeroot=_shell.frompath('fakeroot')
)
exts = ['.zip']
for name in _shell.files(self._dist, '*.tar', False):
exts.extend(self.compress(name))
_shell.rm(name)
return exts
def compress(self, filename):
""" Compress file """
ext = _os.path.splitext(filename)[1]
exts = []
exts.append('.'.join((ext, self.compress_gzip(filename))))
exts.append('.'.join((ext, self.compress_bzip2(filename))))
exts.append('.'.join((ext, self.compress_xz(filename))))
return exts
def compress_xz(self, filename):
outfilename = filename + '.xz'
self.compress_external(filename, outfilename, 'xz', '-c9')
return 'xz'
def compress_bzip2(self, filename):
outfilename = filename + '.bz2'
try:
import bz2 as _bz2
except ImportError:
self.compress_external(filename, outfilename, 'bzip2', '-c9')
else:
outfile = _bz2.BZ2File(outfilename, 'w')
self.compress_internal(filename, outfile, outfilename)
return 'bz2'
def compress_gzip(self, filename):
outfilename = filename + '.gz'
try:
import gzip as _gzip
except ImportError:
self.compress_external(filename, outfilename, 'gzip', '-c9')
else:
outfile = _gzip.GzipFile(filename, 'wb',
fileobj=open(outfilename, 'wb')
)
self.compress_internal(filename, outfile, outfilename)
return 'gz'
def compress_external(self, infile, outfile, *argv):
argv = list(argv)
argv[0] = _shell.frompath(argv[0])
if argv[0] is not None:
return not _shell.spawn(*argv, **{
'filepipe': True, 'stdin': infile, 'stdout': outfile,
})
return None
def compress_internal(self, filename, outfile, outfilename):
infile = open(filename, 'rb')
try:
try:
while 1:
chunk = infile.read(8192)
if not chunk:
break
outfile.write(chunk)
outfile.close()
except:
e = _sys.exc_info()
try:
_shell.rm(outfilename)
finally:
try:
raise e[0], e[1], e[2]
finally:
del e
finally:
infile.close()
def digest_files(self, exts):
""" digest files """
digests = {}
digestnames = {}
for ext in exts:
for name in _shell.files(self._dist, '*' + ext, False):
basename = _os.path.basename(name)
if basename not in digests:
digests[basename] = []
digests[basename].extend(self.digest(name))
digestname = basename[:-len(ext)]
if digestname not in digestnames:
digestnames[digestname] = []
digestnames[digestname].append(basename)
result = []
for name, basenames in digestnames.items():
result.append(_os.path.join(self._dist, name + '.digests'))
fp = open(result[-1], 'wb')
try:
fp.write(
'\n# The file may contain MD5, SHA1 and SHA256 digests\n'
)
fp.write('# Check archive integrity with, e.g. md5sum -c\n')
fp.write('# Check digest file integrity with PGP\n\n')
basenames.sort()
for basename in basenames:
for digest in digests[basename]:
fp.write("%s *%s\n" % (digest, basename))
finally:
fp.close()
return result
def digest(self, filename):
result = []
for method in (self.md5, self.sha1, self.sha256):
digest = method(filename)
if digest is not None:
result.append(digest)
return result
def do_digest(self, hashfunc, name, filename):
filename = _shell.native(filename)
_term.green("%(digest)s-digesting %(name)s...",
digest=name, name=_os.path.basename(filename))
fp = open(filename, 'rb')
sig = hashfunc()
block = fp.read(8192)
while block:
sig.update(block)
block = fp.read(8192)
fp.close()
return sig.hexdigest()
param = {'sig': sig.hexdigest(), 'file': _os.path.basename(filename)}
fp = open("%s.%s" % (filename, name), "w")
fp.write("%(sig)s *%(file)s\n" % param)
fp.close()
return True
def md5(self, filename):
try:
from hashlib import md5
except ImportError:
try:
from md5 import new as md5
except ImportError:
_make.warn("md5 not found -> skip md5 digests", self.NAME)
return None
return self.do_digest(md5, "md5", filename)
def sha1(self, filename):
try:
from hashlib import sha1
except ImportError:
try:
from sha import new as sha1
except ImportError:
_make.warn("sha1 not found -> skip sha1 digests", self.NAME)
return None
return self.do_digest(sha1, "sha1", filename)
def sha256(self, filename):
try:
from hashlib import sha256
except ImportError:
try:
from Crypto.Hash.SHA256 import new as sha256
except ImportError:
_make.warn(
"sha256 not found -> skip sha256 digests", self.NAME
)
return None
return self.do_digest(sha256, "sha256", filename)
def copy_ebuilds(self):
if self._ebuilds is not None:
for src in _shell.files(self._ebuilds, '*.ebuild'):
_shell.cp(src, self._dist)
def copy_changes(self):
if self._changes is not None:
_shell.cp(self._changes, self._dist)
def sign_digests(self, digests):
for digest in digests:
self.sign(digest, detach=False)
def sign(self, filename, detach=True):
filename = _shell.native(filename)
try:
from pyme import core, errors
from pyme.constants.sig import mode
except ImportError:
return self.sign_external(filename, detach=detach)
_term.green("signing %(name)s...", name=_os.path.basename(filename))
sigmode = [mode.CLEAR, mode.DETACH][bool(detach)]
fp = core.Data(file=filename)
sig = core.Data()
try:
c = core.Context()
except errors.GPGMEError:
return self.sign_external(filename, detach=detach)
c.set_armor(1)
try:
c.op_sign(fp, sig, sigmode)
except errors.GPGMEError, e:
_make.fail(str(e))
sig.seek(0, 0)
if detach:
open("%s.asc" % filename, "w").write(sig.read())
else:
open(filename, "w").write(sig.read())
return True
def sign_external(self, filename, detach=True):
""" Sign calling gpg """
gpg = _shell.frompath('gpg')
if gpg is None:
_make.warn('GPG not found -> cannot sign')
return False
if detach:
_shell.spawn(gpg,
'--armor',
'--output', filename + '.asc',
'--detach-sign',
'--',
filename,
)
else:
_shell.spawn(gpg,
'--output', filename + '.signed',
'--clearsign',
'--',
filename,
)
_os.rename(filename + '.signed', filename)
return True
def clean(self, scm, dist):
_term.green("Removing dist files...")
_shell.rm_rf(self._dist)
class Manifest(_make.Target):
""" Create manifest """
NAME = "MANIFEST"
HIDDEN = True
DEPS = ["doc"]
def run(self):
_term.green("Creating %(name)s...", name=self.NAME)
dest = _shell.native(self.NAME)
dest = open(dest, 'w')
for name in self.manifest_names():
dest.write("%s\n" % name)
dest.close()
def manifest_names(self):
import setup
for item in setup.manifest():
yield item
def clean(self, scm, dist):
""" Clean manifest """
if scm:
_term.green("Removing MANIFEST")
_shell.rm(self.NAME)

419
_setup/py2/setup.py Normal file
View File

@ -0,0 +1,419 @@
# -*- coding: ascii -*-
#
# Copyright 2007 - 2013
# Andr\xe9 Malo or his licensors, as applicable
#
# Licensed 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.
"""
===================
Main setup runner
===================
This module provides a wrapper around the distutils core setup.
"""
__author__ = u"Andr\xe9 Malo"
__docformat__ = "restructuredtext en"
import ConfigParser as _config_parser
from distutils import core as _core
import os as _os
import posixpath as _posixpath
import sys as _sys
from _setup import commands as _commands
from _setup import data as _data
from _setup import ext as _ext
from _setup import util as _util
from _setup import shell as _shell
def check_python_version(impl, version_min, version_max):
""" Check python version """
if impl == 'python':
version_info = _sys.version_info
elif impl == 'pypy':
version_info = getattr(_sys, 'pypy_version_info', None)
if not version_info:
return
elif impl == 'jython':
if not 'java' in _sys.platform.lower():
return
version_info = _sys.version_info
else:
raise AssertionError("impl not in ('python', 'pypy', 'jython')")
pyversion = map(int, version_info[:3])
if version_min:
min_required = \
map(int, '.'.join((version_min, '0.0.0')).split('.')[:3])
if pyversion < min_required:
raise EnvironmentError("Need at least %s %s (vs. %s)" % (
impl, version_min, '.'.join(map(str, pyversion))
))
if version_max:
max_required = map(int, version_max.split('.'))
max_required[-1] += 1
if pyversion >= max_required:
raise EnvironmentError("Need at max %s %s (vs. %s)" % (
impl,
version_max,
'.'.join(map(str, pyversion))
))
def find_description(docs):
"""
Determine the package description from DESCRIPTION
:Parameters:
`docs` : ``dict``
Docs config section
:Return: Tuple of summary, description and license
(``('summary', 'description', 'license')``)
(all may be ``None``)
:Rtype: ``tuple``
"""
summary = None
filename = docs.get('meta.summary', 'SUMMARY').strip()
if filename and _os.path.isfile(filename):
fp = open(filename)
try:
try:
summary = fp.read().strip().splitlines()[0].rstrip()
except IndexError:
summary = ''
finally:
fp.close()
description = None
filename = docs.get('meta.description', 'DESCRIPTION').strip()
if filename and _os.path.isfile(filename):
fp = open(filename)
try:
description = fp.read().rstrip()
finally:
fp.close()
if summary is None and description:
from docutils import core
summary = core.publish_parts(
source=description,
source_path=filename,
writer_name='html',
)['title'].encode('utf-8')
return summary, description
def find_classifiers(docs):
"""
Determine classifiers from CLASSIFIERS
:return: List of classifiers (``['classifier', ...]``)
:rtype: ``list``
"""
filename = docs.get('meta.classifiers', 'CLASSIFIERS').strip()
if filename and _os.path.isfile(filename):
fp = open(filename)
try:
content = fp.read()
finally:
fp.close()
content = [item.strip() for item in content.splitlines()]
return [item for item in content if item and not item.startswith('#')]
return []
def find_provides(docs):
"""
Determine provides from PROVIDES
:return: List of provides (``['provides', ...]``)
:rtype: ``list``
"""
filename = docs.get('meta.provides', 'PROVIDES').strip()
if filename and _os.path.isfile(filename):
fp = open(filename)
try:
content = fp.read()
finally:
fp.close()
content = [item.strip() for item in content.splitlines()]
return [item for item in content if item and not item.startswith('#')]
return []
def find_license(docs):
"""
Determine license from LICENSE
:return: License text
:rtype: ``str``
"""
filename = docs.get('meta.license', 'LICENSE').strip()
if filename and _os.path.isfile(filename):
fp = open(filename)
try:
return fp.read().rstrip()
finally:
fp.close()
return None
def find_packages(manifest):
""" Determine packages and subpackages """
packages = {}
collect = manifest.get('packages.collect', '').split()
lib = manifest.get('packages.lib', '.')
try:
sep = _os.path.sep
except AttributeError:
sep = _os.path.join('1', '2')[1:-1]
for root in collect:
for dirpath, _, filenames in _shell.walk(_os.path.join(lib, root)):
if dirpath.find('.svn') >= 0:
continue
if '__init__.py' in filenames:
packages[
_os.path.normpath(dirpath).replace(sep, '.')
] = None
packages = packages.keys()
packages.sort()
return packages
def find_data(name, docs):
""" Determine data files """
result = []
if docs.get('extra', '').strip():
result.append(_data.Documentation(docs['extra'].split(),
prefix='share/doc/%s' % name,
))
if docs.get('examples.dir', '').strip():
tpl = ['recursive-include %s *' % docs['examples.dir']]
if docs.get('examples.ignore', '').strip():
tpl.extend(["global-exclude %s" % item
for item in docs['examples.ignore'].split()
])
strip = int(docs.get('examples.strip', '') or 0)
result.append(_data.Documentation.from_templates(*tpl, **{
'strip': strip,
'prefix': 'share/doc/%s' % name,
'preserve': 1,
}))
if docs.get('userdoc.dir', '').strip():
tpl = ['recursive-include %s *' % docs['userdoc.dir']]
if docs.get('userdoc.ignore', '').strip():
tpl.extend(["global-exclude %s" % item
for item in docs['userdoc.ignore'].split()
])
strip = int(docs.get('userdoc.strip', '') or 0)
result.append(_data.Documentation.from_templates(*tpl, **{
'strip': strip,
'prefix': 'share/doc/%s' % name,
'preserve': 1,
}))
if docs.get('apidoc.dir', '').strip():
tpl = ['recursive-include %s *' % docs['apidoc.dir']]
if docs.get('apidoc.ignore', '').strip():
tpl.extend(["global-exclude %s" % item
for item in docs['apidoc.ignore'].split()
])
strip = int(docs.get('apidoc.strip', '') or 0)
result.append(_data.Documentation.from_templates(*tpl, **{
'strip': strip,
'prefix': 'share/doc/%s' % name,
'preserve': 1,
}))
if docs.get('man', '').strip():
result.extend(_data.Manpages.dispatch(docs['man'].split()))
return result
def make_manifest(manifest, config, docs, kwargs):
""" Create file list to pack up """
# pylint: disable = R0912
kwargs = kwargs.copy()
kwargs['script_args'] = ['install']
kwargs['packages'] = list(kwargs.get('packages') or ()) + [
'_setup', '_setup.py2', '_setup.py3',
] + list(manifest.get('packages.extra', '').split() or ())
_core._setup_stop_after = "commandline"
try:
dist = _core.setup(**kwargs)
finally:
_core._setup_stop_after = None
result = ['MANIFEST', 'PKG-INFO', 'setup.py'] + list(config)
# TODO: work with default values:
for key in ('classifiers', 'description', 'summary', 'provides',
'license'):
filename = docs.get('meta.' + key, '').strip()
if filename and _os.path.isfile(filename):
result.append(filename)
cmd = dist.get_command_obj("build_py")
cmd.ensure_finalized()
#from pprint import pprint; pprint(("build_py", cmd.get_source_files()))
for item in cmd.get_source_files():
result.append(_posixpath.sep.join(
_os.path.normpath(item).split(_os.path.sep)
))
cmd = dist.get_command_obj("build_ext")
cmd.ensure_finalized()
#from pprint import pprint; pprint(("build_ext", cmd.get_source_files()))
for item in cmd.get_source_files():
result.append(_posixpath.sep.join(
_os.path.normpath(item).split(_os.path.sep)
))
for ext in cmd.extensions:
if ext.depends:
result.extend([_posixpath.sep.join(
_os.path.normpath(item).split(_os.path.sep)
) for item in ext.depends])
cmd = dist.get_command_obj("build_clib")
cmd.ensure_finalized()
if cmd.libraries:
#import pprint; pprint.pprint(("build_clib", cmd.get_source_files()))
for item in cmd.get_source_files():
result.append(_posixpath.sep.join(
_os.path.normpath(item).split(_os.path.sep)
))
for lib in cmd.libraries:
if lib[1].get('depends'):
result.extend([_posixpath.sep.join(
_os.path.normpath(item).split(_os.path.sep)
) for item in lib[1]['depends']])
cmd = dist.get_command_obj("build_scripts")
cmd.ensure_finalized()
#import pprint; pprint.pprint(("build_scripts", cmd.get_source_files()))
if cmd.get_source_files():
for item in cmd.get_source_files():
result.append(_posixpath.sep.join(
_os.path.normpath(item).split(_os.path.sep)
))
cmd = dist.get_command_obj("install_data")
cmd.ensure_finalized()
#from pprint import pprint; pprint(("install_data", cmd.get_inputs()))
try:
strings = basestring
except NameError:
strings = (str, unicode)
for item in cmd.get_inputs():
if isinstance(item, strings):
result.append(item)
else:
result.extend(item[1])
for item in manifest.get('dist', '').split():
result.append(item)
if _os.path.isdir(item):
for filename in _shell.files(item):
result.append(filename)
result = dict([(item, None) for item in result]).keys()
result.sort()
return result
def run(config=('package.cfg',), ext=None, script_args=None, manifest_only=0):
""" Main runner """
if ext is None:
ext = []
cfg = _util.SafeConfigParser()
cfg.read(config)
pkg = dict(cfg.items('package'))
python_min = pkg.get('python.min') or None
python_max = pkg.get('python.max') or None
check_python_version('python', python_min, python_max)
pypy_min = pkg.get('pypy.min') or None
pypy_max = pkg.get('pypy.max') or None
check_python_version('pypy', pypy_min, pypy_max)
jython_min = pkg.get('jython.min') or None
jython_max = pkg.get('jython.max') or None
check_python_version('jython', jython_min, jython_max)
manifest = dict(cfg.items('manifest'))
try:
docs = dict(cfg.items('docs'))
except _config_parser.NoSectionError:
docs = {}
summary, description = find_description(docs)
scripts = manifest.get('scripts', '').strip() or None
if scripts:
scripts = scripts.split()
modules = manifest.get('modules', '').strip() or None
if modules:
modules = modules.split()
keywords = docs.get('meta.keywords', '').strip() or None
if keywords:
keywords = keywords.split()
revision = pkg.get('version.revision', '').strip()
if revision:
revision = "-r%s" % (revision,)
kwargs = {
'name': pkg['name'],
'version': "%s%s" % (
pkg['version.number'],
["", "-dev%s" % (revision,)][_util.humanbool(
'version.dev', pkg.get('version.dev', 'false')
)],
),
'provides': find_provides(docs),
'description': summary,
'long_description': description,
'classifiers': find_classifiers(docs),
'keywords': keywords,
'author': pkg['author.name'],
'author_email': pkg['author.email'],
'maintainer': pkg.get('maintainer.name'),
'maintainer_email': pkg.get('maintainer.email'),
'url': pkg.get('url.homepage'),
'download_url': pkg.get('url.download'),
'license': find_license(docs),
'package_dir': {'': manifest.get('packages.lib', '.')},
'packages': find_packages(manifest),
'py_modules': modules,
'ext_modules': ext,
'scripts': scripts,
'script_args': script_args,
'data_files': find_data(pkg['name'], docs),
'cmdclass': {
'build' : _commands.Build,
'build_ext' : _commands.BuildExt,
'install' : _commands.Install,
'install_data': _commands.InstallData,
'install_lib' : _commands.InstallLib,
}
}
for key in ('provides',):
if key not in _core.setup_keywords:
del kwargs[key]
if manifest_only:
return make_manifest(manifest, config, docs, kwargs)
# monkey-patch crappy manifest writer away.
from distutils.command import sdist
sdist.sdist.get_file_list = sdist.sdist.read_manifest
return _core.setup(**kwargs)

478
_setup/py2/shell.py Normal file
View File

@ -0,0 +1,478 @@
# -*- coding: ascii -*-
#
# Copyright 2007 - 2013
# Andr\xe9 Malo or his licensors, as applicable
#
# Licensed 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.
"""
=================
Shell utilities
=================
Shell utilities.
"""
from __future__ import generators
__author__ = u"Andr\xe9 Malo"
__docformat__ = "restructuredtext en"
import errno as _errno
import fnmatch as _fnmatch
import os as _os
import shutil as _shutil
import sys as _sys
import tempfile as _tempfile
cwd = _os.path.dirname(_os.path.abspath(_sys.argv[0]))
class ExitError(RuntimeError):
""" Exit error """
def __init__(self, code):
RuntimeError.__init__(self, code)
self.code = code
self.signal = None
class SignalError(ExitError):
""" Signal error """
def __init__(self, code, signal):
ExitError.__init__(self, code)
import signal as _signal
self.signal = signal
for key, val in vars(_signal).iteritems():
if key.startswith('SIG') and not key.startswith('SIG_'):
if val == signal:
self.signalstr = key[3:]
break
else:
self.signalstr = '%04d' % signal
def native(path):
""" Convert slash path to native """
path = _os.path.sep.join(path.split('/'))
return _os.path.normpath(_os.path.join(cwd, path))
def cp(src, dest):
""" Copy src to dest """
_shutil.copy2(native(src), native(dest))
def cp_r(src, dest):
""" Copy -r src to dest """
_shutil.copytree(native(src), native(dest))
def rm(dest):
""" Remove a file """
try:
_os.unlink(native(dest))
except OSError, e:
if _errno.ENOENT != e.errno:
raise
def rm_rf(dest):
""" Remove a tree """
dest = native(dest)
if _os.path.exists(dest):
for path in files(dest, '*'):
_os.chmod(native(path), 0644)
_shutil.rmtree(dest)
try:
mkstemp = _tempfile.mkstemp
except AttributeError:
# helpers stolen from 2.4 tempfile module
try:
import fcntl as _fcntl
except ImportError:
def _set_cloexec(fd):
""" Set close-on-exec (not implemented, but not an error) """
# pylint: disable = W0613
pass
else:
def _set_cloexec(fd):
""" Set close-on-exec """
try:
flags = _fcntl.fcntl(fd, _fcntl.F_GETFD, 0)
except IOError:
pass
else:
# flags read successfully, modify
flags |= _fcntl.FD_CLOEXEC
_fcntl.fcntl(fd, _fcntl.F_SETFD, flags)
_text_openflags = _os.O_RDWR | _os.O_CREAT | _os.O_EXCL
_text_openflags |= getattr(_os, 'O_NOINHERIT', 0)
_text_openflags |= getattr(_os, 'O_NOFOLLOW', 0)
_bin_openflags = _text_openflags
_bin_openflags |= getattr(_os, 'O_BINARY', 0)
def mkstemp(suffix="", prefix=_tempfile.gettempprefix(), dir=None,
text=False):
""" Create secure temp file """
# pylint: disable = W0622
if dir is None:
dir = _tempfile.gettempdir()
if text:
flags = _text_openflags
else:
flags = _bin_openflags
count = 100
while count > 0:
j = _tempfile._counter.get_next() # pylint: disable = E1101, W0212
fname = _os.path.join(dir, prefix + str(j) + suffix)
try:
fd = _os.open(fname, flags, 0600)
except OSError, e:
if e.errno == _errno.EEXIST:
count -= 1
continue
raise
_set_cloexec(fd)
return fd, _os.path.abspath(fname)
raise IOError, (_errno.EEXIST, "No usable temporary file name found")
def _pipespawn(argv, env):
""" Pipe spawn """
# pylint: disable = R0912
import pickle as _pickle
fd, name = mkstemp('.py')
try:
_os.write(fd, (r"""
import os
import pickle
try:
import subprocess
except ImportError:
subprocess = None
import sys
argv = pickle.loads(%(argv)s)
env = pickle.loads(%(env)s)
if 'X_JYTHON_WA_PATH' in env:
env['PATH'] = env['X_JYTHON_WA_PATH']
if subprocess is None:
pid = os.spawnve(os.P_NOWAIT, argv[0], argv, env)
result = os.waitpid(pid, 0)[1]
else:
p = subprocess.Popen(argv, env=env)
result = p.wait()
if result < 0:
print "\n%%d 1" %% (-result)
sys.exit(2)
if result == 0:
sys.exit(0)
signalled = getattr(os, 'WIFSIGNALED', None)
if signalled is not None:
if signalled(result):
print "\n%%d %%d" %% (os.WTERMSIG(result), result & 7)
sys.exit(2)
print "\n%%d" %% (result & 7,)
sys.exit(3)
""".strip() + "\n") % {
'argv': repr(_pickle.dumps(argv)),
'env': repr(_pickle.dumps(env)),
})
fd, _ = None, _os.close(fd)
if _sys.platform == 'win32':
argv = []
for arg in [_sys.executable, name]:
if ' ' in arg or arg.startswith('"'):
arg = '"%s"' % arg.replace('"', '\\"')
argv.append(arg)
argv = ' '.join(argv)
shell = True
close_fds = False
else:
argv = [_sys.executable, name]
shell = False
close_fds = True
res = 0
try:
import subprocess
except ImportError:
import popen2 as _popen2
proc = _popen2.Popen3(argv, False)
try:
proc.tochild.close()
result = proc.fromchild.read()
finally:
res = proc.wait()
else:
if 'X_JYTHON_WA_PATH' in env:
env['PATH'] = env['X_JYTHON_WA_PATH']
proc = subprocess.Popen(argv,
shell=shell,
stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
close_fds=close_fds,
env=env,
)
try:
proc.stdin.close()
result = proc.stdout.read()
finally:
res = proc.wait()
if res != 0:
if res == 2:
signal, code = map(int, result.splitlines()[-1].split())
raise SignalError(code, signal)
elif res == 3:
code = int(result.splitlines()[-1].strip())
raise ExitError(code)
raise ExitError(res)
return result
finally:
try:
if fd is not None:
_os.close(fd)
finally:
_os.unlink(name)
def _filepipespawn(infile, outfile, argv, env):
""" File Pipe spawn """
try:
import subprocess
except ImportError:
subprocess = None
import pickle as _pickle
fd, name = mkstemp('.py')
try:
_os.write(fd, ("""
import os
import pickle
import sys
infile = pickle.loads(%(infile)s)
outfile = pickle.loads(%(outfile)s)
argv = pickle.loads(%(argv)s)
env = pickle.loads(%(env)s)
if infile is not None:
infile = open(infile, 'rb')
os.dup2(infile.fileno(), 0)
infile.close()
if outfile is not None:
outfile = open(outfile, 'wb')
os.dup2(outfile.fileno(), 1)
outfile.close()
pid = os.spawnve(os.P_NOWAIT, argv[0], argv, env)
result = os.waitpid(pid, 0)[1]
sys.exit(result & 7)
""".strip() + "\n") % {
'infile': repr(_pickle.dumps(_os.path.abspath(infile))),
'outfile': repr(_pickle.dumps(_os.path.abspath(outfile))),
'argv': repr(_pickle.dumps(argv)),
'env': repr(_pickle.dumps(env)),
})
fd, _ = None, _os.close(fd)
if _sys.platform == 'win32':
argv = []
for arg in [_sys.executable, name]:
if ' ' in arg or arg.startswith('"'):
arg = '"%s"' % arg.replace('"', '\\"')
argv.append(arg)
argv = ' '.join(argv)
close_fds = False
shell = True
else:
argv = [_sys.executable, name]
close_fds = True
shell = False
if subprocess is None:
pid = _os.spawnve(_os.P_NOWAIT, argv[0], argv, env)
return _os.waitpid(pid, 0)[1]
else:
p = subprocess.Popen(
argv, env=env, shell=shell, close_fds=close_fds
)
return p.wait()
finally:
try:
if fd is not None:
_os.close(fd)
finally:
_os.unlink(name)
def spawn(*argv, **kwargs):
""" Spawn a process """
try:
import subprocess
except ImportError:
subprocess = None
if _sys.platform == 'win32':
newargv = []
for arg in argv:
if not arg or ' ' in arg or arg.startswith('"'):
arg = '"%s"' % arg.replace('"', '\\"')
newargv.append(arg)
argv = newargv
close_fds = False
shell = True
else:
close_fds = True
shell = False
env = kwargs.get('env')
if env is None:
env = dict(_os.environ)
if 'X_JYTHON_WA_PATH' in env:
env['PATH'] = env['X_JYTHON_WA_PATH']
echo = kwargs.get('echo')
if echo:
print ' '.join(argv)
filepipe = kwargs.get('filepipe')
if filepipe:
return _filepipespawn(
kwargs.get('stdin'), kwargs.get('stdout'), argv, env
)
pipe = kwargs.get('stdout')
if pipe:
return _pipespawn(argv, env)
if subprocess is None:
pid = _os.spawnve(_os.P_NOWAIT, argv[0], argv, env)
return _os.waitpid(pid, 0)[1]
else:
p = subprocess.Popen(argv, env=env, shell=shell, close_fds=close_fds)
return p.wait()
try:
walk = _os.walk
except AttributeError:
# copy from python 2.4 sources (modulo docs and comments)
def walk(top, topdown=True, onerror=None):
""" directory tree walker """
# pylint: disable = C0103
join, isdir, islink = _os.path.join, _os.path.isdir, _os.path.islink
listdir, error = _os.listdir, _os.error
try:
names = listdir(top)
except error, err:
if onerror is not None:
onerror(err)
return
dirs, nondirs = [], []
for name in names:
if isdir(join(top, name)):
dirs.append(name)
else:
nondirs.append(name)
if topdown:
yield top, dirs, nondirs
for name in dirs:
path = join(top, name)
if not islink(path):
for x in walk(path, topdown, onerror):
yield x
if not topdown:
yield top, dirs, nondirs
def files(base, wildcard='[!.]*', recursive=1, prune=('.svn', 'CVS')):
""" Determine a filelist """
for dirpath, dirnames, filenames in walk(native(base)):
for item in prune:
if item in dirnames:
dirnames.remove(item)
filenames.sort()
for name in _fnmatch.filter(filenames, wildcard):
dest = _os.path.join(dirpath, name)
if dest.startswith(cwd):
dest = dest.replace(cwd, '', 1)
aslist = []
head, tail = _os.path.split(dest)
while tail:
aslist.append(tail)
head, tail = _os.path.split(head)
aslist.reverse()
dest = '/'.join(aslist)
yield dest
if not recursive:
break
dirnames.sort()
def dirs(base, wildcard='[!.]*', recursive=1, prune=('.svn', 'CVS')):
""" Determine a filelist """
for dirpath, dirnames, filenames in walk(native(base)):
for item in prune:
if item in dirnames:
dirnames.remove(item)
dirnames.sort()
for name in _fnmatch.filter(dirnames, wildcard):
dest = _os.path.join(dirpath, name)
if dest.startswith(cwd):
dest = dest.replace(cwd, '', 1)
aslist = []
head, tail = _os.path.split(dest)
while tail:
aslist.append(tail)
head, tail = _os.path.split(head)
aslist.reverse()
dest = '/'.join(aslist)
yield dest
if not recursive:
break
def frompath(executable):
""" Find executable in PATH """
# Based on distutils.spawn.find_executable.
path = _os.environ.get('PATH', '')
paths = [
_os.path.expanduser(item)
for item in path.split(_os.pathsep)
]
ext = _os.path.splitext(executable)[1]
exts = ['']
if _sys.platform == 'win32' or _os.name == 'os2':
eext = ['.exe', '.bat', '.py']
if ext not in eext:
exts.extend(eext)
for ext in exts:
if not _os.path.isfile(executable + ext):
for path in paths:
fname = _os.path.join(path, executable + ext)
if _os.path.isfile(fname):
# the file exists, we have a shot at spawn working
return fname
else:
return executable + ext
return None

View File

@ -0,0 +1,28 @@
# -*- coding: ascii -*-
#
# Copyright 2010, 2011
# Andr\xe9 Malo or his licensors, as applicable
#
# Licensed 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.
"""
=====================
Package _setup.term
=====================
Terminal tools, not distributed.
"""
__author__ = u"Andr\xe9 Malo"
__docformat__ = "restructuredtext en"
# pylint: disable = W0611
from _setup.term._term import terminfo, write, green, red, yellow, announce

115
_setup/py2/term/_term.py Normal file
View File

@ -0,0 +1,115 @@
# -*- coding: ascii -*-
#
# Copyright 2007, 2008, 2009, 2010, 2011
# Andr\xe9 Malo or his licensors, as applicable
#
# Licensed 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.
"""
=================
Terminal writer
=================
"""
__author__ = u"Andr\xe9 Malo"
__docformat__ = "restructuredtext en"
import sys as _sys
class _INFO(dict):
""" Terminal info dict """
def __init__(self):
""" Initialization """
dict.__init__(self, {
'NORMAL': '',
'BOLD': '',
'ERASE': '\n',
'RED': '',
'YELLOW': '',
'GREEN': '',
})
try:
import curses as _curses
except ImportError:
# fixup if a submodule of curses failed.
if 'curses' in _sys.modules:
del _sys.modules['curses']
else:
try:
_curses.setupterm()
except (TypeError, _curses.error):
pass
else:
def make_color(color):
""" Make color control string """
seq = _curses.tigetstr('setaf')
if seq is not None:
# XXX may fail - need better logic
seq = seq.replace("%p1", "") % color
return seq
self['NORMAL'] = _curses.tigetstr('sgr0')
self['BOLD'] = _curses.tigetstr('bold')
erase = _curses.tigetstr('el1')
if erase is not None:
self['ERASE'] = erase + _curses.tigetstr('cr')
self['RED'] = make_color(_curses.COLOR_RED)
self['YELLOW'] = make_color(_curses.COLOR_YELLOW)
self['GREEN'] = make_color(_curses.COLOR_GREEN)
def __getitem__(self, key):
""" Deliver always """
dict.get(self, key) or ""
def terminfo():
""" Get info singleton """
# pylint: disable = E1101, W0612
if terminfo.info is None:
terminfo.info = _INFO()
return terminfo.info
terminfo.info = None
def write(fmt, **kwargs):
""" Write stuff on the terminal """
parm = dict(terminfo())
parm.update(kwargs)
_sys.stdout.write(fmt % parm)
_sys.stdout.flush()
def green(bmt, **kwargs):
""" Write something in green on screen """
announce("%%(GREEN)s%s%%(NORMAL)s" % bmt, **kwargs)
def red(bmt, **kwargs):
""" Write something in red on the screen """
announce("%%(BOLD)s%%(RED)s%s%%(NORMAL)s" % bmt, **kwargs)
def yellow(fmt, **kwargs):
""" Write something in yellow on the screen """
announce("%%(BOLD)s%%(YELLOW)s%s%%(NORMAL)s" % fmt, **kwargs)
def announce(fmt, **kwargs):
""" Announce something """
write(fmt, **kwargs)
_sys.stdout.write("\n")
_sys.stdout.flush()

73
_setup/py2/util.py Normal file
View File

@ -0,0 +1,73 @@
# -*- coding: ascii -*-
#
# Copyright 2007, 2008, 2009, 2010, 2011
# Andr\xe9 Malo or his licensors, as applicable
#
# Licensed 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.
"""
=================
Setup utilities
=================
Setup utilities.
"""
__author__ = u"Andr\xe9 Malo"
__docformat__ = "restructuredtext en"
try:
from distutils import log
except ImportError:
class log(object):
def info(self, value):
print value
def debug(self, value):
pass
log = log()
from distutils import util as _util
try:
from ConfigParser import SafeConfigParser
except ImportError:
import ConfigParser as _config_parser
class SafeConfigParser(_config_parser.ConfigParser):
""" Safe config parser """
def _interpolate(self, section, option, rawval, vars):
return rawval
def items(self, section):
return [(key, self.get(section, key))
for key in self.options(section)
]
def humanbool(name, value):
"""
Determine human boolean value
:Parameters:
`name` : ``str``
The config key (used for error message)
`value` : ``str``
The config value
:Return: The boolean value
:Rtype: ``bool``
:Exceptions:
- `ValueError` : The value could not be recognized
"""
try:
return _util.strtobool(str(value).strip().lower() or 'no')
except ValueError:
raise ValueError("Unrecognized config value: %s = %s" % (name, value))

27
_setup/py3/__init__.py Normal file
View File

@ -0,0 +1,27 @@
# -*- coding: ascii -*-
#
# Copyright 2007, 2008, 2009, 2010, 2011
# Andr\xe9 Malo or his licensors, as applicable
#
# Licensed 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.
"""
================
Package _setup
================
This package provides tools for main package setup.
"""
__author__ = "Andr\xe9 Malo"
__docformat__ = "restructuredtext en"
from _setup.setup import run # pylint: disable = W0611

266
_setup/py3/commands.py Normal file
View File

@ -0,0 +1,266 @@
# -*- coding: ascii -*-
#
# Copyright 2007, 2008, 2009, 2010, 2011
# Andr\xe9 Malo or his licensors, as applicable
#
# Licensed 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.
"""
===================
Command extenders
===================
Command extenders.
"""
__author__ = "Andr\xe9 Malo"
__docformat__ = "restructuredtext en"
__test__ = False
from distutils import fancy_getopt as _fancy_getopt
from distutils import log
from distutils.command import build as _build
from distutils.command import build_ext as _build_ext
from distutils.command import install as _install
from distutils.command import install_data as _install_data
from distutils.command import install_lib as _install_lib
import os as _os
_option_defaults = {}
_option_inherits = {}
_option_finalizers = {}
_command_mapping = {
'install': 'Install',
'install_data': 'InstallData',
'install_lib': 'InstallLib',
'build': 'Build',
'build_ext': 'BuildExt',
}
def add_option(command, long_name, help_text, short_name=None, default=None,
inherit=None):
""" Add an option """
try:
command_class = globals()[_command_mapping[command]]
except KeyError:
raise ValueError("Unknown command %r" % (command,))
for opt in command_class.user_options:
if opt[0] == long_name:
break
else:
opt = (long_name, short_name, help_text)
command_class.user_options.append(opt)
if not long_name.endswith('='):
command_class.boolean_options.append(long_name)
attr_name = _fancy_getopt.translate_longopt(long_name)
else:
attr_name = _fancy_getopt.translate_longopt(long_name[:-1])
if command not in _option_defaults:
_option_defaults[command] = []
if inherit is not None:
if isinstance(inherit, str):
inherit = [inherit]
for i_inherit in inherit:
add_option(
i_inherit, long_name, help_text, short_name, default
)
default = None
if command not in _option_inherits:
_option_inherits[command] = []
for i_inherit in inherit:
for i_command, opt_name in _option_inherits[command]:
if i_command == i_inherit and opt_name == attr_name:
break
else:
_option_inherits[command].append((i_inherit, attr_name))
_option_defaults[command].append((attr_name, default))
def add_finalizer(command, key, func):
""" Add finalizer """
if command not in _option_finalizers:
_option_finalizers[command] = {}
if key not in _option_finalizers[command]:
_option_finalizers[command][key] = func
class Install(_install.install):
""" Extended installer to reflect the additional data options """
user_options = _install.install.user_options + [
('single-version-externally-managed', None,
"Compat option. Does not a thing."),
]
boolean_options = _install.install.boolean_options + [
'single-version-externally-managed'
]
def initialize_options(self):
""" Prepare for new options """
_install.install.initialize_options(self)
self.single_version_externally_managed = None
if 'install' in _option_defaults:
for opt_name, default in _option_defaults['install']:
setattr(self, opt_name, default)
def finalize_options(self):
""" Finalize options """
_install.install.finalize_options(self)
if 'install' in _option_inherits:
for parent, opt_name in _option_inherits['install']:
self.set_undefined_options(parent, (opt_name, opt_name))
if 'install' in _option_finalizers:
for func in list(_option_finalizers['install'].values()):
func(self)
class InstallData(_install_data.install_data):
""" Extended data installer """
user_options = _install_data.install_data.user_options + []
boolean_options = _install_data.install_data.boolean_options + []
def initialize_options(self):
""" Prepare for new options """
_install_data.install_data.initialize_options(self)
if 'install_data' in _option_defaults:
for opt_name, default in _option_defaults['install_data']:
setattr(self, opt_name, default)
def finalize_options(self):
""" Finalize options """
_install_data.install_data.finalize_options(self)
if 'install_data' in _option_inherits:
for parent, opt_name in _option_inherits['install_data']:
self.set_undefined_options(parent, (opt_name, opt_name))
if 'install_data' in _option_finalizers:
for func in list(_option_finalizers['install_data'].values()):
func(self)
class InstallLib(_install_lib.install_lib):
""" Extended lib installer """
user_options = _install_lib.install_lib.user_options + []
boolean_options = _install_lib.install_lib.boolean_options + []
def initialize_options(self):
""" Prepare for new options """
_install_lib.install_lib.initialize_options(self)
if 'install_lib' in _option_defaults:
for opt_name, default in _option_defaults['install_lib']:
setattr(self, opt_name, default)
def finalize_options(self):
""" Finalize options """
_install_lib.install_lib.finalize_options(self)
if 'install_lib' in _option_inherits:
for parent, opt_name in _option_inherits['install_lib']:
self.set_undefined_options(parent, (opt_name, opt_name))
if 'install_lib' in _option_finalizers:
for func in list(_option_finalizers['install_lib'].values()):
func(self)
class BuildExt(_build_ext.build_ext):
"""
Extended extension builder class
This class allows extensions to provide a ``check_prerequisites`` method
which is called before actually building it. The method takes the
`BuildExt` instance and returns whether the extension should be skipped or
not.
"""
def initialize_options(self):
""" Prepare for new options """
_build_ext.build_ext.initialize_options(self)
if 'build_ext' in _option_defaults:
for opt_name, default in _option_defaults['build_ext']:
setattr(self, opt_name, default)
def finalize_options(self):
""" Finalize options """
_build_ext.build_ext.finalize_options(self)
if 'build_ext' in _option_inherits:
for parent, opt_name in _option_inherits['build_ext']:
self.set_undefined_options(parent, (opt_name, opt_name))
if 'build_ext' in _option_finalizers:
for func in list(_option_finalizers['build_ext'].values()):
func(self)
def build_extension(self, ext):
"""
Build C extension - with extended functionality
The following features are added here:
- ``ext.check_prerequisites`` is called before the extension is being
built. See `Extension` for details. If the method does not exist,
simply no check will be run.
- The macros ``EXT_PACKAGE`` and ``EXT_MODULE`` will be filled (or
unset) depending on the extensions name, but only if they are not
already defined.
:Parameters:
`ext` : `Extension`
The extension to build. If it's a pure
``distutils.core.Extension``, simply no prequisites check is
applied.
:Return: whatever ``distutils.command.build_ext.build_ext`` returns
:Rtype: any
"""
# handle name macros
macros = dict(ext.define_macros or ())
tup = ext.name.split('.')
if len(tup) == 1:
pkg, mod = None, tup[0]
else:
pkg, mod = '.'.join(tup[:-1]), tup[-1]
if pkg is not None and 'EXT_PACKAGE' not in macros:
ext.define_macros.append(('EXT_PACKAGE', pkg))
if 'EXT_MODULE' not in macros:
ext.define_macros.append(('EXT_MODULE', mod))
if pkg is None:
macros = dict(ext.undef_macros or ())
if 'EXT_PACKAGE' not in macros:
ext.undef_macros.append('EXT_PACKAGE')
# handle prereq checks
try:
checker = ext.check_prerequisites
except AttributeError:
pass
else:
if checker(self):
log.info("Skipping %s extension" % ext.name)
return
return _build_ext.build_ext.build_extension(self, ext)
class Build(_build.build):
def initialize_options(self):
""" Prepare for new options """
_build.build.initialize_options(self)
if 'build' in _option_defaults:
for opt_name, default in _option_defaults['build']:
setattr(self, opt_name, default)
def finalize_options(self):
""" Finalize options """
_build.build.finalize_options(self)
if 'build' in _option_inherits:
for parent, opt_name in _option_inherits['build']:
self.set_undefined_options(parent, (opt_name, opt_name))
if 'build' in _option_finalizers:
for func in list(_option_finalizers['build'].values()):
func(self)

165
_setup/py3/data.py Normal file
View File

@ -0,0 +1,165 @@
# -*- coding: ascii -*-
#
# Copyright 2007, 2008, 2009, 2010, 2011
# Andr\xe9 Malo or his licensors, as applicable
#
# Licensed 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.
"""
===================
Data distribution
===================
This module provides tools to simplify data distribution.
"""
__author__ = "Andr\xe9 Malo"
__docformat__ = "restructuredtext en"
from distutils import filelist as _filelist
import os as _os
import posixpath as _posixpath
import sys as _sys
from _setup import commands as _commands
def splitpath(path):
""" Split a path """
drive, path = '', _os.path.normpath(path)
try:
splitunc = _os.path.splitunc
except AttributeError:
pass
else:
drive, path = splitunc(path)
if not drive:
drive, path = _os.path.splitdrive(path)
elems = []
try:
sep = _os.path.sep
except AttributeError:
sep = _os.path.join('1', '2')[1:-1]
while 1:
prefix, path = _os.path.split(path)
elems.append(path)
if prefix in ('', sep):
drive = _os.path.join(drive, prefix)
break
path = prefix
elems.reverse()
return drive, elems
def finalizer(installer):
""" Finalize install_data """
data_files = []
for item in installer.data_files:
if not isinstance(item, Data):
data_files.append(item)
continue
data_files.extend(item.flatten(installer))
installer.data_files = data_files
class Data(object):
""" File list container """
def __init__(self, files, target=None, preserve=0, strip=0,
prefix=None):
""" Initialization """
self._files = files
self._target = target
self._preserve = preserve
self._strip = strip
self._prefix = prefix
self.fixup_commands()
def fixup_commands(self):
pass
def from_templates(cls, *templates, **kwargs):
""" Initialize from template """
files = _filelist.FileList()
for tpl in templates:
for line in tpl.split(';'):
files.process_template_line(line.strip())
files.sort()
files.remove_duplicates()
result = []
for filename in files.files:
_, elems = splitpath(filename)
if '.svn' in elems:
continue
result.append(filename)
return cls(result, **kwargs)
from_templates = classmethod(from_templates)
def flatten(self, installer):
""" Flatten the file list to (target, file) tuples """
# pylint: disable = W0613
if self._prefix:
_, prefix = splitpath(self._prefix)
telems = prefix
else:
telems = []
tmap = {}
for fname in self._files:
(_, name), target = splitpath(fname), telems
if self._preserve:
if self._strip:
name = name[max(0, min(self._strip, len(name) - 1)):]
if len(name) > 1:
target = telems + name[:-1]
tmap.setdefault(_posixpath.join(*target), []).append(fname)
return list(tmap.items())
class Documentation(Data):
""" Documentation container """
def fixup_commands(self):
_commands.add_option('install_data', 'without-docs',
help_text='Do not install documentation files',
inherit='install',
)
_commands.add_finalizer('install_data', 'documentation', finalizer)
def flatten(self, installer):
""" Check if docs should be installed at all """
if installer.without_docs:
return []
return Data.flatten(self, installer)
class Manpages(Documentation):
""" Manpages container """
def dispatch(cls, files):
""" Automatically dispatch manpages to their target directories """
mpmap = {}
for manpage in files:
normalized = _os.path.normpath(manpage)
_, ext = _os.path.splitext(normalized)
if ext.startswith(_os.path.extsep):
ext = ext[len(_os.path.extsep):]
mpmap.setdefault(ext, []).append(manpage)
return [cls(manpages, prefix=_posixpath.join(
'share', 'man', 'man%s' % section,
)) for section, manpages in list(mpmap.items())]
dispatch = classmethod(dispatch)
def flatten(self, installer):
""" Check if manpages are suitable """
if _sys.platform == 'win32':
return []
return Documentation.flatten(self, installer)

View File

@ -0,0 +1,25 @@
# -*- coding: ascii -*-
#
# Copyright 2009, 2010, 2011
# Andr\xe9 Malo or his licensors, as applicable
#
# Licensed 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.
"""
====================
Package _setup.dev
====================
Development tools, not distributed.
"""
__author__ = "Andr\xe9 Malo"
__docformat__ = "restructuredtext en"

258
_setup/py3/dev/_pylint.py Normal file
View File

@ -0,0 +1,258 @@
# -*- coding: ascii -*-
#
# Copyright 2006, 2007, 2008, 2009, 2010, 2011
# Andr\xe9 Malo or his licensors, as applicable
#
# Licensed 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.
"""
=================================
Support for code analysis tools
=================================
Support for code analysis tools.
"""
__author__ = "Andr\xe9 Malo"
__docformat__ = "restructuredtext en"
import re as _re
import sys as _sys
from _setup import term as _term
from _setup import shell as _shell
class NotFinished(Exception):
""" Exception used for message passing in the stream filter """
class NotParseable(Exception):
""" Exception used for message passing in the stream filter """
class SpecialMessage(Exception):
""" Exception used for message passing in the stream filter """
class FilterStream(object):
""" Stream filter """
_LINERE = _re.compile(r'''
(?P<name>[^:]+)
:
(?P<lineno>\d+)
:\s+
\[(?P<mid>[^\],]+)(?:,\s+(?P<func>[^\]]+))?\]
\s+
(?P<desc>.*)
''', _re.X)
_SIMRE = _re.compile(r'in (?P<number>\d+) files')
_CYCRE = _re.compile(r'\((?P<cycle>[^)]+)\)')
def __init__(self, term, stream=_sys.stdout):
self.written = False
self._stream = stream
self._lastname = None
self._cycled = False
self._term = dict(term)
self._buffer = ''
def write(self, towrite):
""" Stream write function """
self._buffer += towrite
term = self._term
while True:
try:
name, lineno, mid, func, desc = self._parse()
except NotFinished:
break
except SpecialMessage as e:
self._dospecial(e)
continue
except NotParseable as e:
self._print_literal(str(e.args[0]))
continue
if name != self._lastname:
if self._lastname is not None:
self._stream.write("\n")
term['path'] = name
self._stream.write(
"%(BOLD)s>>> %(path)s%(NORMAL)s\n" % term
)
self._lastname = name
self.written = True
term['mid'] = mid
if mid.startswith('E') or mid.startswith('F'):
self._stream.write("%(BOLD)s%(RED)s%(mid)s%(NORMAL)s" % term)
elif mid == 'W0511':
self._stream.write(
"%(BOLD)s%(GREEN)s%(mid)s%(NORMAL)s" % term
)
else:
self._stream.write(
"%(BOLD)s%(YELLOW)s%(mid)s%(NORMAL)s" % term
)
if int(lineno) != 0:
term['lineno'] = lineno
self._stream.write(" (%(lineno)s" % term)
if func:
term['func'] = func
self._stream.write(
", %(BOLD)s%(YELLOW)s%(func)s%(NORMAL)s" % term
)
self._stream.write(')')
self._stream.write(": %s\n" % desc)
self._stream.flush()
return
def _print_literal(self, line):
""" Print literal """
suppress = (
line.startswith('Unable to get imported names for ') or
line.startswith("Exception exceptions.RuntimeError: 'generator "
"ignored GeneratorExit' in <generator object at") or
line.startswith("Exception RuntimeError: 'generator "
"ignored GeneratorExit' in <generator object") or
not line.strip()
)
if not suppress:
self._stream.write("%s\n" % line)
self._stream.flush()
self.written = True
def _dospecial(self, e):
""" Deal with special messages """
if e.args[0] == 'R0401':
pos = self._buffer.find('\n')
line, self._buffer = (
self._buffer[:pos + 1], self._buffer[pos + 1:]
)
term = self._term
term['mid'] = e.args[0]
if not self._cycled:
self._cycled = True
self._stream.write('\n')
self._stream.write(
"%(BOLD)s%(YELLOW)s%(mid)s%(NORMAL)s" % term
)
self._stream.write(": Cyclic imports\n")
match = self._CYCRE.search(e.args[1])
term['cycle'] = match.group('cycle')
self._stream.write("%(BOLD)s@@@ %(NORMAL)s%(cycle)s\n" % term)
self._stream.flush()
self.written = True
elif e.args[0] == 'R0801':
match = self._SIMRE.search(e.args[1])
if not match:
raise AssertionError(
'Could not determine number of similar files'
)
numfiles = int(match.group('number'))
pos = -1
for _ in range(numfiles + 1):
pos = self._buffer.find('\n', pos + 1)
if pos >= 0:
lines = self._buffer[:pos + 1]
self._buffer = self._buffer[pos + 1:]
term = self._term
self._stream.write("\n")
for name in lines.splitlines()[1:]:
name = name.rstrip()[2:]
term['path'] = name
self._stream.write(
"%(BOLD)s=== %(path)s%(NORMAL)s\n" % term
)
self._lastname = name
term['mid'] = e.args[0]
self._stream.write(
"%(BOLD)s%(YELLOW)s%(mid)s%(NORMAL)s" % term
)
self._stream.write(": %s\n" % e.args[1])
self._stream.flush()
self.written = True
def _parse(self):
""" Parse output """
if '\n' not in self._buffer:
raise NotFinished()
line = self._buffer[:self._buffer.find('\n') + 1]
self._buffer = self._buffer[len(line):]
line = line.rstrip()
match = self._LINERE.match(line)
if not match:
raise NotParseable(line)
mid = match.group('mid')
if mid in ('R0801', 'R0401'):
self._buffer = "%s\n%s" % (line, self._buffer)
raise SpecialMessage(mid, match.group('desc'))
return match.group('name', 'lineno', 'mid', 'func', 'desc')
def run(config, *args):
""" Run pylint """
try:
from pylint import lint
from pylint.reporters import text
except ImportError:
return 2
if config is None:
config = _shell.native('pylint.conf')
argv = ['--rcfile', config,
'--reports', 'no',
'--output-format', 'parseable',
'--include-ids', 'yes'
]
stream = FilterStream(_term.terminfo())
old_stderr = _sys.stderr
try:
# pylint: disable = E1101
_sys.stderr = stream
from pylint import __pkginfo__
if __pkginfo__.numversion < (0, 13):
# The lint tool is not very user friendly, so we need a hack here.
lint.REPORTER_OPT_MAP['parseable'] = \
lambda: text.TextReporter2(stream)
reporter = text.TextReporter2(stream)
else:
reporter = text.ParseableTextReporter(stream)
lint.REPORTER_OPT_MAP['parseable'] = lambda: reporter
for path in args:
try:
try:
lint.Run(argv + [path], reporter=reporter)
except SystemExit:
pass # don't accept the exit. strange errors happen...
if stream.written:
print()
stream.written = False
except KeyboardInterrupt:
print()
raise
finally:
_sys.stderr = old_stderr
return 0

View File

@ -0,0 +1,31 @@
# -*- coding: ascii -*-
#
# Copyright 2006, 2007, 2008, 2009, 2010, 2011
# Andr\xe9 Malo or his licensors, as applicable
#
# Licensed 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.
"""
=================================
Support for code analysis tools
=================================
Support for code analysis tools.
"""
__author__ = "Andr\xe9 Malo"
__docformat__ = "restructuredtext en"
def pylint(config, *args):
""" Run pylint """
from _setup.dev import _pylint
return _pylint.run(config, *args)

131
_setup/py3/dev/apidoc.py Normal file
View File

@ -0,0 +1,131 @@
# -*- coding: ascii -*-
#
# Copyright 2007, 2008, 2009, 2010, 2011
# Andr\xe9 Malo or his licensors, as applicable
#
# Licensed 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.
"""
==================
API doc builders
==================
API doc builders.
"""
__author__ = "Andr\xe9 Malo"
__docformat__ = "restructuredtext en"
import os as _os
import re as _re
from _setup import shell as _shell
from _setup import term as _term
from _setup import util as _util
def _cleanup_epydoc(target):
"""
Cleanup epydoc generated files
This removes the epydoc-footer. It changes every release because of the
timestamp. That creates bad diffs (accidently it's also invalid html).
"""
search = _re.compile(r'<table[^<>]+width="100%%"').search
for filename in _shell.files(target, '*.html'):
fp = open(filename, 'r')
try:
html = fp.read()
finally:
fp.close()
match = search(html)
if match:
start = match.start()
end = html.find('</table>', start)
if end >= 0:
end += len('</table>') + 1
html = html[:start] + html[end:]
fp = open(filename, 'w')
try:
fp.write(html)
finally:
fp.close()
_VERSION_SEARCH = _re.compile(
r'\bversion\s+(?P<major>\d+)\.(?P<minor>\d+)'
).search
def epydoc(**kwargs):
""" Run epydoc """
# pylint: disable = R0912
prog = kwargs.get('epydoc') or 'epydoc'
if not _os.path.dirname(_os.path.normpath(prog)):
prog = _shell.frompath(prog)
if not prog:
_term.red("%(epydoc)s not found",
epydoc=kwargs.get('epydoc') or 'epydoc',
)
return False
version = _VERSION_SEARCH(_shell.spawn(prog, "--version", stdout=True))
if version is not None:
try:
version = tuple(map(int, version.group('major', 'minor')))
except (TypeError, ValueError):
version = None
if version is None:
_term.red("%(prog)s version not recognized" % locals())
return False
if version < (3, 0):
_term.red("%(prog)s is too old %(version)r < (3, 0)" % locals())
return False
env = dict(_os.environ)
prepend = kwargs.get('prepend')
if prepend:
toprepend = _os.pathsep.join(map(str, prepend))
if 'PYTHONPATH' in env:
env['PYTHONPATH'] = _os.pathsep.join((
toprepend, env['PYTHONPATH']
))
else:
env['PYTHONPATH'] = toprepend
append = kwargs.get('append')
if append:
toappend = _os.pathsep.join(map(str, append))
if 'PYTHONPATH' in env:
env['PYTHONPATH'] = _os.pathsep.join((
env['PYTHONPATH'], toappend
))
else:
env['PYTHONPATH'] = toappend
moreenv = kwargs.get('env')
if moreenv:
env.update(moreenv)
config = kwargs.get('config') or _shell.native('docs/epydoc.conf')
argv = [prog, '--config', config]
res = not _shell.spawn(*argv, **{'env': env})
if res:
cfg = _util.SafeConfigParser()
cfg.read(config)
try:
target = dict(cfg.items('epydoc'))['target']
except KeyError:
pass
else:
_cleanup_epydoc(target)
return res

50
_setup/py3/dev/userdoc.py Normal file
View File

@ -0,0 +1,50 @@
# -*- coding: ascii -*-
#
# Copyright 2009, 2010, 2011
# Andr\xe9 Malo or his licensors, as applicable
#
# Licensed 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.
"""
===================
User doc builders
===================
User doc builders.
"""
__author__ = "Andr\xe9 Malo"
__docformat__ = "restructuredtext en"
import os as _os
from _setup import shell as _shell
from _setup import term as _term
def sphinx(**kwargs):
""" Run sphinx """
prog = _shell.frompath('sphinx-build')
if prog is None:
_term.red("sphinx-build not found")
return False
env = dict(_os.environ)
argv = [
prog, '-a',
'-d', _os.path.join(kwargs['build'], 'doctrees'),
'-b', 'html',
kwargs['source'],
kwargs['target'],
]
return not _shell.spawn(*argv, **{'env': env})

51
_setup/py3/dist.py Normal file
View File

@ -0,0 +1,51 @@
# -*- coding: ascii -*-
#
# Copyright 2007, 2008, 2009, 2010, 2011
# Andr\xe9 Malo or his licensors, as applicable
#
# Licensed 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.
"""
================
dist utilities
================
dist utilities.
"""
__author__ = "Andr\xe9 Malo"
__docformat__ = "restructuredtext en"
import sys as _sys
from _setup import shell as _shell
def run_setup(*args, **kwargs):
""" Run setup """
if 'setup' in kwargs:
script = kwargs.get('setup') or 'setup.py'
del kwargs['setup']
else:
script = 'setup.py'
if 'fakeroot' in kwargs:
fakeroot = kwargs['fakeroot']
del kwargs['fakeroot']
else:
fakeroot = None
if kwargs:
raise TypeError("Unrecognized keyword parameters")
script = _shell.native(script)
argv = [_sys.executable, script] + list(args)
if fakeroot:
argv.insert(0, fakeroot)
return not _shell.spawn(*argv)

253
_setup/py3/ext.py Normal file
View File

@ -0,0 +1,253 @@
# -*- coding: ascii -*-
#
# Copyright 2007, 2008, 2009, 2010, 2011
# Andr\xe9 Malo or his licensors, as applicable
#
# Licensed 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.
"""
===================
C extension tools
===================
C extension tools.
"""
__author__ = "Andr\xe9 Malo"
__docformat__ = "restructuredtext en"
__test__ = False
from distutils import core as _core
from distutils import errors as _distutils_errors
from distutils import log
import os as _os
import posixpath as _posixpath
import shutil as _shutil
import tempfile as _tempfile
from _setup import commands as _commands
def _install_finalizer(installer):
if installer.without_c_extensions:
installer.distribution.ext_modules = []
def _build_finalizer(builder):
if builder.without_c_extensions:
builder.extensions = []
class Extension(_core.Extension):
"""
Extension with prerequisite check interface
If your check is cacheable (during the setup run), override
`cached_check_prerequisites`, `check_prerequisites` otherwise.
:IVariables:
`cached_check` : ``bool``
The cached check result
"""
cached_check = None
def __init__(self, *args, **kwargs):
""" Initialization """
if 'depends' in kwargs:
self.depends = kwargs['depends'] or []
else:
self.depends = []
_core.Extension.__init__(self, *args, **kwargs)
# add include path
included = _posixpath.join('_setup', 'include')
if included not in self.include_dirs:
self.include_dirs.append(included)
# add cext.h to the dependencies
cext_h = _posixpath.join(included, 'cext.h')
if cext_h not in self.depends:
self.depends.append(cext_h)
_commands.add_option('install_lib', 'without-c-extensions',
help_text='Don\'t install C extensions',
inherit='install',
)
_commands.add_finalizer('install_lib', 'c-extensions',
_install_finalizer
)
_commands.add_option('build_ext', 'without-c-extensions',
help_text='Don\'t build C extensions',
inherit=('build', 'install_lib'),
)
_commands.add_finalizer('build_ext', 'c-extensions', _build_finalizer)
def check_prerequisites(self, build):
"""
Check prerequisites
The check should cover all dependencies needed for the extension to
be built and run. The method can do the following:
- return a false value: the extension will be built
- return a true value: the extension will be skipped. This is useful
for optional extensions
- raise an exception. This is useful for mandatory extensions
If the check result is cacheable (during the setup run), override
`cached_check_prerequisites` instead.
:Parameters:
`build` : `BuildExt`
The extension builder
:Return: Skip the extension?
:Rtype: ``bool``
"""
if self.cached_check is None:
log.debug("PREREQ check for %s" % self.name)
self.cached_check = self.cached_check_prerequisites(build)
else:
log.debug("PREREQ check for %s (cached)" % self.name)
return self.cached_check
def cached_check_prerequisites(self, build):
"""
Check prerequisites
The check should cover all dependencies needed for the extension to
be built and run. The method can do the following:
- return a false value: the extension will be built
- return a true value: the extension will be skipped. This is useful
for optional extensions
- raise an exception. This is useful for mandatory extensions
If the check result is *not* cacheable (during the setup run),
override `check_prerequisites` instead.
:Parameters:
`build` : `BuildExt`
The extension builder
:Return: Skip the extension?
:Rtype: ``bool``
"""
# pylint: disable = W0613
log.debug("Nothing to check for %s!" % self.name)
return False
class ConfTest(object):
"""
Single conftest abstraction
:IVariables:
`_tempdir` : ``str``
The tempdir created for this test
`src` : ``str``
Name of the source file
`target` : ``str``
Target filename
`compiler` : ``CCompiler``
compiler instance
`obj` : ``list``
List of object filenames (``[str, ...]``)
"""
_tempdir = None
def __init__(self, build, source):
"""
Initialization
:Parameters:
`build` : ``distuils.command.build_ext.build_ext``
builder instance
`source` : ``str``
Source of the file to compile
"""
self._tempdir = tempdir = _tempfile.mkdtemp()
src = _os.path.join(tempdir, 'conftest.c')
fp = open(src, 'w')
try:
fp.write(source)
finally:
fp.close()
self.src = src
self.compiler = compiler = build.compiler
self.target = _os.path.join(tempdir, 'conftest')
self.obj = compiler.object_filenames([src], output_dir=tempdir)
def __del__(self):
""" Destruction """
self.destroy()
def destroy(self):
""" Destroy the conftest leftovers on disk """
tempdir, self._tempdir = self._tempdir, None
if tempdir is not None:
_shutil.rmtree(tempdir)
def compile(self, **kwargs):
"""
Compile the conftest
:Parameters:
`kwargs` : ``dict``
Optional keyword parameters for the compiler call
:Return: Was the compilation successful?
:Rtype: ``bool``
"""
kwargs['output_dir'] = self._tempdir
try:
self.compiler.compile([self.src], **kwargs)
except _distutils_errors.CompileError:
return False
return True
def link(self, **kwargs):
r"""
Link the conftest
Before you can link the conftest objects they need to be `compile`\d.
:Parameters:
`kwargs` : ``dict``
Optional keyword parameters for the linker call
:Return: Was the linking successful?
:Rtype: ``bool``
"""
try:
self.compiler.link_executable(self.obj, self.target, **kwargs)
except _distutils_errors.LinkError:
return False
return True
def pipe(self, mode="r"):
r"""
Execute the conftest binary and connect to it using a pipe
Before you can pipe to or from the conftest binary it needs to
be `link`\ed.
:Parameters:
`mode` : ``str``
Pipe mode - r/w
:Return: The open pipe
:Rtype: ``file``
"""
return _os.popen(self.compiler.executable_filename(self.target), mode)

View File

@ -0,0 +1,28 @@
# -*- coding: ascii -*-
#
# Copyright 2010, 2011
# Andr\xe9 Malo or his licensors, as applicable
#
# Licensed 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.
"""
=====================
Package _setup.make
=====================
Make tools, not distributed.
"""
__author__ = "Andr\xe9 Malo"
__docformat__ = "restructuredtext en"
# pylint: disable = W0611
from _setup.make._make import main, fail, warn, fatal, Target

338
_setup/py3/make/_make.py Normal file
View File

@ -0,0 +1,338 @@
# -*- coding: ascii -*-
#
# Copyright 2007, 2008, 2009, 2010, 2011
# Andr\xe9 Malo or his licensors, as applicable
#
# Licensed 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.
"""
==================
Simple make base
==================
Simple make base.
"""
__author__ = "Andr\xe9 Malo"
__docformat__ = "restructuredtext en"
import sys as _sys
from _setup import term as _term
class Failure(SystemExit):
""" Failure exception """
def fail(reason):
""" Fail for a reason """
raise Failure(reason)
def warn(message, name=None):
""" Warn """
_term.red("%(NAME)sWarning: %(msg)s",
NAME=name and "%s:" % name or '', msg=message
)
def fatal(reason):
""" Fatal error, immediate stop """
print(reason, file=_sys.stderr)
_sys.exit(1)
class Target(object):
""" Target base class """
NAME = None
DEPS = None
HIDDEN = False
ERROR = None
def __init__(self, runner):
""" Base __init__ """
self.runner = runner
self.init()
def init(self):
""" Default init hook """
pass
def run(self):
""" Default run hook """
pass
def clean(self, scm=True, dist=False):
""" Default clean hook """
pass
class _Runner(object):
""" Runner """
def __init__(self, *targetscollection):
""" Initialization """
tdict = {}
if not targetscollection:
import __main__
targetscollection = [__main__]
from _setup.make import default_targets
if default_targets not in targetscollection:
targetscollection.append(default_targets)
for targets in targetscollection:
for value in list(vars(targets).values()):
if isinstance(value, type) and issubclass(value, Target) and \
value.NAME is not None:
if value.NAME in tdict:
if issubclass(value, tdict[value.NAME]):
pass # override base target
elif issubclass(tdict[value.NAME], value):
continue # found base later. ignore
else:
warn('Ambiguous target name', value.NAME)
continue
tdict[value.NAME] = value
self._tdict = tdict
self._itdict = {}
def print_help(self):
""" Print make help """
import textwrap as _textwrap
targets = self.targetinfo()
keys = []
for key, info in list(targets.items()):
if not info['hide']:
keys.append(key)
keys.sort()
length = max(list(map(len, keys)))
info = []
for key in keys:
info.append("%s%s" % (
(key + " " * length)[:length + 2],
_textwrap.fill(
targets[key]['desc'].strip(),
subsequent_indent=" " * (length + 2)
),
))
print("Available targets:\n\n" + "\n".join(info))
def targetinfo(self):
""" Extract target information """
result = {}
for name, cls in list(self._tdict.items()):
result[name] = {
'desc': cls.__doc__ or "no description",
'hide': cls.HIDDEN,
'deps': cls.DEPS or (),
}
return result
def _topleveltargets(self):
""" Find all top level targets """
rev = {} # key is a dep of [values]
all_ = self.targetinfo()
for target, info in list(all_.items()):
for dep in info['deps']:
if dep not in all_:
fatal("Unknown target '%s' (dep of %s) -> exit" % (
dep, target
))
rev.setdefault(dep, []).append(target)
return [target for target, info in list(rev.items()) if not info]
def _run(self, target, seen=None):
""" Run a target """
if target.DEPS:
self(*target.DEPS, **{'seen': seen})
if not target.HIDDEN:
_term.yellow(">>> %(name)s", name=target.NAME)
try:
result = target.run()
except KeyboardInterrupt:
result, target.ERROR = False, "^C -> exit"
except Failure as e:
result, target.ERROR = False, "%s: %s" % (target.NAME, e)
except (SystemExit, MemoryError):
raise
except:
import traceback
target.ERROR = "%s errored:\n%s" % (target.NAME, ''.join(
traceback.format_exception(*_sys.exc_info())
))
result = False
else:
if result is None:
result = True
return result
def _clean(self, target, scm, dist, seen=None):
""" Run a target """
if target.DEPS:
self.run_clean(
*target.DEPS, **{'scm': scm, 'dist': dist, 'seen': seen}
)
try:
result = target.clean(scm, dist)
except KeyboardInterrupt:
result, target.ERROR = False, "^C -> exit"
except Failure as e:
result, target.ERROR = False, "%s: %s" % (target.NAME, e)
except (SystemExit, MemoryError):
raise
except:
import traceback
target.ERROR = "%s errored:\n%s" % (target.NAME, ''.join(
traceback.format_exception(*_sys.exc_info())
))
result = False
else:
if result is None:
result = True
return result
def _make_init(self, seen):
""" Make init mapper """
def init(target):
""" Return initialized target """
if target not in seen:
try:
seen[target] = self._tdict[target](self)
except KeyError:
fatal("Unknown target '%s' -> exit" % target)
else:
seen[target] = None
return seen[target]
return init
def run_clean(self, *targets, **kwargs):
""" Run targets """
def pop(name, default=None):
""" Pop """
if name in kwargs:
value = kwargs[name]
del kwargs[name]
if value is None:
return default
return value
else:
return default
seen = pop('seen', {})
scm = pop('scm', True)
dist = pop('dist', False)
if kwargs:
raise TypeError('Unknown keyword parameters')
if not targets:
top_targets = self._topleveltargets()
targets = self.targetinfo()
for item in top_targets:
del targets[item]
targets = list(targets.keys())
targets.sort()
top_targets.sort()
targets = top_targets + targets
init = self._make_init(seen)
for name in targets:
target = init(name)
if target is not None:
if not self._clean(target, scm=scm, dist=dist, seen=seen):
msg = target.ERROR
if msg is None:
msg = "Clean target %s returned error -> exit" % name
fatal(msg)
def __call__(self, *targets, **kwargs):
""" Run targets """
if 'seen' in kwargs:
seen = kwargs['seen']
del kwargs['seen']
else:
seen = None
if seen is None:
seen = self._itdict
if kwargs:
raise TypeError('Unknown keyword parameters')
init = self._make_init(seen)
for name in targets:
target = init(name)
if target is not None:
if not self._run(target, seen):
msg = target.ERROR
if msg is None:
msg = "Target %s returned error -> exit" % name
fatal(msg)
def main(*args, **kwargs):
"""
main(argv=None, *args, name=None)
Main start point. This function parses the command line and executes the
targets given through `argv`. If there are no targets given, a help output
is generated.
:Parameters:
`argv` : sequence
Command line arguments. If omitted or ``None``, they are picked from
``sys.argv``.
`args` : ``tuple``
The list of modules with targets. If omitted, ``__main__``
is imported and treated as target module. Additionally the mechanism
always adds the `_setup.make` module (this one) to the list in order
to grab some default targets.
`name` : ``str``
Name of the executing module. If omitted or ``None``, ``'__main__'``
is assumed. If the final name is not ``'__main__'``, the function
returns immediately.
"""
try:
name = kwargs['name']
except KeyError:
name = '__main__'
else:
del kwargs['name']
if name is None:
name = '__main__'
try:
argv = kwargs['argv']
except KeyError:
if not args:
args = (None,)
else:
del kwargs['argv']
args = (argv,) + args
if kwargs:
raise TypeError("Unrecognized keyword arguments for main()")
if name == '__main__':
argv, args = args[0], args[1:]
if argv is None:
argv = _sys.argv[1:]
runner = _Runner(*args)
if argv:
runner(*argv)
else:
runner.print_help()

View File

@ -0,0 +1,110 @@
# -*- coding: ascii -*-
#
# Copyright 2007, 2008, 2009, 2010, 2011
# Andr\xe9 Malo or his licensors, as applicable
#
# Licensed 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.
"""
==================
Simple make base
==================
Simple make base.
"""
__author__ = "Andr\xe9 Malo"
__docformat__ = "restructuredtext en"
import os as _os
import sys as _sys
from _setup import make as _make
from _setup import shell as _shell
class MakefileTarget(_make.Target):
""" Create a make file """
NAME = 'makefile'
def run(self):
def escape(value):
""" Escape for make and shell """
return '"%s"' % value.replace(
'\\', '\\\\').replace(
'"', '\\"').replace(
'$', '\\$$')
def decorate(line, prefix='# ', width=78, char='~', padding=' '):
""" Decorate a line """
line = line.center(width - len(prefix))
return '%s%s%s%s%s%s' % (
prefix,
char * (len(line) - len(line.lstrip()) - len(padding)),
padding,
line.strip(),
padding,
char * (len(line) - len(line.rstrip()) - len(padding)),
)
python = escape(_sys.executable)
script = escape(_sys.argv[0])
targets = self.runner.targetinfo()
names = []
for name, info in list(targets.items()):
if not info['hide']:
names.append(name)
names.sort()
fp = open(_shell.native('Makefile'), 'w')
print(decorate("Generated Makefile, DO NOT EDIT"), file=fp)
print(decorate("python %s %s" % (
_os.path.basename(script), self.NAME
)), file=fp)
print(file=fp)
print("_default_:", file=fp)
print("\t@%s %s" % (python, script), file=fp)
for name in names:
print("\n", file=fp)
print("# %s" % \
targets[name]['desc'].splitlines()[0].strip(), file=fp)
print("%s:" % name, file=fp)
print("\t@%s %s %s" % (python, script, escape(name)), file=fp)
print(file=fp)
extension = self.extend(names)
if extension is not None:
print(extension, file=fp)
print(file=fp)
print(".PHONY: _default_ %s\n\n" % ' '.join(names), file=fp)
fp.close()
def extend(self, names):
pass
class CleanTarget(_make.Target):
""" Clean the mess """
NAME = 'clean'
_scm, _dist = True, False
def run(self):
self.runner.run_clean(scm=self._scm, dist=self._dist)
class DistCleanTarget(CleanTarget):
""" Clean as freshly unpacked dist package """
NAME = 'distclean'
_scm, _dist = False, True
class ExtraCleanTarget(CleanTarget):
""" Clean everything """
NAME = 'extraclean'
_scm, _dist = True, True

326
_setup/py3/make/targets.py Normal file
View File

@ -0,0 +1,326 @@
# -*- coding: ascii -*-
#
# Copyright 2007 - 2013
# Andr\xe9 Malo or his licensors, as applicable
#
# Licensed 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.
"""
==================
Standard targets
==================
Standard targets.
"""
__author__ = "Andr\xe9 Malo"
__docformat__ = "restructuredtext en"
import os as _os
import sys as _sys
from _setup import dist as _dist
from _setup import make as _make
from _setup import shell as _shell
from _setup import term as _term
class Distribution(_make.Target):
""" Build a distribution """
NAME = "dist"
DEPS = ["MANIFEST"]
_dist, _ebuilds, _changes = None, None, None
def init(self):
raise NotImplementedError()
def run(self):
exts = self.dist_pkg()
digests = self.digest_files(exts)
self.sign_digests(digests)
self.copy_ebuilds()
self.copy_changes()
def dist_pkg(self):
_term.green("Building package...")
_dist.run_setup("sdist", "--formats", "tar,zip",
fakeroot=_shell.frompath('fakeroot')
)
exts = ['.zip']
for name in _shell.files(self._dist, '*.tar', False):
exts.extend(self.compress(name))
_shell.rm(name)
return exts
def compress(self, filename):
""" Compress file """
ext = _os.path.splitext(filename)[1]
exts = []
exts.append('.'.join((ext, self.compress_gzip(filename))))
exts.append('.'.join((ext, self.compress_bzip2(filename))))
exts.append('.'.join((ext, self.compress_xz(filename))))
return exts
def compress_xz(self, filename):
outfilename = filename + '.xz'
self.compress_external(filename, outfilename, 'xz', '-c9')
return 'xz'
def compress_bzip2(self, filename):
outfilename = filename + '.bz2'
try:
import bz2 as _bz2
except ImportError:
self.compress_external(filename, outfilename, 'bzip2', '-c9')
else:
outfile = _bz2.BZ2File(outfilename, 'w')
self.compress_internal(filename, outfile, outfilename)
return 'bz2'
def compress_gzip(self, filename):
outfilename = filename + '.gz'
try:
import gzip as _gzip
except ImportError:
self.compress_external(filename, outfilename, 'gzip', '-c9')
else:
outfile = _gzip.GzipFile(filename, 'wb',
fileobj=open(outfilename, 'wb')
)
self.compress_internal(filename, outfile, outfilename)
return 'gz'
def compress_external(self, infile, outfile, *argv):
argv = list(argv)
argv[0] = _shell.frompath(argv[0])
if argv[0] is not None:
return not _shell.spawn(*argv, **{
'filepipe': True, 'stdin': infile, 'stdout': outfile,
})
return None
def compress_internal(self, filename, outfile, outfilename):
infile = open(filename, 'rb')
try:
try:
while 1:
chunk = infile.read(8192)
if not chunk:
break
outfile.write(chunk)
outfile.close()
except:
e = _sys.exc_info()
try:
_shell.rm(outfilename)
finally:
try:
raise e[0](e[1]).with_traceback(e[2])
finally:
del e
finally:
infile.close()
def digest_files(self, exts):
""" digest files """
digests = {}
digestnames = {}
for ext in exts:
for name in _shell.files(self._dist, '*' + ext, False):
basename = _os.path.basename(name)
if basename not in digests:
digests[basename] = []
digests[basename].extend(self.digest(name))
digestname = basename[:-len(ext)]
if digestname not in digestnames:
digestnames[digestname] = []
digestnames[digestname].append(basename)
result = []
for name, basenames in digestnames.items():
result.append(_os.path.join(self._dist, name + '.digests'))
fp = open(result[-1], 'wb')
try:
fp.write(
b'\n# The file may contain MD5, SHA1 and SHA256 digests\n'
)
fp.write(b'# Check archive integrity with, e.g. md5sum -c\n')
fp.write(b'# Check digest file integrity with PGP\n\n')
basenames.sort()
for basename in basenames:
for digest in digests[basename]:
fp.write((
"%s *%s\n" % (digest, basename)).encode('utf-8')
)
finally:
fp.close()
return result
def digest(self, filename):
result = []
for method in (self.md5, self.sha1, self.sha256):
digest = method(filename)
if digest is not None:
result.append(digest)
return result
def do_digest(self, hashfunc, name, filename):
filename = _shell.native(filename)
_term.green("%(digest)s-digesting %(name)s...",
digest=name, name=_os.path.basename(filename))
fp = open(filename, 'rb')
sig = hashfunc()
block = fp.read(8192)
while block:
sig.update(block)
block = fp.read(8192)
fp.close()
return sig.hexdigest()
param = {'sig': sig.hexdigest(), 'file': _os.path.basename(filename)}
fp = open("%s.%s" % (filename, name), "w")
fp.write("%(sig)s *%(file)s\n" % param)
fp.close()
return True
def md5(self, filename):
try:
from hashlib import md5
except ImportError:
try:
from md5 import new as md5
except ImportError:
_make.warn("md5 not found -> skip md5 digests", self.NAME)
return None
return self.do_digest(md5, "md5", filename)
def sha1(self, filename):
try:
from hashlib import sha1
except ImportError:
try:
from sha import new as sha1
except ImportError:
_make.warn("sha1 not found -> skip sha1 digests", self.NAME)
return None
return self.do_digest(sha1, "sha1", filename)
def sha256(self, filename):
try:
from hashlib import sha256
except ImportError:
try:
from Crypto.Hash.SHA256 import new as sha256
except ImportError:
_make.warn(
"sha256 not found -> skip sha256 digests", self.NAME
)
return None
return self.do_digest(sha256, "sha256", filename)
def copy_ebuilds(self):
if self._ebuilds is not None:
for src in _shell.files(self._ebuilds, '*.ebuild'):
_shell.cp(src, self._dist)
def copy_changes(self):
if self._changes is not None:
_shell.cp(self._changes, self._dist)
def sign_digests(self, digests):
for digest in digests:
self.sign(digest, detach=False)
def sign(self, filename, detach=True):
filename = _shell.native(filename)
try:
from pyme import core, errors
from pyme.constants.sig import mode
except ImportError:
return self.sign_external(filename, detach=detach)
_term.green("signing %(name)s...", name=_os.path.basename(filename))
sigmode = [mode.CLEAR, mode.DETACH][bool(detach)]
fp = core.Data(file=filename)
sig = core.Data()
try:
c = core.Context()
except errors.GPGMEError:
return self.sign_external(filename, detach=detach)
c.set_armor(1)
try:
c.op_sign(fp, sig, sigmode)
except errors.GPGMEError as e:
_make.fail(str(e))
sig.seek(0, 0)
if detach:
open("%s.asc" % filename, "w").write(sig.read())
else:
open(filename, "w").write(sig.read())
return True
def sign_external(self, filename, detach=True):
""" Sign calling gpg """
gpg = _shell.frompath('gpg')
if gpg is None:
_make.warn('GPG not found -> cannot sign')
return False
if detach:
_shell.spawn(gpg,
'--armor',
'--output', filename + '.asc',
'--detach-sign',
'--',
filename,
)
else:
_shell.spawn(gpg,
'--output', filename + '.signed',
'--clearsign',
'--',
filename,
)
_os.rename(filename + '.signed', filename)
return True
def clean(self, scm, dist):
_term.green("Removing dist files...")
_shell.rm_rf(self._dist)
class Manifest(_make.Target):
""" Create manifest """
NAME = "MANIFEST"
HIDDEN = True
DEPS = ["doc"]
def run(self):
_term.green("Creating %(name)s...", name=self.NAME)
dest = _shell.native(self.NAME)
dest = open(dest, 'w')
for name in self.manifest_names():
dest.write("%s\n" % name)
dest.close()
def manifest_names(self):
import setup
for item in setup.manifest():
yield item
def clean(self, scm, dist):
""" Clean manifest """
if scm:
_term.green("Removing MANIFEST")
_shell.rm(self.NAME)

420
_setup/py3/setup.py Normal file
View File

@ -0,0 +1,420 @@
# -*- coding: ascii -*-
#
# Copyright 2007 - 2013
# Andr\xe9 Malo or his licensors, as applicable
#
# Licensed 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.
"""
===================
Main setup runner
===================
This module provides a wrapper around the distutils core setup.
"""
__author__ = "Andr\xe9 Malo"
__docformat__ = "restructuredtext en"
import configparser as _config_parser
from distutils import core as _core
import os as _os
import posixpath as _posixpath
import sys as _sys
from _setup import commands as _commands
from _setup import data as _data
from _setup import ext as _ext
from _setup import util as _util
from _setup import shell as _shell
def check_python_version(impl, version_min, version_max):
""" Check python version """
if impl == 'python':
version_info = _sys.version_info
elif impl == 'pypy':
version_info = getattr(_sys, 'pypy_version_info', None)
if not version_info:
return
elif impl == 'jython':
if not 'java' in _sys.platform.lower():
return
version_info = _sys.version_info
else:
raise AssertionError("impl not in ('python', 'pypy', 'jython')")
pyversion = list(map(int, version_info[:3]))
if version_min:
min_required = list(
map(int, '.'.join((version_min, '0.0.0')).split('.')[:3])
)
if pyversion < min_required:
raise EnvironmentError("Need at least %s %s (vs. %s)" % (
impl, version_min, '.'.join(map(str, pyversion))
))
if version_max:
max_required = list(map(int, version_max.split('.')))
max_required[-1] += 1
if pyversion >= max_required:
raise EnvironmentError("Need at max %s %s (vs. %s)" % (
impl,
version_max,
'.'.join(map(str, pyversion))
))
def find_description(docs):
"""
Determine the package description from DESCRIPTION
:Parameters:
`docs` : ``dict``
Docs config section
:Return: Tuple of summary, description and license
(``('summary', 'description', 'license')``)
(all may be ``None``)
:Rtype: ``tuple``
"""
summary = None
filename = docs.get('meta.summary', 'SUMMARY').strip()
if filename and _os.path.isfile(filename):
fp = open(filename)
try:
try:
summary = fp.read().strip().splitlines()[0].rstrip()
except IndexError:
summary = ''
finally:
fp.close()
description = None
filename = docs.get('meta.description', 'DESCRIPTION').strip()
if filename and _os.path.isfile(filename):
fp = open(filename)
try:
description = fp.read().rstrip()
finally:
fp.close()
if summary is None and description:
from docutils import core
summary = core.publish_parts(
source=description,
source_path=filename,
writer_name='html',
)['title'].encode('utf-8')
return summary, description
def find_classifiers(docs):
"""
Determine classifiers from CLASSIFIERS
:return: List of classifiers (``['classifier', ...]``)
:rtype: ``list``
"""
filename = docs.get('meta.classifiers', 'CLASSIFIERS').strip()
if filename and _os.path.isfile(filename):
fp = open(filename)
try:
content = fp.read()
finally:
fp.close()
content = [item.strip() for item in content.splitlines()]
return [item for item in content if item and not item.startswith('#')]
return []
def find_provides(docs):
"""
Determine provides from PROVIDES
:return: List of provides (``['provides', ...]``)
:rtype: ``list``
"""
filename = docs.get('meta.provides', 'PROVIDES').strip()
if filename and _os.path.isfile(filename):
fp = open(filename)
try:
content = fp.read()
finally:
fp.close()
content = [item.strip() for item in content.splitlines()]
return [item for item in content if item and not item.startswith('#')]
return []
def find_license(docs):
"""
Determine license from LICENSE
:return: License text
:rtype: ``str``
"""
filename = docs.get('meta.license', 'LICENSE').strip()
if filename and _os.path.isfile(filename):
fp = open(filename)
try:
return fp.read().rstrip()
finally:
fp.close()
return None
def find_packages(manifest):
""" Determine packages and subpackages """
packages = {}
collect = manifest.get('packages.collect', '').split()
lib = manifest.get('packages.lib', '.')
try:
sep = _os.path.sep
except AttributeError:
sep = _os.path.join('1', '2')[1:-1]
for root in collect:
for dirpath, _, filenames in _shell.walk(_os.path.join(lib, root)):
if dirpath.find('.svn') >= 0:
continue
if '__init__.py' in filenames:
packages[
_os.path.normpath(dirpath).replace(sep, '.')
] = None
packages = list(packages.keys())
packages.sort()
return packages
def find_data(name, docs):
""" Determine data files """
result = []
if docs.get('extra', '').strip():
result.append(_data.Documentation(docs['extra'].split(),
prefix='share/doc/%s' % name,
))
if docs.get('examples.dir', '').strip():
tpl = ['recursive-include %s *' % docs['examples.dir']]
if docs.get('examples.ignore', '').strip():
tpl.extend(["global-exclude %s" % item
for item in docs['examples.ignore'].split()
])
strip = int(docs.get('examples.strip', '') or 0)
result.append(_data.Documentation.from_templates(*tpl, **{
'strip': strip,
'prefix': 'share/doc/%s' % name,
'preserve': 1,
}))
if docs.get('userdoc.dir', '').strip():
tpl = ['recursive-include %s *' % docs['userdoc.dir']]
if docs.get('userdoc.ignore', '').strip():
tpl.extend(["global-exclude %s" % item
for item in docs['userdoc.ignore'].split()
])
strip = int(docs.get('userdoc.strip', '') or 0)
result.append(_data.Documentation.from_templates(*tpl, **{
'strip': strip,
'prefix': 'share/doc/%s' % name,
'preserve': 1,
}))
if docs.get('apidoc.dir', '').strip():
tpl = ['recursive-include %s *' % docs['apidoc.dir']]
if docs.get('apidoc.ignore', '').strip():
tpl.extend(["global-exclude %s" % item
for item in docs['apidoc.ignore'].split()
])
strip = int(docs.get('apidoc.strip', '') or 0)
result.append(_data.Documentation.from_templates(*tpl, **{
'strip': strip,
'prefix': 'share/doc/%s' % name,
'preserve': 1,
}))
if docs.get('man', '').strip():
result.extend(_data.Manpages.dispatch(docs['man'].split()))
return result
def make_manifest(manifest, config, docs, kwargs):
""" Create file list to pack up """
# pylint: disable = R0912
kwargs = kwargs.copy()
kwargs['script_args'] = ['install']
kwargs['packages'] = list(kwargs.get('packages') or ()) + [
'_setup', '_setup.py2', '_setup.py3',
] + list(manifest.get('packages.extra', '').split() or ())
_core._setup_stop_after = "commandline"
try:
dist = _core.setup(**kwargs)
finally:
_core._setup_stop_after = None
result = ['MANIFEST', 'PKG-INFO', 'setup.py'] + list(config)
# TODO: work with default values:
for key in ('classifiers', 'description', 'summary', 'provides',
'license'):
filename = docs.get('meta.' + key, '').strip()
if filename and _os.path.isfile(filename):
result.append(filename)
cmd = dist.get_command_obj("build_py")
cmd.ensure_finalized()
#from pprint import pprint; pprint(("build_py", cmd.get_source_files()))
for item in cmd.get_source_files():
result.append(_posixpath.sep.join(
_os.path.normpath(item).split(_os.path.sep)
))
cmd = dist.get_command_obj("build_ext")
cmd.ensure_finalized()
#from pprint import pprint; pprint(("build_ext", cmd.get_source_files()))
for item in cmd.get_source_files():
result.append(_posixpath.sep.join(
_os.path.normpath(item).split(_os.path.sep)
))
for ext in cmd.extensions:
if ext.depends:
result.extend([_posixpath.sep.join(
_os.path.normpath(item).split(_os.path.sep)
) for item in ext.depends])
cmd = dist.get_command_obj("build_clib")
cmd.ensure_finalized()
if cmd.libraries:
#import pprint; pprint.pprint(("build_clib", cmd.get_source_files()))
for item in cmd.get_source_files():
result.append(_posixpath.sep.join(
_os.path.normpath(item).split(_os.path.sep)
))
for lib in cmd.libraries:
if lib[1].get('depends'):
result.extend([_posixpath.sep.join(
_os.path.normpath(item).split(_os.path.sep)
) for item in lib[1]['depends']])
cmd = dist.get_command_obj("build_scripts")
cmd.ensure_finalized()
#import pprint; pprint.pprint(("build_scripts", cmd.get_source_files()))
if cmd.get_source_files():
for item in cmd.get_source_files():
result.append(_posixpath.sep.join(
_os.path.normpath(item).split(_os.path.sep)
))
cmd = dist.get_command_obj("install_data")
cmd.ensure_finalized()
#from pprint import pprint; pprint(("install_data", cmd.get_inputs()))
try:
strings = str
except NameError:
strings = (str, str)
for item in cmd.get_inputs():
if isinstance(item, strings):
result.append(item)
else:
result.extend(item[1])
for item in manifest.get('dist', '').split():
result.append(item)
if _os.path.isdir(item):
for filename in _shell.files(item):
result.append(filename)
result = list(dict([(item, None) for item in result]).keys())
result.sort()
return result
def run(config=('package.cfg',), ext=None, script_args=None, manifest_only=0):
""" Main runner """
if ext is None:
ext = []
cfg = _util.SafeConfigParser()
cfg.read(config)
pkg = dict(cfg.items('package'))
python_min = pkg.get('python.min') or None
python_max = pkg.get('python.max') or None
check_python_version('python', python_min, python_max)
pypy_min = pkg.get('pypy.min') or None
pypy_max = pkg.get('pypy.max') or None
check_python_version('pypy', pypy_min, pypy_max)
jython_min = pkg.get('jython.min') or None
jython_max = pkg.get('jython.max') or None
check_python_version('jython', jython_min, jython_max)
manifest = dict(cfg.items('manifest'))
try:
docs = dict(cfg.items('docs'))
except _config_parser.NoSectionError:
docs = {}
summary, description = find_description(docs)
scripts = manifest.get('scripts', '').strip() or None
if scripts:
scripts = scripts.split()
modules = manifest.get('modules', '').strip() or None
if modules:
modules = modules.split()
keywords = docs.get('meta.keywords', '').strip() or None
if keywords:
keywords = keywords.split()
revision = pkg.get('version.revision', '').strip()
if revision:
revision = "-r%s" % (revision,)
kwargs = {
'name': pkg['name'],
'version': "%s%s" % (
pkg['version.number'],
["", "-dev%s" % (revision,)][_util.humanbool(
'version.dev', pkg.get('version.dev', 'false')
)],
),
'provides': find_provides(docs),
'description': summary,
'long_description': description,
'classifiers': find_classifiers(docs),
'keywords': keywords,
'author': pkg['author.name'],
'author_email': pkg['author.email'],
'maintainer': pkg.get('maintainer.name'),
'maintainer_email': pkg.get('maintainer.email'),
'url': pkg.get('url.homepage'),
'download_url': pkg.get('url.download'),
'license': find_license(docs),
'package_dir': {'': manifest.get('packages.lib', '.')},
'packages': find_packages(manifest),
'py_modules': modules,
'ext_modules': ext,
'scripts': scripts,
'script_args': script_args,
'data_files': find_data(pkg['name'], docs),
'cmdclass': {
'build' : _commands.Build,
'build_ext' : _commands.BuildExt,
'install' : _commands.Install,
'install_data': _commands.InstallData,
'install_lib' : _commands.InstallLib,
}
}
for key in ('provides',):
if key not in _core.setup_keywords:
del kwargs[key]
if manifest_only:
return make_manifest(manifest, config, docs, kwargs)
# monkey-patch crappy manifest writer away.
from distutils.command import sdist
sdist.sdist.get_file_list = sdist.sdist.read_manifest
return _core.setup(**kwargs)

351
_setup/py3/shell.py Normal file
View File

@ -0,0 +1,351 @@
# -*- coding: ascii -*-
#
# Copyright 2007 - 2013
# Andr\xe9 Malo or his licensors, as applicable
#
# Licensed 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.
"""
=================
Shell utilities
=================
Shell utilities.
"""
__author__ = "Andr\xe9 Malo"
__docformat__ = "restructuredtext en"
import errno as _errno
import fnmatch as _fnmatch
import os as _os
import shutil as _shutil
import subprocess as _subprocess
import sys as _sys
import tempfile as _tempfile
cwd = _os.path.dirname(_os.path.abspath(_sys.argv[0]))
class ExitError(RuntimeError):
""" Exit error """
def __init__(self, code):
RuntimeError.__init__(self, code)
self.code = code
self.signal = None
class SignalError(ExitError):
""" Signal error """
def __init__(self, code, signal):
ExitError.__init__(self, code)
import signal as _signal
self.signal = signal
for key, val in vars(_signal).items():
if key.startswith('SIG') and not key.startswith('SIG_'):
if val == signal:
self.signalstr = key[3:]
break
else:
self.signalstr = '%04d' % signal
def native(path):
""" Convert slash path to native """
path = _os.path.sep.join(path.split('/'))
return _os.path.normpath(_os.path.join(cwd, path))
def cp(src, dest):
""" Copy src to dest """
_shutil.copy2(native(src), native(dest))
def cp_r(src, dest):
""" Copy -r src to dest """
_shutil.copytree(native(src), native(dest))
def rm(dest):
""" Remove a file """
try:
_os.unlink(native(dest))
except OSError as e:
if _errno.ENOENT != e.errno:
raise
def rm_rf(dest):
""" Remove a tree """
dest = native(dest)
if _os.path.exists(dest):
for path in files(dest, '*'):
_os.chmod(native(path), 0o644)
_shutil.rmtree(dest)
mkstemp = _tempfile.mkstemp
def _pipespawn(argv, env):
""" Pipe spawn """
# pylint: disable = R0912
import pickle as _pickle
fd, name = mkstemp('.py')
try:
_os.write(fd, ((r"""
import os
import pickle
import subprocess
import sys
argv = pickle.loads(%(argv)s)
env = pickle.loads(%(env)s)
if 'X_JYTHON_WA_PATH' in env:
env['PATH'] = env['X_JYTHON_WA_PATH']
p = subprocess.Popen(argv, env=env)
result = p.wait()
if result < 0:
print("\n%%d 1" %% (-result))
sys.exit(2)
if result == 0:
sys.exit(0)
print("\n%%d" %% (result & 7,))
sys.exit(3)
""".strip() + "\n") % {
'argv': repr(_pickle.dumps(argv)),
'env': repr(_pickle.dumps(dict(env))),
}).encode('utf-8'))
fd, _ = None, _os.close(fd)
if _sys.platform == 'win32':
argv = []
for arg in [_sys.executable, name]:
if ' ' in arg or arg.startswith('"'):
arg = '"%s"' % arg.replace('"', '\\"')
argv.append(arg)
argv = ' '.join(argv)
shell = True
close_fds = False
else:
argv = [_sys.executable, name]
shell = False
close_fds = True
res = 0
if 'X_JYTHON_WA_PATH' in env:
env['PATH'] = env['X_JYTHON_WA_PATH']
proc = _subprocess.Popen(argv,
shell=shell,
stdin=_subprocess.PIPE,
stdout=_subprocess.PIPE,
close_fds=close_fds,
env=env,
)
try:
proc.stdin.close()
result = proc.stdout.read()
finally:
res = proc.wait()
if res != 0:
if res == 2:
signal, code = list(map(int, result.splitlines()[-1].split()))
raise SignalError(code, signal)
elif res == 3:
code = int(result.splitlines()[-1].strip())
raise ExitError(code)
raise ExitError(res)
return result.decode('latin-1')
finally:
try:
if fd is not None:
_os.close(fd)
finally:
_os.unlink(name)
def _filepipespawn(infile, outfile, argv, env):
""" File Pipe spawn """
import pickle as _pickle
fd, name = mkstemp('.py')
try:
_os.write(fd, (("""
import os
import pickle
import sys
infile = pickle.loads(%(infile)s)
outfile = pickle.loads(%(outfile)s)
argv = pickle.loads(%(argv)s)
env = pickle.loads(%(env)s)
if infile is not None:
infile = open(infile, 'rb')
os.dup2(infile.fileno(), 0)
infile.close()
if outfile is not None:
outfile = open(outfile, 'wb')
os.dup2(outfile.fileno(), 1)
outfile.close()
pid = os.spawnve(os.P_NOWAIT, argv[0], argv, env)
result = os.waitpid(pid, 0)[1]
sys.exit(result & 7)
""".strip() + "\n") % {
'infile': repr(_pickle.dumps(_os.path.abspath(infile))),
'outfile': repr(_pickle.dumps(_os.path.abspath(outfile))),
'argv': repr(_pickle.dumps(argv)),
'env': repr(_pickle.dumps(env)),
}))
fd, _ = None, _os.close(fd)
if _sys.platform == 'win32':
argv = []
for arg in [_sys.executable, name]:
if ' ' in arg or arg.startswith('"'):
arg = '"%s"' % arg.replace('"', '\\"')
argv.append(arg)
argv = ' '.join(argv)
close_fds = False
shell = True
else:
argv = [_sys.executable, name]
close_fds = True
shell = False
p = _subprocess.Popen(
argv, env=env, shell=shell, close_fds=close_fds
)
return p.wait()
finally:
try:
if fd is not None:
_os.close(fd)
finally:
_os.unlink(name)
def spawn(*argv, **kwargs):
""" Spawn a process """
if _sys.platform == 'win32':
newargv = []
for arg in argv:
if not arg or ' ' in arg or arg.startswith('"'):
arg = '"%s"' % arg.replace('"', '\\"')
newargv.append(arg)
argv = newargv
close_fds = False
shell = True
else:
close_fds = True
shell = False
env = kwargs.get('env')
if env is None:
env = dict(_os.environ)
if 'X_JYTHON_WA_PATH' in env:
env['PATH'] = env['X_JYTHON_WA_PATH']
echo = kwargs.get('echo')
if echo:
print(' '.join(argv))
filepipe = kwargs.get('filepipe')
if filepipe:
return _filepipespawn(
kwargs.get('stdin'), kwargs.get('stdout'), argv, env
)
pipe = kwargs.get('stdout')
if pipe:
return _pipespawn(argv, env)
p = _subprocess.Popen(argv, env=env, shell=shell, close_fds=close_fds)
return p.wait()
walk = _os.walk
def files(base, wildcard='[!.]*', recursive=1, prune=('.svn', 'CVS')):
""" Determine a filelist """
for dirpath, dirnames, filenames in walk(native(base)):
for item in prune:
if item in dirnames:
dirnames.remove(item)
filenames.sort()
for name in _fnmatch.filter(filenames, wildcard):
dest = _os.path.join(dirpath, name)
if dest.startswith(cwd):
dest = dest.replace(cwd, '', 1)
aslist = []
head, tail = _os.path.split(dest)
while tail:
aslist.append(tail)
head, tail = _os.path.split(head)
aslist.reverse()
dest = '/'.join(aslist)
yield dest
if not recursive:
break
dirnames.sort()
def dirs(base, wildcard='[!.]*', recursive=1, prune=('.svn', 'CVS')):
""" Determine a filelist """
for dirpath, dirnames, filenames in walk(native(base)):
for item in prune:
if item in dirnames:
dirnames.remove(item)
dirnames.sort()
for name in _fnmatch.filter(dirnames, wildcard):
dest = _os.path.join(dirpath, name)
if dest.startswith(cwd):
dest = dest.replace(cwd, '', 1)
aslist = []
head, tail = _os.path.split(dest)
while tail:
aslist.append(tail)
head, tail = _os.path.split(head)
aslist.reverse()
dest = '/'.join(aslist)
yield dest
if not recursive:
break
def frompath(executable):
""" Find executable in PATH """
# Based on distutils.spawn.find_executable.
path = _os.environ.get('PATH', '')
paths = [
_os.path.expanduser(item)
for item in path.split(_os.pathsep)
]
ext = _os.path.splitext(executable)[1]
exts = ['']
if _sys.platform == 'win32' or _os.name == 'os2':
eext = ['.exe', '.bat', '.py']
if ext not in eext:
exts.extend(eext)
for ext in exts:
if not _os.path.isfile(executable + ext):
for path in paths:
fname = _os.path.join(path, executable + ext)
if _os.path.isfile(fname):
# the file exists, we have a shot at spawn working
return fname
else:
return executable + ext
return None

View File

@ -0,0 +1,28 @@
# -*- coding: ascii -*-
#
# Copyright 2010, 2011
# Andr\xe9 Malo or his licensors, as applicable
#
# Licensed 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.
"""
=====================
Package _setup.term
=====================
Terminal tools, not distributed.
"""
__author__ = "Andr\xe9 Malo"
__docformat__ = "restructuredtext en"
# pylint: disable = W0611
from _setup.term._term import terminfo, write, green, red, yellow, announce

116
_setup/py3/term/_term.py Normal file
View File

@ -0,0 +1,116 @@
# -*- coding: ascii -*-
#
# Copyright 2007, 2008, 2009, 2010, 2011
# Andr\xe9 Malo or his licensors, as applicable
#
# Licensed 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.
"""
=================
Terminal writer
=================
"""
__author__ = "Andr\xe9 Malo"
__docformat__ = "restructuredtext en"
import sys as _sys
class _INFO(dict):
""" Terminal info dict """
def __init__(self):
""" Initialization """
dict.__init__(self, {
'NORMAL': '',
'BOLD': '',
'ERASE': '\n',
'RED': '',
'YELLOW': '',
'GREEN': '',
})
try:
import curses as _curses
except ImportError:
# fixup if a submodule of curses failed.
if 'curses' in _sys.modules:
del _sys.modules['curses']
else:
try:
_curses.setupterm()
except (TypeError, _curses.error):
pass
else:
def make_color(color):
""" Make color control string """
seq = _curses.tigetstr('setaf').decode('ascii')
if seq is not None:
# XXX may fail - need better logic
seq = seq.replace("%p1", "") % color
return seq
self['NORMAL'] = _curses.tigetstr('sgr0').decode('ascii')
self['BOLD'] = _curses.tigetstr('bold').decode('ascii')
erase = _curses.tigetstr('el1').decode('ascii')
if erase is not None:
self['ERASE'] = erase + \
_curses.tigetstr('cr').decode('ascii')
self['RED'] = make_color(_curses.COLOR_RED)
self['YELLOW'] = make_color(_curses.COLOR_YELLOW)
self['GREEN'] = make_color(_curses.COLOR_GREEN)
def __getitem__(self, key):
""" Deliver always """
dict.get(self, key) or ""
def terminfo():
""" Get info singleton """
# pylint: disable = E1101, W0612
if terminfo.info is None:
terminfo.info = _INFO()
return terminfo.info
terminfo.info = None
def write(fmt, **kwargs):
""" Write stuff on the terminal """
parm = dict(terminfo())
parm.update(kwargs)
_sys.stdout.write(fmt % parm)
_sys.stdout.flush()
def green(bmt, **kwargs):
""" Write something in green on screen """
announce("%%(GREEN)s%s%%(NORMAL)s" % bmt, **kwargs)
def red(bmt, **kwargs):
""" Write something in red on the screen """
announce("%%(BOLD)s%%(RED)s%s%%(NORMAL)s" % bmt, **kwargs)
def yellow(fmt, **kwargs):
""" Write something in yellow on the screen """
announce("%%(BOLD)s%%(YELLOW)s%s%%(NORMAL)s" % fmt, **kwargs)
def announce(fmt, **kwargs):
""" Announce something """
write(fmt, **kwargs)
_sys.stdout.write("\n")
_sys.stdout.flush()

63
_setup/py3/util.py Normal file
View File

@ -0,0 +1,63 @@
# -*- coding: ascii -*-
#
# Copyright 2007, 2008, 2009, 2010, 2011
# Andr\xe9 Malo or his licensors, as applicable
#
# Licensed 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.
"""
=================
Setup utilities
=================
Setup utilities.
"""
__author__ = "Andr\xe9 Malo"
__docformat__ = "restructuredtext en"
from distutils import util as _util
try:
from configparser import SafeConfigParser
except ImportError:
import configparser as _config_parser
class SafeConfigParser(_config_parser.ConfigParser):
""" Safe config parser """
def _interpolate(self, section, option, rawval, vars):
return rawval
def items(self, section):
return [(key, self.get(section, key))
for key in self.options(section)
]
def humanbool(name, value):
"""
Determine human boolean value
:Parameters:
`name` : ``str``
The config key (used for error message)
`value` : ``str``
The config value
:Return: The boolean value
:Rtype: ``bool``
:Exceptions:
- `ValueError` : The value could not be recognized
"""
try:
return _util.strtobool(str(value).strip().lower() or 'no')
except ValueError:
raise ValueError("Unrecognized config value: %s = %s" % (name, value))

172
bench.py Executable file
View File

@ -0,0 +1,172 @@
#!/usr/bin/env python
# -*- coding: ascii -*-
#
# Copyright 2011, 2012
# Andr\xe9 Malo or his licensors, as applicable
#
# Licensed 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.
"""
=================================
Benchmark jsmin implementations
=================================
Benchmark jsmin implementations.
Usage::
bench.py [-c COUNT] jsfile ...
-c COUNT number of runs per jsfile and minifier. Defaults to 10.
"""
__author__ = "Andr\xe9 Malo"
__author__ = getattr(__author__, 'decode', lambda x: __author__)('latin-1')
__docformat__ = "restructuredtext en"
__license__ = "Apache License, Version 2.0"
__version__ = "1.0.0"
import sys as _sys
import time as _time
class jsmins(object):
from bench import jsmin as p_01_simple_port
if _sys.version_info >= (2, 4):
from bench import jsmin_2_0_2 as p_02_jsmin_2_0_2
else:
print("jsmin_2_0_2 available for python 2.4 and later...")
if _sys.version_info < (3, 0):
try:
import slimit as _slimit_0_7
except ImportError:
print("slimit_0_7 not installed for python %d.%d..." %
_sys.version_info[:2]
)
else:
class p_03_slimit_0_7(object):
pass
p_03_slimit_0_7 = p_03_slimit_0_7()
p_03_slimit_0_7.jsmin = _slimit_0_7.minify
class p_04_slimit_0_7_mangle(object):
pass
p_04_slimit_0_7_mangle = p_04_slimit_0_7_mangle()
p_04_slimit_0_7_mangle.jsmin = \
lambda x, s=_slimit_0_7: s.minify(x, True)
else:
print("slimit_0_7 not available for python 3...")
import rjsmin as p_05_rjsmin
try:
import _rjsmin as p_06__rjsmin
except ImportError:
print("_rjsmin (C-Port) not available")
jsmins.p_05_rjsmin.jsmin = jsmins.p_05_rjsmin._make_jsmin(
python_only=True
)
print("Python Release: %s" % ".".join(map(str, _sys.version_info[:3])))
print("")
def slurp(filename):
""" Load a file """
fp = open(filename)
try:
return fp.read()
finally:
fp.close()
def print_(*value, **kwargs):
""" Print stuff """
(kwargs.get('file') or _sys.stdout).write(
''.join(value) + kwargs.get('end', '\n')
)
def bench(filenames, count):
"""
Benchmark the minifiers with given javascript samples
:Parameters:
`filenames` : sequence
List of filenames
`count` : ``int``
Number of runs per js file and minifier
:Exceptions:
- `RuntimeError` : empty filenames sequence
"""
if not filenames:
raise RuntimeError("Missing files to benchmark")
try:
xrange
except NameError:
xrange = range
try:
cmp
except NameError:
cmp = lambda a, b: (a > b) - (a < b)
ports = [item for item in dir(jsmins) if item.startswith('p_')]
ports.sort()
space = max(map(len, ports)) - 4
ports = [(item[5:], getattr(jsmins, item).jsmin) for item in ports]
counted = [None for _ in xrange(count)]
flush = _sys.stdout.flush
inputs = [(filename, slurp(filename)) for filename in filenames]
for filename, script in inputs:
print_("Benchmarking %r..." % filename, end=" ")
flush()
outputs = [jsmin(script) for _, jsmin in ports]
print_("(%.1f KiB)" % (len(script) / 1024.0))
flush()
times = []
for idx, (name, jsmin) in enumerate(ports):
print_(" Timing %s%s... (%5.1f KiB %s)" % (
name,
" " * (space - len(name)),
len(outputs[idx]) / 1024.0,
idx == 0 and '*' or
['=', '>', '<'][cmp(len(outputs[idx]), len(outputs[0]))],
), end=" ")
flush()
start = _time.time()
for _ in counted:
jsmin(script)
end = _time.time()
times.append((end - start) * 1000 / count)
print_("%8.2f ms" % times[-1], end=" ")
flush()
if len(times) <= 1:
print_()
else:
print_("(factor: %s)" % (', '.join([
'%.2f' % (timed / times[-1]) for timed in times[:-1]
])))
flush()
print_()
def main(argv):
""" Main """
count, idx = 10, 0
if argv and argv[0] == '-c':
count, idx = int(argv[1]), 2
elif argv and argv[0].startswith('-c'):
count, idx = int(argv[0][2:]), 1
bench(argv[idx:], count)
if __name__ == '__main__':
main(_sys.argv[1:])

0
bench/__init__.py Normal file
View File

178
bench/apiviewer.js Normal file

File diff suppressed because one or more lines are too long

1829
bench/bootstrap.js vendored Normal file

File diff suppressed because it is too large Load Diff

9266
bench/jquery-1.7.1.js vendored Normal file

File diff suppressed because it is too large Load Diff

291
bench/jsmin.c Normal file
View File

@ -0,0 +1,291 @@
/* jsmin.c
2011-01-22
Copyright (c) 2002 Douglas Crockford (www.crockford.com)
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
The Software shall be used for Good, not Evil.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#include <stdlib.h>
#include <stdio.h>
static int theA;
static int theB;
static int theLookahead = EOF;
/* isAlphanum -- return true if the character is a letter, digit, underscore,
dollar sign, or non-ASCII character.
*/
static int
isAlphanum(int c)
{
return ((c >= 'a' && c <= 'z') || (c >= '0' && c <= '9') ||
(c >= 'A' && c <= 'Z') || c == '_' || c == '$' || c == '\\' ||
c > 126);
}
/* get -- return the next character from stdin. Watch out for lookahead. If
the character is a control character, translate it to a space or
linefeed.
*/
static int
get()
{
int c = theLookahead;
theLookahead = EOF;
if (c == EOF) {
c = getc(stdin);
}
if (c >= ' ' || c == '\n' || c == EOF) {
return c;
}
if (c == '\r') {
return '\n';
}
return ' ';
}
/* peek -- get the next character without getting it.
*/
static int
peek()
{
theLookahead = get();
return theLookahead;
}
/* next -- get the next character, excluding comments. peek() is used to see
if a '/' is followed by a '/' or '*'.
*/
static int
next()
{
int c = get();
if (c == '/') {
switch (peek()) {
case '/':
for (;;) {
c = get();
if (c <= '\n') {
return c;
}
}
case '*':
get();
for (;;) {
switch (get()) {
case '*':
if (peek() == '/') {
get();
return ' ';
}
break;
case EOF:
fprintf(stderr, "Error: JSMIN Unterminated comment.\n");
exit(1);
}
}
default:
return c;
}
}
return c;
}
/* action -- do something! What you do is determined by the argument:
1 Output A. Copy B to A. Get the next B.
2 Copy B to A. Get the next B. (Delete A).
3 Get the next B. (Delete B).
action treats a string as a single character. Wow!
action recognizes a regular expression if it is preceded by ( or , or =.
*/
static void
action(int d)
{
switch (d) {
case 1:
putc(theA, stdout);
case 2:
theA = theB;
if (theA == '\'' || theA == '"') {
for (;;) {
putc(theA, stdout);
theA = get();
if (theA == theB) {
break;
}
if (theA == '\\') {
putc(theA, stdout);
theA = get();
}
if (theA == EOF) {
fprintf(stderr, "Error: JSMIN unterminated string literal.");
exit(1);
}
}
}
case 3:
theB = next();
if (theB == '/' && (theA == '(' || theA == ',' || theA == '=' ||
theA == ':' || theA == '[' || theA == '!' ||
theA == '&' || theA == '|' || theA == '?' ||
theA == '{' || theA == '}' || theA == ';' ||
theA == '\n')) {
putc(theA, stdout);
putc(theB, stdout);
for (;;) {
theA = get();
if (theA == '[') {
for (;;) {
putc(theA, stdout);
theA = get();
if (theA == ']') {
break;
}
if (theA == '\\') {
putc(theA, stdout);
theA = get();
}
if (theA == EOF) {
fprintf(stderr,
"Error: JSMIN unterminated set in Regular Expression literal.\n");
exit(1);
}
}
} else if (theA == '/') {
break;
} else if (theA =='\\') {
putc(theA, stdout);
theA = get();
}
if (theA == EOF) {
fprintf(stderr,
"Error: JSMIN unterminated Regular Expression literal.\n");
exit(1);
}
putc(theA, stdout);
}
theB = next();
}
}
}
/* jsmin -- Copy the input to the output, deleting the characters which are
insignificant to JavaScript. Comments will be removed. Tabs will be
replaced with spaces. Carriage returns will be replaced with linefeeds.
Most spaces and linefeeds will be removed.
*/
static void
jsmin()
{
theA = '\n';
action(3);
while (theA != EOF) {
switch (theA) {
case ' ':
if (isAlphanum(theB)) {
action(1);
} else {
action(2);
}
break;
case '\n':
switch (theB) {
case '{':
case '[':
case '(':
case '+':
case '-':
action(1);
break;
case ' ':
action(3);
break;
default:
if (isAlphanum(theB)) {
action(1);
} else {
action(2);
}
}
break;
default:
switch (theB) {
case ' ':
if (isAlphanum(theA)) {
action(1);
break;
}
action(3);
break;
case '\n':
switch (theA) {
case '}':
case ']':
case ')':
case '+':
case '-':
case '"':
case '\'':
action(1);
break;
default:
if (isAlphanum(theA)) {
action(1);
} else {
action(3);
}
}
break;
default:
action(1);
break;
}
}
}
}
/* main -- Output any command line arguments as comments
and then minify the input.
*/
extern int
main(int argc, char* argv[])
{
int i;
for (i = 1; i < argc; i += 1) {
fprintf(stdout, "// %s\n", argv[i]);
}
jsmin();
return 0;
}

226
bench/jsmin.py Executable file
View File

@ -0,0 +1,226 @@
#!/usr/bin/env python
# This code is original from jsmin by Douglas Crockford, it was translated to
# Python by Baruch Even. The original code had the following copyright and
# license.
#
# /* jsmin.c
# 2007-05-22
#
# Copyright (c) 2002 Douglas Crockford (www.crockford.com)
#
# Permission is hereby granted, free of charge, to any person obtaining a copy of
# this software and associated documentation files (the "Software"), to deal in
# the Software without restriction, including without limitation the rights to
# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
# of the Software, and to permit persons to whom the Software is furnished to do
# so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#
# The Software shall be used for Good, not Evil.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
# */
# imports adjusted for speed (cStringIO) and python 3 (io) -- nd
try:
from cStringIO import StringIO
except ImportError:
try:
from StringIO import StringIO
except ImportError:
from io import StringIO
def jsmin(js):
ins = StringIO(js)
outs = StringIO()
JavascriptMinify().minify(ins, outs)
str = outs.getvalue()
if len(str) > 0 and str[0] == '\n':
str = str[1:]
return str
def isAlphanum(c):
"""return true if the character is a letter, digit, underscore,
dollar sign, or non-ASCII character.
"""
return ((c >= 'a' and c <= 'z') or (c >= '0' and c <= '9') or
(c >= 'A' and c <= 'Z') or c == '_' or c == '$' or c == '\\' or (c is not None and ord(c) > 126));
class UnterminatedComment(Exception):
pass
class UnterminatedStringLiteral(Exception):
pass
class UnterminatedRegularExpression(Exception):
pass
class JavascriptMinify(object):
def _outA(self):
self.outstream.write(self.theA)
def _outB(self):
self.outstream.write(self.theB)
def _get(self):
"""return the next character from stdin. Watch out for lookahead. If
the character is a control character, translate it to a space or
linefeed.
"""
c = self.theLookahead
self.theLookahead = None
if c == None:
c = self.instream.read(1)
if c >= ' ' or c == '\n':
return c
if c == '': # EOF
return '\000'
if c == '\r':
return '\n'
return ' '
def _peek(self):
self.theLookahead = self._get()
return self.theLookahead
def _next(self):
"""get the next character, excluding comments. peek() is used to see
if an unescaped '/' is followed by a '/' or '*'.
"""
c = self._get()
if c == '/' and self.theA != '\\':
p = self._peek()
if p == '/':
c = self._get()
while c > '\n':
c = self._get()
return c
if p == '*':
c = self._get()
while 1:
c = self._get()
if c == '*':
if self._peek() == '/':
self._get()
return ' '
if c == '\000':
raise UnterminatedComment()
return c
def _action(self, action):
"""do something! What you do is determined by the argument:
1 Output A. Copy B to A. Get the next B.
2 Copy B to A. Get the next B. (Delete A).
3 Get the next B. (Delete B).
action treats a string as a single character. Wow!
action recognizes a regular expression if it is preceded by ( or , or =.
"""
if action <= 1:
self._outA()
if action <= 2:
self.theA = self.theB
if self.theA == "'" or self.theA == '"':
while 1:
self._outA()
self.theA = self._get()
if self.theA == self.theB:
break
if self.theA <= '\n':
raise UnterminatedStringLiteral()
if self.theA == '\\':
self._outA()
self.theA = self._get()
if action <= 3:
self.theB = self._next()
if self.theB == '/' and (self.theA == '(' or self.theA == ',' or
self.theA == '=' or self.theA == ':' or
self.theA == '[' or self.theA == '?' or
self.theA == '!' or self.theA == '&' or
self.theA == '|' or self.theA == ';' or
self.theA == '{' or self.theA == '}' or
self.theA == '\n'):
self._outA()
self._outB()
while 1:
self.theA = self._get()
if self.theA == '/':
break
elif self.theA == '\\':
self._outA()
self.theA = self._get()
elif self.theA <= '\n':
raise UnterminatedRegularExpression()
self._outA()
self.theB = self._next()
def _jsmin(self):
"""Copy the input to the output, deleting the characters which are
insignificant to JavaScript. Comments will be removed. Tabs will be
replaced with spaces. Carriage returns will be replaced with linefeeds.
Most spaces and linefeeds will be removed.
"""
self.theA = '\n'
self._action(3)
while self.theA != '\000':
if self.theA == ' ':
if isAlphanum(self.theB):
self._action(1)
else:
self._action(2)
elif self.theA == '\n':
if self.theB in ['{', '[', '(', '+', '-']:
self._action(1)
elif self.theB == ' ':
self._action(3)
else:
if isAlphanum(self.theB):
self._action(1)
else:
self._action(2)
else:
if self.theB == ' ':
if isAlphanum(self.theA):
self._action(1)
else:
self._action(3)
elif self.theB == '\n':
if self.theA in ['}', ']', ')', '+', '-', '"', '\'']:
self._action(1)
else:
if isAlphanum(self.theA):
self._action(1)
else:
self._action(3)
else:
self._action(1)
def minify(self, instream, outstream):
self.instream = instream
self.outstream = outstream
self.theA = '\n'
self.theB = None
self.theLookahead = None
self._jsmin()
self.instream.close()
if __name__ == '__main__':
import sys
jsm = JavascriptMinify()
jsm.minify(sys.stdin, sys.stdout)

202
bench/jsmin_2_0_2.py Executable file
View File

@ -0,0 +1,202 @@
#!/usr/bin/env python
# This code is original from jsmin by Douglas Crockford, it was translated to
# Python by Baruch Even. It was refactored by Dave St.Germain for speed.
# The original code had the following copyright and license.
#
# /* jsmin.c
# 2007-01-08
#
# Copyright (c) 2002 Douglas Crockford (www.crockford.com)
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# The Software shall be used for Good, not Evil.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
# */
import sys
is_3 = sys.version_info >= (3, 0)
if is_3:
import io
else:
import StringIO
try:
import cStringIO
except ImportError:
cStringIO = None
__all__ = ['jsmin', 'JavascriptMinify']
__version__ = '2.0.2'
def jsmin(js):
"""
returns a minified version of the javascript string
"""
if not is_3:
if cStringIO and not isinstance(js, unicode):
# strings can use cStringIO for a 3x performance
# improvement, but unicode (in python2) cannot
klass = cStringIO.StringIO
else:
klass = StringIO.StringIO
else:
klass = io.StringIO
ins = klass(js)
outs = klass()
JavascriptMinify(ins, outs).minify()
return outs.getvalue()
class JavascriptMinify(object):
"""
Minify an input stream of javascript, writing
to an output stream
"""
def __init__(self, instream=None, outstream=None):
self.ins = instream
self.outs = outstream
def minify(self, instream=None, outstream=None):
if instream and outstream:
self.ins, self.outs = instream, outstream
write = self.outs.write
read = self.ins.read
space_strings = "abcdefghijklmnopqrstuvwxyz"\
"ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_$\\"
starters, enders = '{[(+-', '}])+-"\''
newlinestart_strings = starters + space_strings
newlineend_strings = enders + space_strings
do_newline = False
do_space = False
doing_single_comment = False
previous_before_comment = ''
doing_multi_comment = False
in_re = False
in_quote = ''
quote_buf = []
previous = read(1)
next1 = read(1)
if previous == '/':
if next1 == '/':
doing_single_comment = True
elif next1 == '*':
doing_multi_comment = True
else:
write(previous)
elif not previous:
return
elif previous >= '!':
if previous in "'\"":
in_quote = previous
write(previous)
previous_non_space = previous
else:
previous_non_space = ' '
if not next1:
return
while 1:
next2 = read(1)
if not next2:
last = next1.strip()
if not (doing_single_comment or doing_multi_comment)\
and last not in ('', '/'):
write(last)
break
if doing_multi_comment:
if next1 == '*' and next2 == '/':
doing_multi_comment = False
next2 = read(1)
elif doing_single_comment:
if next1 in '\r\n':
doing_single_comment = False
while next2 in '\r\n':
next2 = read(1)
if previous_before_comment in ')}]':
do_newline = True
elif in_quote:
quote_buf.append(next1)
if next1 == in_quote:
numslashes = 0
for c in reversed(quote_buf[:-1]):
if c != '\\':
break
else:
numslashes += 1
if numslashes % 2 == 0:
in_quote = ''
write(''.join(quote_buf))
elif next1 in '\r\n':
if previous_non_space in newlineend_strings \
or previous_non_space > '~':
while 1:
if next2 < '!':
next2 = read(1)
if not next2:
break
else:
if next2 in newlinestart_strings \
or next2 > '~' or next2 == '/':
do_newline = True
break
elif next1 < '!' and not in_re:
if (previous_non_space in space_strings \
or previous_non_space > '~') \
and (next2 in space_strings or next2 > '~'):
do_space = True
elif next1 == '/':
if (previous in ';\n\r{}' or previous < '!') and next2 in '/*':
if next2 == '/':
doing_single_comment = True
previous_before_comment = previous_non_space
elif next2 == '*':
doing_multi_comment = True
else:
if not in_re:
in_re = previous_non_space in '(,=:[?!&|'
elif previous_non_space != '\\':
in_re = not in_re
write('/')
else:
if do_space:
do_space = False
write(' ')
if do_newline:
write('\n')
do_newline = False
write(next1)
if not in_re and next1 in "'\"":
in_quote = next1
quote_buf = []
previous = next1
next1 = next2
if previous >= '!':
previous_non_space = previous
if __name__ == '__main__':
import sys as _sys
_sys.stdout.write(jsmin(_sys.stdin.read()))

239
bench/jsmin_playground.py Executable file
View File

@ -0,0 +1,239 @@
#!/usr/bin/env python
# This code is original from jsmin.c by Douglas Crockford. This is a
# playground port for understanding the semantics by Andr\xe9 Malo. Here's the
# jsmin.c license:
#
# /* jsmin.c
# 2007-01-08
#
# Copyright (c) 2002 Douglas Crockford (www.crockford.com)
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# The Software shall be used for Good, not Evil.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
# */
import re as _re
try:
import cStringIO as _string_io
except ImportError:
try:
import StringIO as _string_io
except ImportError:
import io as _string_io
class JSMinError(Exception):
""" Minifier base error """
class UnterminatedComment(JSMinError):
""" Unterminated comment """
class UnterminatedRegex(JSMinError):
""" Unterminated Regex literal """
class UnterminatedString(JSMinError):
""" Unterminated String literal """
class PrintableLookAheadStream(object):
""" Stream wrapper providing get and peek methods """
def __init__(self, stream):
""" Initialization """
self._stream = stream
self._looked = None
def get(self):
""" Get one character """
char, self._looked = self._looked, None
if char is not None:
return char
char = self._stream.read(1)
if not char:
raise EOFError()
if char == '\r':
return '\n'
if ord(char) >= 32 or char == '\n':
return char
return ' '
def peek(self):
""" Peek one character ahead """
self._looked = self.get()
return self._looked
def m(regex):
""" Regex -> matcher """
return _re.compile(regex).match
def next_char(stream):
""" Next character leaving out comments """
get, peek = stream.get, stream.peek
char = get()
if char == '/':
try:
c_next = peek()
except EOFError:
return char
if c_next == '/': # // comment
while char != '\n':
char = get()
elif c_next == '*': # /* comment */
get()
try:
while not(char == '*' and peek() == '/'):
char = get()
get()
char = ' '
except EOFError:
raise UnterminatedComment()
return char
def action3(stream, out, first, second,
pre_regex_match=m(r'[(,=:\[!&|?{};\n]')):
""" throw away second, skip comments and regexps """
try:
second = next_char(stream)
except EOFError:
out.write(first)
raise
if second == '/' and pre_regex_match(first):
# Regex found. Parse it till the end.
write, get = out.write, stream.get
write(first)
write(second)
try:
first = get()
while first != '/':
if first == '\\':
write(first)
first = get()
elif first == '[':
write(first)
first = get()
while first != ']':
if first == '\\':
write(first)
first = get()
write(first)
first = get()
write(first)
first = get()
second = next_char(stream)
except EOFError:
raise UnterminatedRegex()
return first, second
def action2(stream, out, first, second):
""" shift, skip strings, comments and regexps """
first = second
if first in (r''''"'''):
quote = first
write, get = out.write, stream.get
write(first)
try:
first = get()
while first != quote:
if first == '\\':
write(first)
first = get()
write(first)
first = get()
except EOFError:
raise UnterminatedString()
return action3(stream, out, first, second)
def action1(stream, out, first, second):
""" write, shift, skip strings, comments and regexps """
out.write(first)
return action2(stream, out, first, second)
def jsmin_stream(stream, out,
id_literal=m(r'[a-zA-Z0-9_$\\\177-\377]'),
open_match=m(r'[{\[(+-]'),
close_match=m(r'[}\])+"\047-]')):
"""
JSMin after jsmin.c by Douglas Crockford
http://www.crockford.com/javascript/jsmin.c
"""
# pylint: disable = R0912
stream = PrintableLookAheadStream(stream)
try:
first, second = action3(stream, out, '\n', None)
while 1:
if first == ' ':
if id_literal(second):
first, second = action1(stream, out, first, second)
else:
first, second = action2(stream, out, first, second)
elif first == '\n':
if open_match(second):
first, second = action1(stream, out, first, second)
elif second == ' ':
first, second = action3(stream, out, first, second)
elif id_literal(second):
first, second = action1(stream, out, first, second)
else:
first, second = action2(stream, out, first, second)
elif second == ' ':
if id_literal(first):
first, second = action1(stream, out, first, second)
else:
first, second = action3(stream, out, first, second)
elif second == '\n':
if close_match(first):
first, second = action1(stream, out, first, second)
elif id_literal(first):
first, second = action1(stream, out, first, second)
else:
first, second = action3(stream, out, first, second)
else:
first, second = action1(stream, out, first, second)
except EOFError:
pass # done.
def jsmin(script):
"""
Minify JS
:Parameters:
`script` : ``str``
JS to minify
:Return: Minified JS
:Rtype: ``str``
"""
out = _string_io.StringIO()
jsmin_stream(_string_io.StringIO(script), out)
return out.getvalue().strip()
if __name__ == '__main__':
import sys as _sys
_sys.stdout.write(jsmin(_sys.stdin.read()))

97
bench/knockout-2.0.0.js vendored Normal file
View File

@ -0,0 +1,97 @@
// Knockout JavaScript library v2.0.0
// (c) Steven Sanderson - http://knockoutjs.com/
// License: MIT (http://www.opensource.org/licenses/mit-license.php)
(function(window,undefined){
function c(a){throw a;}var l=void 0,m=!0,o=null,p=!1,r=window.ko={};r.b=function(a,b){for(var d=a.split("."),e=window,f=0;f<d.length-1;f++)e=e[d[f]];e[d[d.length-1]]=b};r.l=function(a,b,d){a[b]=d};
r.a=new function(){function a(a,e){if("INPUT"!=a.tagName||!a.type)return p;if("click"!=e.toLowerCase())return p;var b=a.type.toLowerCase();return"checkbox"==b||"radio"==b}var b=/^(\s|\u00A0)+|(\s|\u00A0)+$/g,d={},e={};d[/Firefox\/2/i.test(navigator.userAgent)?"KeyboardEvent":"UIEvents"]=["keyup","keydown","keypress"];d.MouseEvents="click,dblclick,mousedown,mouseup,mousemove,mouseover,mouseout,mouseenter,mouseleave".split(",");for(var f in d){var h=d[f];if(h.length)for(var g=0,i=h.length;g<i;g++)e[h[g]]=
f}var j=function(){for(var a=3,e=document.createElement("div"),b=e.getElementsByTagName("i");e.innerHTML="<\!--[if gt IE "+ ++a+"]><i></i><![endif]--\>",b[0];);return 4<a?a:l}();return{Ba:["authenticity_token",/^__RequestVerificationToken(_.*)?$/],n:function(a,e){for(var b=0,f=a.length;b<f;b++)e(a[b])},k:function(a,e){if("function"==typeof Array.prototype.indexOf)return Array.prototype.indexOf.call(a,e);for(var b=0,f=a.length;b<f;b++)if(a[b]===e)return b;return-1},Wa:function(a,e,b){for(var f=0,d=
a.length;f<d;f++)if(e.call(b,a[f]))return a[f];return o},ca:function(a,e){var b=r.a.k(a,e);0<=b&&a.splice(b,1)},ya:function(a){for(var a=a||[],e=[],b=0,f=a.length;b<f;b++)0>r.a.k(e,a[b])&&e.push(a[b]);return e},ba:function(a,e){for(var a=a||[],b=[],f=0,d=a.length;f<d;f++)b.push(e(a[f]));return b},aa:function(a,e){for(var a=a||[],b=[],f=0,d=a.length;f<d;f++)e(a[f])&&b.push(a[f]);return b},J:function(a,e){for(var b=0,f=e.length;b<f;b++)a.push(e[b]);return a},extend:function(a,e){for(var b in e)e.hasOwnProperty(b)&&
(a[b]=e[b]);return a},U:function(a){for(;a.firstChild;)r.removeNode(a.firstChild)},oa:function(a,e){r.a.U(a);e&&r.a.n(e,function(e){a.appendChild(e)})},Ja:function(a,e){var b=a.nodeType?[a]:a;if(0<b.length){for(var f=b[0],d=f.parentNode,h=0,g=e.length;h<g;h++)d.insertBefore(e[h],f);h=0;for(g=b.length;h<g;h++)r.removeNode(b[h])}},La:function(a,e){0<=navigator.userAgent.indexOf("MSIE 6")?a.setAttribute("selected",e):a.selected=e},z:function(a){return(a||"").replace(b,"")},Db:function(a,e){for(var b=
[],f=(a||"").split(e),d=0,h=f.length;d<h;d++){var g=r.a.z(f[d]);""!==g&&b.push(g)}return b},Cb:function(a,e){a=a||"";return e.length>a.length?p:a.substring(0,e.length)===e},hb:function(a){for(var e=Array.prototype.slice.call(arguments,1),b="return ("+a+")",f=0;f<e.length;f++)e[f]&&"object"==typeof e[f]&&(b="with(sc["+f+"]) { "+b+" } ");return(new Function("sc",b))(e)},fb:function(a,e){if(e.compareDocumentPosition)return 16==(e.compareDocumentPosition(a)&16);for(;a!=o;){if(a==e)return m;a=a.parentNode}return p},
ga:function(a){return r.a.fb(a,document)},s:function(e,b,f){if("undefined"!=typeof jQuery){if(a(e,b))var d=f,f=function(a,e){var b=this.checked;if(e)this.checked=e.Ya!==m;d.call(this,a);this.checked=b};jQuery(e).bind(b,f)}else"function"==typeof e.addEventListener?e.addEventListener(b,f,p):"undefined"!=typeof e.attachEvent?e.attachEvent("on"+b,function(a){f.call(e,a)}):c(Error("Browser doesn't support addEventListener or attachEvent"))},sa:function(b,f){(!b||!b.nodeType)&&c(Error("element must be a DOM node when calling triggerEvent"));
if("undefined"!=typeof jQuery){var d=[];a(b,f)&&d.push({Ya:b.checked});jQuery(b).trigger(f,d)}else if("function"==typeof document.createEvent)"function"==typeof b.dispatchEvent?(d=document.createEvent(e[f]||"HTMLEvents"),d.initEvent(f,m,m,window,0,0,0,0,0,p,p,p,p,0,b),b.dispatchEvent(d)):c(Error("The supplied element doesn't support dispatchEvent"));else if("undefined"!=typeof b.fireEvent){if("click"==f&&"INPUT"==b.tagName&&("checkbox"==b.type.toLowerCase()||"radio"==b.type.toLowerCase()))b.checked=
b.checked!==m;b.fireEvent("on"+f)}else c(Error("Browser doesn't support triggering events"))},d:function(a){return r.V(a)?a():a},eb:function(a,e){return 0<=r.a.k((a.className||"").split(/\s+/),e)},Qa:function(a,e,b){var f=r.a.eb(a,e);if(b&&!f)a.className=(a.className||"")+" "+e;else if(f&&!b){for(var b=(a.className||"").split(/\s+/),f="",d=0;d<b.length;d++)b[d]!=e&&(f+=b[d]+" ");a.className=r.a.z(f)}},outerHTML:function(a){if(j===l){var e=a.outerHTML;if("string"==typeof e)return e}e=window.document.createElement("div");
e.appendChild(a.cloneNode(m));return e.innerHTML},Ma:function(a,e){var b=r.a.d(e);if(b===o||b===l)b="";"innerText"in a?a.innerText=b:a.textContent=b;if(9<=j)a.innerHTML=a.innerHTML},yb:function(a,e){for(var a=r.a.d(a),e=r.a.d(e),b=[],f=a;f<=e;f++)b.push(f);return b},X:function(a){for(var e=[],b=0,f=a.length;b<f;b++)e.push(a[b]);return e},ob:6===j,pb:7===j,Ca:function(a,e){for(var b=r.a.X(a.getElementsByTagName("INPUT")).concat(r.a.X(a.getElementsByTagName("TEXTAREA"))),f="string"==typeof e?function(a){return a.name===
e}:function(a){return e.test(a.name)},d=[],h=b.length-1;0<=h;h--)f(b[h])&&d.push(b[h]);return d},vb:function(a){return"string"==typeof a&&(a=r.a.z(a))?window.JSON&&window.JSON.parse?window.JSON.parse(a):(new Function("return "+a))():o},qa:function(a){("undefined"==typeof JSON||"undefined"==typeof JSON.stringify)&&c(Error("Cannot find JSON.stringify(). Some browsers (e.g., IE < 8) don't support it natively, but you can overcome this by adding a script reference to json2.js, downloadable from http://www.json.org/json2.js"));
return JSON.stringify(r.a.d(a))},wb:function(a,e,b){var b=b||{},f=b.params||{},d=b.includeFields||this.Ba,h=a;if("object"==typeof a&&"FORM"==a.tagName)for(var h=a.action,g=d.length-1;0<=g;g--)for(var j=r.a.Ca(a,d[g]),i=j.length-1;0<=i;i--)f[j[i].name]=j[i].value;var e=r.a.d(e),u=document.createElement("FORM");u.style.display="none";u.action=h;u.method="post";for(var y in e)a=document.createElement("INPUT"),a.name=y,a.value=r.a.qa(r.a.d(e[y])),u.appendChild(a);for(y in f)a=document.createElement("INPUT"),
a.name=y,a.value=f[y],u.appendChild(a);document.body.appendChild(u);b.submitter?b.submitter(u):u.submit();setTimeout(function(){u.parentNode.removeChild(u)},0)}}};r.b("ko.utils",r.a);
r.a.n([["arrayForEach",r.a.n],["arrayFirst",r.a.Wa],["arrayFilter",r.a.aa],["arrayGetDistinctValues",r.a.ya],["arrayIndexOf",r.a.k],["arrayMap",r.a.ba],["arrayPushAll",r.a.J],["arrayRemoveItem",r.a.ca],["extend",r.a.extend],["fieldsIncludedWithJsonPost",r.a.Ba],["getFormFields",r.a.Ca],["postJson",r.a.wb],["parseJson",r.a.vb],["registerEventHandler",r.a.s],["stringifyJson",r.a.qa],["range",r.a.yb],["toggleDomNodeCssClass",r.a.Qa],["triggerEvent",r.a.sa],["unwrapObservable",r.a.d]],function(a){r.b("ko.utils."+
a[0],a[1])});Function.prototype.bind||(Function.prototype.bind=function(a){var b=this,d=Array.prototype.slice.call(arguments),a=d.shift();return function(){return b.apply(a,d.concat(Array.prototype.slice.call(arguments)))}});
r.a.e=new function(){var a=0,b="__ko__"+(new Date).getTime(),d={};return{get:function(a,b){var d=r.a.e.getAll(a,p);return d===l?l:d[b]},set:function(a,b,d){d===l&&r.a.e.getAll(a,p)===l||(r.a.e.getAll(a,m)[b]=d)},getAll:function(e,f){var h=e[b];if(!(h&&"null"!==h)){if(!f)return;h=e[b]="ko"+a++;d[h]={}}return d[h]},clear:function(a){var f=a[b];f&&(delete d[f],a[b]=o)}}};r.b("ko.utils.domData",r.a.e);r.b("ko.utils.domData.clear",r.a.e.clear);
r.a.A=new function(){function a(a,b){var h=r.a.e.get(a,d);h===l&&b&&(h=[],r.a.e.set(a,d,h));return h}function b(e){var b=a(e,p);if(b)for(var b=b.slice(0),d=0;d<b.length;d++)b[d](e);r.a.e.clear(e);"function"==typeof jQuery&&"function"==typeof jQuery.cleanData&&jQuery.cleanData([e])}var d="__ko_domNodeDisposal__"+(new Date).getTime();return{va:function(e,b){"function"!=typeof b&&c(Error("Callback must be a function"));a(e,m).push(b)},Ia:function(e,b){var h=a(e,p);h&&(r.a.ca(h,b),0==h.length&&r.a.e.set(e,
d,l))},F:function(a){if(!(1!=a.nodeType&&9!=a.nodeType)){b(a);var f=[];r.a.J(f,a.getElementsByTagName("*"));for(var a=0,d=f.length;a<d;a++)b(f[a])}},removeNode:function(a){r.F(a);a.parentNode&&a.parentNode.removeChild(a)}}};r.F=r.a.A.F;r.removeNode=r.a.A.removeNode;r.b("ko.cleanNode",r.F);r.b("ko.removeNode",r.removeNode);r.b("ko.utils.domNodeDisposal",r.a.A);r.b("ko.utils.domNodeDisposal.addDisposeCallback",r.a.A.va);r.b("ko.utils.domNodeDisposal.removeDisposeCallback",r.a.A.Ia);
r.a.ma=function(a){var b;if("undefined"!=typeof jQuery){if((b=jQuery.clean([a]))&&b[0]){for(a=b[0];a.parentNode&&11!==a.parentNode.nodeType;)a=a.parentNode;a.parentNode&&a.parentNode.removeChild(a)}}else{var d=r.a.z(a).toLowerCase();b=document.createElement("div");d=d.match(/^<(thead|tbody|tfoot)/)&&[1,"<table>","</table>"]||!d.indexOf("<tr")&&[2,"<table><tbody>","</tbody></table>"]||(!d.indexOf("<td")||!d.indexOf("<th"))&&[3,"<table><tbody><tr>","</tr></tbody></table>"]||[0,"",""];a="ignored<div>"+
d[1]+a+d[2]+"</div>";for("function"==typeof window.innerShiv?b.appendChild(window.innerShiv(a)):b.innerHTML=a;d[0]--;)b=b.lastChild;b=r.a.X(b.lastChild.childNodes)}return b};r.a.Z=function(a,b){r.a.U(a);if(b!==o&&b!==l)if("string"!=typeof b&&(b=b.toString()),"undefined"!=typeof jQuery)jQuery(a).html(b);else for(var d=r.a.ma(b),e=0;e<d.length;e++)a.appendChild(d[e])};r.b("ko.utils.parseHtmlFragment",r.a.ma);r.b("ko.utils.setHtml",r.a.Z);
r.r=function(){function a(){return(4294967296*(1+Math.random())|0).toString(16).substring(1)}function b(a,f){if(a)if(8==a.nodeType){var d=r.r.Ga(a.nodeValue);d!=o&&f.push({cb:a,tb:d})}else if(1==a.nodeType)for(var d=0,g=a.childNodes,i=g.length;d<i;d++)b(g[d],f)}var d={};return{ka:function(b){"function"!=typeof b&&c(Error("You can only pass a function to ko.memoization.memoize()"));var f=a()+a();d[f]=b;return"<\!--[ko_memo:"+f+"]--\>"},Ra:function(a,b){var h=d[a];h===l&&c(Error("Couldn't find any memo with ID "+
a+". Perhaps it's already been unmemoized."));try{return h.apply(o,b||[]),m}finally{delete d[a]}},Sa:function(a,f){var d=[];b(a,d);for(var g=0,i=d.length;g<i;g++){var j=d[g].cb,k=[j];f&&r.a.J(k,f);r.r.Ra(d[g].tb,k);j.nodeValue="";j.parentNode&&j.parentNode.removeChild(j)}},Ga:function(a){return(a=a.match(/^\[ko_memo\:(.*?)\]$/))?a[1]:o}}}();r.b("ko.memoization",r.r);r.b("ko.memoization.memoize",r.r.ka);r.b("ko.memoization.unmemoize",r.r.Ra);r.b("ko.memoization.parseMemoText",r.r.Ga);
r.b("ko.memoization.unmemoizeDomNodeAndDescendants",r.r.Sa);r.Aa={throttle:function(a,b){a.throttleEvaluation=b;var d=o;return r.i({read:a,write:function(e){clearTimeout(d);d=setTimeout(function(){a(e)},b)}})},notify:function(a,b){a.equalityComparer="always"==b?function(){return p}:r.w.fn.equalityComparer;return a}};r.b("ko.extenders",r.Aa);r.Oa=function(a,b){this.da=a;this.bb=b;r.l(this,"dispose",this.v)};r.Oa.prototype.v=function(){this.nb=m;this.bb()};
r.R=function(){this.u={};r.a.extend(this,r.R.fn);r.l(this,"subscribe",this.ra);r.l(this,"extend",this.extend);r.l(this,"getSubscriptionsCount",this.kb)};
r.R.fn={ra:function(a,b,d){var d=d||"change",a=b?a.bind(b):a,e=new r.Oa(a,function(){r.a.ca(this.u[d],e)}.bind(this));this.u[d]||(this.u[d]=[]);this.u[d].push(e);return e},notifySubscribers:function(a,b){b=b||"change";this.u[b]&&r.a.n(this.u[b].slice(0),function(b){b&&b.nb!==m&&b.da(a)})},kb:function(){var a=0,b;for(b in this.u)this.u.hasOwnProperty(b)&&(a+=this.u[b].length);return a},extend:function(a){var b=this;if(a)for(var d in a){var e=r.Aa[d];"function"==typeof e&&(b=e(b,a[d]))}return b}};
r.Ea=function(a){return"function"==typeof a.ra&&"function"==typeof a.notifySubscribers};r.b("ko.subscribable",r.R);r.b("ko.isSubscribable",r.Ea);r.T=function(){var a=[];return{Xa:function(b){a.push({da:b,za:[]})},end:function(){a.pop()},Ha:function(b){r.Ea(b)||c("Only subscribable things can act as dependencies");if(0<a.length){var d=a[a.length-1];0<=r.a.k(d.za,b)||(d.za.push(b),d.da(b))}}}}();var B={undefined:m,"boolean":m,number:m,string:m};
r.w=function(a){function b(){if(0<arguments.length){if(!b.equalityComparer||!b.equalityComparer(d,arguments[0]))b.H(),d=arguments[0],b.G();return this}r.T.Ha(b);return d}var d=a;r.R.call(b);b.G=function(){b.notifySubscribers(d)};b.H=function(){b.notifySubscribers(d,"beforeChange")};r.a.extend(b,r.w.fn);r.l(b,"valueHasMutated",b.G);r.l(b,"valueWillMutate",b.H);return b};r.w.fn={B:r.w,equalityComparer:function(a,b){return a===o||typeof a in B?a===b:p}};
r.V=function(a){return a===o||a===l||a.B===l?p:a.B===r.w?m:r.V(a.B)};r.P=function(a){return"function"==typeof a&&a.B===r.w?m:"function"==typeof a&&a.B===r.i&&a.lb?m:p};r.b("ko.observable",r.w);r.b("ko.isObservable",r.V);r.b("ko.isWriteableObservable",r.P);
r.Q=function(a){0==arguments.length&&(a=[]);a!==o&&a!==l&&!("length"in a)&&c(Error("The argument passed when initializing an observable array must be an array, or null, or undefined."));var b=new r.w(a);r.a.extend(b,r.Q.fn);r.l(b,"remove",b.remove);r.l(b,"removeAll",b.zb);r.l(b,"destroy",b.fa);r.l(b,"destroyAll",b.ab);r.l(b,"indexOf",b.indexOf);r.l(b,"replace",b.replace);return b};
r.Q.fn={remove:function(a){for(var b=this(),d=[],e="function"==typeof a?a:function(b){return b===a},f=0;f<b.length;f++){var h=b[f];e(h)&&(0===d.length&&this.H(),d.push(h),b.splice(f,1),f--)}d.length&&this.G();return d},zb:function(a){if(a===l){var b=this(),d=b.slice(0);this.H();b.splice(0,b.length);this.G();return d}return!a?[]:this.remove(function(b){return 0<=r.a.k(a,b)})},fa:function(a){var b=this(),d="function"==typeof a?a:function(b){return b===a};this.H();for(var e=b.length-1;0<=e;e--)d(b[e])&&
(b[e]._destroy=m);this.G()},ab:function(a){return a===l?this.fa(function(){return m}):!a?[]:this.fa(function(b){return 0<=r.a.k(a,b)})},indexOf:function(a){var b=this();return r.a.k(b,a)},replace:function(a,b){var d=this.indexOf(a);0<=d&&(this.H(),this()[d]=b,this.G())}};r.a.n("pop,push,reverse,shift,sort,splice,unshift".split(","),function(a){r.Q.fn[a]=function(){var b=this();this.H();b=b[a].apply(b,arguments);this.G();return b}});
r.a.n(["slice"],function(a){r.Q.fn[a]=function(){var b=this();return b[a].apply(b,arguments)}});r.b("ko.observableArray",r.Q);function C(a,b){a&&"object"==typeof a?b=a:(b=b||{},b.read=a||b.read);"function"!=typeof b.read&&c("Pass a function that returns the value of the dependentObservable");return b}
r.i=function(a,b,d){function e(){r.a.n(q,function(a){a.v()});q=[]}function f(){var a=g.throttleEvaluation;a&&0<=a?(clearTimeout(v),v=setTimeout(h,a)):h()}function h(){if(j&&"function"==typeof d.disposeWhen&&d.disposeWhen())g.v();else{try{e();r.T.Xa(function(a){q.push(a.ra(f))});var a=d.read.call(d.owner||b);g.notifySubscribers(i,"beforeChange");i=a}finally{r.T.end()}g.notifySubscribers(i);j=m}}function g(){if(0<arguments.length)"function"===typeof d.write?d.write.apply(d.owner||b,arguments):c("Cannot write a value to a dependentObservable unless you specify a 'write' option. If you wish to read the current value, don't pass any parameters.");
else return j||h(),r.T.Ha(g),i}var i,j=p,d=C(a,d),k="object"==typeof d.disposeWhenNodeIsRemoved?d.disposeWhenNodeIsRemoved:o,n=o;if(k){n=function(){g.v()};r.a.A.va(k,n);var t=d.disposeWhen;d.disposeWhen=function(){return!r.a.ga(k)||"function"==typeof t&&t()}}var q=[],v=o;g.jb=function(){return q.length};g.lb="function"===typeof d.write;g.v=function(){k&&r.a.A.Ia(k,n);e()};r.R.call(g);r.a.extend(g,r.i.fn);d.deferEvaluation!==m&&h();r.l(g,"dispose",g.v);r.l(g,"getDependenciesCount",g.jb);return g};
r.i.fn={B:r.i};r.i.B=r.w;r.b("ko.dependentObservable",r.i);r.b("ko.computed",r.i);
(function(){function a(e,f,h){h=h||new d;e=f(e);if(!("object"==typeof e&&e!==o&&e!==l&&!(e instanceof Date)))return e;var g=e instanceof Array?[]:{};h.save(e,g);b(e,function(b){var d=f(e[b]);switch(typeof d){case "boolean":case "number":case "string":case "function":g[b]=d;break;case "object":case "undefined":var k=h.get(d);g[b]=k!==l?k:a(d,f,h)}});return g}function b(a,b){if(a instanceof Array)for(var d=0;d<a.length;d++)b(d);else for(d in a)b(d)}function d(){var a=[],b=[];this.save=function(d,g){var i=
r.a.k(a,d);0<=i?b[i]=g:(a.push(d),b.push(g))};this.get=function(d){d=r.a.k(a,d);return 0<=d?b[d]:l}}r.Pa=function(b){0==arguments.length&&c(Error("When calling ko.toJS, pass the object you want to convert."));return a(b,function(a){for(var b=0;r.V(a)&&10>b;b++)a=a();return a})};r.toJSON=function(a){a=r.Pa(a);return r.a.qa(a)}})();r.b("ko.toJS",r.Pa);r.b("ko.toJSON",r.toJSON);
r.h={q:function(a){return"OPTION"==a.tagName?a.__ko__hasDomDataOptionValue__===m?r.a.e.get(a,r.c.options.la):a.getAttribute("value"):"SELECT"==a.tagName?0<=a.selectedIndex?r.h.q(a.options[a.selectedIndex]):l:a.value},S:function(a,b){if("OPTION"==a.tagName)switch(typeof b){case "string":r.a.e.set(a,r.c.options.la,l);"__ko__hasDomDataOptionValue__"in a&&delete a.__ko__hasDomDataOptionValue__;a.value=b;break;default:r.a.e.set(a,r.c.options.la,b),a.__ko__hasDomDataOptionValue__=m,a.value="number"===typeof b?
b:""}else if("SELECT"==a.tagName)for(var d=a.options.length-1;0<=d;d--){if(r.h.q(a.options[d])==b){a.selectedIndex=d;break}}else{if(b===o||b===l)b="";a.value=b}}};r.b("ko.selectExtensions",r.h);r.b("ko.selectExtensions.readValue",r.h.q);r.b("ko.selectExtensions.writeValue",r.h.S);
r.j=function(){function a(a,e){for(var d=o;a!=d;)d=a,a=a.replace(b,function(a,b){return e[b]});return a}var b=/\@ko_token_(\d+)\@/g,d=/^[\_$a-z][\_$a-z0-9]*(\[.*?\])*(\.[\_$a-z][\_$a-z0-9]*(\[.*?\])*)*$/i,e=["true","false"];return{D:[],Y:function(b){var e=r.a.z(b);if(3>e.length)return[];"{"===e.charAt(0)&&(e=e.substring(1,e.length-1));for(var b=[],d=o,i,j=0;j<e.length;j++){var k=e.charAt(j);if(d===o)switch(k){case '"':case "'":case "/":d=j,i=k}else if(k==i&&"\\"!==e.charAt(j-1)){k=e.substring(d,j+
1);b.push(k);var n="@ko_token_"+(b.length-1)+"@",e=e.substring(0,d)+n+e.substring(j+1),j=j-(k.length-n.length),d=o}}i=d=o;for(var t=0,q=o,j=0;j<e.length;j++){k=e.charAt(j);if(d===o)switch(k){case "{":d=j;q=k;i="}";break;case "(":d=j;q=k;i=")";break;case "[":d=j,q=k,i="]"}k===q?t++:k===i&&(t--,0===t&&(k=e.substring(d,j+1),b.push(k),n="@ko_token_"+(b.length-1)+"@",e=e.substring(0,d)+n+e.substring(j+1),j-=k.length-n.length,d=o))}i=[];e=e.split(",");d=0;for(j=e.length;d<j;d++)t=e[d],q=t.indexOf(":"),
0<q&&q<t.length-1?(k=t.substring(q+1),i.push({key:a(t.substring(0,q),b),value:a(k,b)})):i.push({unknown:a(t,b)});return i},ia:function(a){for(var b="string"===typeof a?r.j.Y(a):a,g=[],a=[],i,j=0;i=b[j];j++)if(0<g.length&&g.push(","),i.key){var k;a:{k=i.key;var n=r.a.z(k);switch(n.length&&n.charAt(0)){case "'":case '"':break a;default:k="'"+n+"'"}}i=i.value;g.push(k);g.push(":");g.push(i);n=r.a.z(i);if(0<=r.a.k(e,r.a.z(n).toLowerCase())?0:n.match(d)!==o)0<a.length&&a.push(", "),a.push(k+" : function(__ko_value) { "+
i+" = __ko_value; }")}else i.unknown&&g.push(i.unknown);b=g.join("");0<a.length&&(b=b+", '_ko_property_writers' : { "+a.join("")+" } ");return b},rb:function(a,b){for(var e=0;e<a.length;e++)if(r.a.z(a[e].key)==b)return m;return p}}}();r.b("ko.jsonExpressionRewriting",r.j);r.b("ko.jsonExpressionRewriting.bindingRewriteValidators",r.j.D);r.b("ko.jsonExpressionRewriting.parseObjectLiteral",r.j.Y);r.b("ko.jsonExpressionRewriting.insertPropertyAccessorsIntoJson",r.j.ia);
(function(){function a(a){return 8==a.nodeType&&(f?a.text:a.nodeValue).match(h)}function b(a){return 8==a.nodeType&&(f?a.text:a.nodeValue).match(g)}function d(e,d){for(var f=e,g=1,h=[];f=f.nextSibling;){if(b(f)&&(g--,0===g))return h;h.push(f);a(f)&&g++}d||c(Error("Cannot find closing comment tag to match: "+e.nodeValue));return o}function e(a,b){var e=d(a,b);return e?0<e.length?e[e.length-1].nextSibling:a.nextSibling:o}var f="<\!--test--\>"===document.createComment("test").text,h=f?/^<\!--\s*ko\s+(.*\:.*)\s*--\>$/:
/^\s*ko\s+(.*\:.*)\s*$/,g=f?/^<\!--\s*\/ko\s*--\>$/:/^\s*\/ko\s*$/,i={ul:m,ol:m};r.f={C:{},childNodes:function(b){return a(b)?d(b):b.childNodes},ha:function(b){if(a(b))for(var b=r.f.childNodes(b),e=0,d=b.length;e<d;e++)r.removeNode(b[e]);else r.a.U(b)},oa:function(b,e){if(a(b)){r.f.ha(b);for(var d=b.nextSibling,f=0,g=e.length;f<g;f++)d.parentNode.insertBefore(e[f],d)}else r.a.oa(b,e)},xb:function(b,e){a(b)?b.parentNode.insertBefore(e,b.nextSibling):b.firstChild?b.insertBefore(e,b.firstChild):b.appendChild(e)},
mb:function(b,e,d){a(b)?b.parentNode.insertBefore(e,d.nextSibling):d.nextSibling?b.insertBefore(e,d.nextSibling):b.appendChild(e)},nextSibling:function(d){return a(d)?e(d).nextSibling:d.nextSibling&&b(d.nextSibling)?l:d.nextSibling},ta:function(b){return(b=a(b))?b[1]:o},ib:function(a){if(r.f.ta(a)){var b;b=r.f.childNodes(a);for(var e=[],d=0,f=b.length;d<f;d++)r.a.A.F(b[d]),e.push(r.a.outerHTML(b[d]));b=String.prototype.concat.apply("",e);r.f.ha(a);(new r.m.I(a)).text(b)}},Fa:function(d){if(i[d.tagName.toLowerCase()]){var f=
d.firstChild;if(f){do if(1===f.nodeType){var g;g=f.firstChild;var h=o;if(g){do if(h)h.push(g);else if(a(g)){var q=e(g,m);q?g=q:h=[g]}else b(g)&&(h=[g]);while(g=g.nextSibling)}if(g=h){h=f.nextSibling;for(q=0;q<g.length;q++)h?d.insertBefore(g[q],h):d.appendChild(g[q])}}while(f=f.nextSibling)}}}}})();r.L=function(){};
r.a.extend(r.L.prototype,{nodeHasBindings:function(a){switch(a.nodeType){case 1:return a.getAttribute("data-bind")!=o;case 8:return r.f.ta(a)!=o;default:return p}},getBindings:function(a,b){var d=this.getBindingsString(a,b);return d?this.parseBindingsString(d,b):o},getBindingsString:function(a){switch(a.nodeType){case 1:return a.getAttribute("data-bind");case 8:return r.f.ta(a);default:return o}},parseBindingsString:function(a,b){try{var d=b.$data,e=" { "+r.j.ia(a)+" } ";return r.a.hb(e,d===o?window:
d,b)}catch(f){c(Error("Unable to parse bindings.\nMessage: "+f+";\nBindings value: "+a))}}});r.L.instance=new r.L;r.b("ko.bindingProvider",r.L);
(function(){function a(a,d){for(var h,g=d.childNodes[0];h=g;)g=r.f.nextSibling(h),b(a,h,p)}function b(b,f,h){var g=m,i=1==f.nodeType;i&&r.f.Fa(f);if(i&&h||r.L.instance.nodeHasBindings(f))g=d(f,o,b,h).Bb;i&&g&&a(b,f)}function d(a,b,d,g){function i(a){return function(){return n[a]}}function j(){return n}var k=0;r.f.ib(a);var n,t;new r.i(function(){var q=d&&d instanceof r.K?d:new r.K(r.a.d(d)),v=q.$data;g&&r.Na(a,q);if(n=("function"==typeof b?b():b)||r.L.instance.getBindings(a,q)){if(0===k){k=1;for(var s in n){var w=
r.c[s];w&&8===a.nodeType&&!r.f.C[s]&&c(Error("The binding '"+s+"' cannot be used with virtual elements"));if(w&&"function"==typeof w.init&&(w=(0,w.init)(a,i(s),j,v,q))&&w.controlsDescendantBindings)t!==l&&c(Error("Multiple bindings ("+t+" and "+s+") are trying to control descendant bindings of the same element. You cannot use these bindings together on the same element.")),t=s}k=2}if(2===k)for(s in n)(w=r.c[s])&&"function"==typeof w.update&&(0,w.update)(a,i(s),j,v,q)}},o,{disposeWhenNodeIsRemoved:a});
return{Bb:t===l}}r.c={};r.K=function(a,b){this.$data=a;b?(this.$parent=b.$data,this.$parents=(b.$parents||[]).slice(0),this.$parents.unshift(this.$parent),this.$root=b.$root):(this.$parents=[],this.$root=a)};r.K.prototype.createChildContext=function(a){return new r.K(a,this)};r.Na=function(a,b){if(2==arguments.length)r.a.e.set(a,"__ko_bindingContext__",b);else return r.a.e.get(a,"__ko_bindingContext__")};r.xa=function(a,b,h){1===a.nodeType&&r.f.Fa(a);return d(a,b,h,m)};r.Ta=function(b,d){1===d.nodeType&&
a(b,d)};r.wa=function(a,d){d&&1!==d.nodeType&&8!==d.nodeType&&c(Error("ko.applyBindings: first parameter should be your view model; second parameter should be a DOM node"));d=d||window.document.body;b(a,d,m)};r.ea=function(a){switch(a.nodeType){case 1:case 8:var b=r.Na(a);if(b)return b;if(a.parentNode)return r.ea(a.parentNode)}};r.$a=function(a){return(a=r.ea(a))?a.$data:l};r.b("ko.bindingHandlers",r.c);r.b("ko.applyBindings",r.wa);r.b("ko.applyBindingsToDescendants",r.Ta);r.b("ko.applyBindingsToNode",
r.xa);r.b("ko.contextFor",r.ea);r.b("ko.dataFor",r.$a)})();r.a.n(["click"],function(a){r.c[a]={init:function(b,d,e,f){return r.c.event.init.call(this,b,function(){var b={};b[a]=d();return b},e,f)}}});
r.c.event={init:function(a,b,d,e){var f=b()||{},h;for(h in f)(function(){var f=h;"string"==typeof f&&r.a.s(a,f,function(a){var h,k=b()[f];if(k){var n=d();try{var t=r.a.X(arguments);t.unshift(e);h=k.apply(e,t)}finally{if(h!==m)a.preventDefault?a.preventDefault():a.returnValue=p}if(n[f+"Bubble"]===p)a.cancelBubble=m,a.stopPropagation&&a.stopPropagation()}})})()}};
r.c.submit={init:function(a,b,d,e){"function"!=typeof b()&&c(Error("The value for a submit binding must be a function"));r.a.s(a,"submit",function(d){var h,g=b();try{h=g.call(e,a)}finally{if(h!==m)d.preventDefault?d.preventDefault():d.returnValue=p}})}};r.c.visible={update:function(a,b){var d=r.a.d(b()),e="none"!=a.style.display;if(d&&!e)a.style.display="";else if(!d&&e)a.style.display="none"}};
r.c.enable={update:function(a,b){var d=r.a.d(b());if(d&&a.disabled)a.removeAttribute("disabled");else if(!d&&!a.disabled)a.disabled=m}};r.c.disable={update:function(a,b){r.c.enable.update(a,function(){return!r.a.d(b())})}};function D(a,b,d){d&&b!==r.h.q(a)&&r.h.S(a,b);b!==r.h.q(a)&&r.a.sa(a,"change")}
r.c.value={init:function(a,b,d){var e=["change"],f=d().valueUpdate;f&&("string"==typeof f&&(f=[f]),r.a.J(e,f),e=r.a.ya(e));r.a.n(e,function(e){var f=p;r.a.Cb(e,"after")&&(f=m,e=e.substring(5));var i=f?function(a){setTimeout(a,0)}:function(a){a()};r.a.s(a,e,function(){i(function(){var e=b(),f=r.h.q(a);r.P(e)?e(f):(e=d(),e._ko_property_writers&&e._ko_property_writers.value&&e._ko_property_writers.value(f))})})})},update:function(a,b){var d=r.a.d(b()),e=r.h.q(a),f=d!=e;0===d&&0!==e&&"0"!==e&&(f=m);f&&
(e=function(){r.h.S(a,d)},e(),"SELECT"==a.tagName&&setTimeout(e,0));"SELECT"==a.tagName&&0<a.length&&D(a,d,p)}};
r.c.options={update:function(a,b,d){"SELECT"!=a.tagName&&c(Error("options binding applies only to SELECT elements"));var e=0==a.length,f=r.a.ba(r.a.aa(a.childNodes,function(a){return a.tagName&&"OPTION"==a.tagName&&a.selected}),function(a){return r.h.q(a)||a.innerText||a.textContent}),h=a.scrollTop;a.scrollTop=0;for(var g=r.a.d(b());0<a.length;)r.F(a.options[0]),a.remove(0);if(g){d=d();"number"!=typeof g.length&&(g=[g]);if(d.optionsCaption){var i=document.createElement("OPTION");r.a.Z(i,d.optionsCaption);
r.h.S(i,l);a.appendChild(i)}for(var b=0,j=g.length;b<j;b++){var i=document.createElement("OPTION"),k="string"==typeof d.optionsValue?g[b][d.optionsValue]:g[b],k=r.a.d(k);r.h.S(i,k);var n=d.optionsText,k="function"==typeof n?n(g[b]):"string"==typeof n?g[b][n]:k;if(k===o||k===l)k="";r.a.Ma(i,k);a.appendChild(i)}g=a.getElementsByTagName("OPTION");b=i=0;for(j=g.length;b<j;b++)0<=r.a.k(f,r.h.q(g[b]))&&(r.a.La(g[b],m),i++);if(h)a.scrollTop=h;e&&"value"in d&&D(a,r.a.d(d.value),m)}}};r.c.options.la="__ko.optionValueDomData__";
r.c.selectedOptions={Da:function(a){for(var b=[],a=a.childNodes,d=0,e=a.length;d<e;d++){var f=a[d];"OPTION"==f.tagName&&f.selected&&b.push(r.h.q(f))}return b},init:function(a,b,d){r.a.s(a,"change",function(){var a=b();r.P(a)?a(r.c.selectedOptions.Da(this)):(a=d(),a._ko_property_writers&&a._ko_property_writers.value&&a._ko_property_writers.value(r.c.selectedOptions.Da(this)))})},update:function(a,b){"SELECT"!=a.tagName&&c(Error("values binding applies only to SELECT elements"));var d=r.a.d(b());if(d&&
"number"==typeof d.length)for(var e=a.childNodes,f=0,h=e.length;f<h;f++){var g=e[f];"OPTION"==g.tagName&&r.a.La(g,0<=r.a.k(d,r.h.q(g)))}}};r.c.text={update:function(a,b){r.a.Ma(a,b())}};r.c.html={init:function(){return{controlsDescendantBindings:m}},update:function(a,b){var d=r.a.d(b());r.a.Z(a,d)}};r.c.css={update:function(a,b){var d=r.a.d(b()||{}),e;for(e in d)if("string"==typeof e){var f=r.a.d(d[e]);r.a.Qa(a,e,f)}}};
r.c.style={update:function(a,b){var d=r.a.d(b()||{}),e;for(e in d)if("string"==typeof e){var f=r.a.d(d[e]);a.style[e]=f||""}}};r.c.uniqueName={init:function(a,b){if(b())a.name="ko_unique_"+ ++r.c.uniqueName.Za,(r.a.ob||r.a.pb)&&a.mergeAttributes(document.createElement("<input name='"+a.name+"'/>"),p)}};r.c.uniqueName.Za=0;
r.c.checked={init:function(a,b,d){r.a.s(a,"click",function(){var e;if("checkbox"==a.type)e=a.checked;else if("radio"==a.type&&a.checked)e=a.value;else return;var f=b();"checkbox"==a.type&&r.a.d(f)instanceof Array?(e=r.a.k(r.a.d(f),a.value),a.checked&&0>e?f.push(a.value):!a.checked&&0<=e&&f.splice(e,1)):r.P(f)?f()!==e&&f(e):(f=d(),f._ko_property_writers&&f._ko_property_writers.checked&&f._ko_property_writers.checked(e))});"radio"==a.type&&!a.name&&r.c.uniqueName.init(a,function(){return m})},update:function(a,
b){var d=r.a.d(b());if("checkbox"==a.type)a.checked=d instanceof Array?0<=r.a.k(d,a.value):d;else if("radio"==a.type)a.checked=a.value==d}};r.c.attr={update:function(a,b){var d=r.a.d(b())||{},e;for(e in d)if("string"==typeof e){var f=r.a.d(d[e]);f===p||f===o||f===l?a.removeAttribute(e):a.setAttribute(e,f.toString())}}};
r.c.hasfocus={init:function(a,b,d){function e(a){var e=b();a!=r.a.d(e)&&(r.P(e)?e(a):(e=d(),e._ko_property_writers&&e._ko_property_writers.hasfocus&&e._ko_property_writers.hasfocus(a)))}r.a.s(a,"focus",function(){e(m)});r.a.s(a,"focusin",function(){e(m)});r.a.s(a,"blur",function(){e(p)});r.a.s(a,"focusout",function(){e(p)})},update:function(a,b){var d=r.a.d(b());d?a.focus():a.blur();r.a.sa(a,d?"focusin":"focusout")}};
r.c["with"]={o:function(a){return function(){var b=a();return{"if":b,data:b,templateEngine:r.p.M}}},init:function(a,b){return r.c.template.init(a,r.c["with"].o(b))},update:function(a,b,d,e,f){return r.c.template.update(a,r.c["with"].o(b),d,e,f)}};r.j.D["with"]=p;r.f.C["with"]=m;r.c["if"]={o:function(a){return function(){return{"if":a(),templateEngine:r.p.M}}},init:function(a,b){return r.c.template.init(a,r.c["if"].o(b))},update:function(a,b,d,e,f){return r.c.template.update(a,r.c["if"].o(b),d,e,f)}};
r.j.D["if"]=p;r.f.C["if"]=m;r.c.ifnot={o:function(a){return function(){return{ifnot:a(),templateEngine:r.p.M}}},init:function(a,b){return r.c.template.init(a,r.c.ifnot.o(b))},update:function(a,b,d,e,f){return r.c.template.update(a,r.c.ifnot.o(b),d,e,f)}};r.j.D.ifnot=p;r.f.C.ifnot=m;
r.c.foreach={o:function(a){return function(){var b=r.a.d(a());return!b||"number"==typeof b.length?{foreach:b,templateEngine:r.p.M}:{foreach:b.data,includeDestroyed:b.includeDestroyed,afterAdd:b.afterAdd,beforeRemove:b.beforeRemove,afterRender:b.afterRender,templateEngine:r.p.M}}},init:function(a,b){return r.c.template.init(a,r.c.foreach.o(b))},update:function(a,b,d,e,f){return r.c.template.update(a,r.c.foreach.o(b),d,e,f)}};r.j.D.foreach=p;r.f.C.foreach=m;r.b("ko.allowedVirtualElementBindings",r.f.C);
r.t=function(){};r.t.prototype.renderTemplateSource=function(){c("Override renderTemplateSource")};r.t.prototype.createJavaScriptEvaluatorBlock=function(){c("Override createJavaScriptEvaluatorBlock")};r.t.prototype.makeTemplateSource=function(a){if("string"==typeof a){var b=document.getElementById(a);b||c(Error("Cannot find template with ID "+a));return new r.m.g(b)}if(1==a.nodeType||8==a.nodeType)return new r.m.I(a);c(Error("Unknown template type: "+a))};
r.t.prototype.renderTemplate=function(a,b,d){return this.renderTemplateSource(this.makeTemplateSource(a),b,d)};r.t.prototype.isTemplateRewritten=function(a){return this.allowTemplateRewriting===p?m:this.W&&this.W[a]?m:this.makeTemplateSource(a).data("isRewritten")};r.t.prototype.rewriteTemplate=function(a,b){var d=this.makeTemplateSource(a),e=b(d.text());d.text(e);d.data("isRewritten",m);if("string"==typeof a)this.W=this.W||{},this.W[a]=m};r.b("ko.templateEngine",r.t);
r.$=function(){function a(a,b,d){for(var a=r.j.Y(a),g=r.j.D,i=0;i<a.length;i++){var j=a[i].key;if(g.hasOwnProperty(j)){var k=g[j];"function"===typeof k?(j=k(a[i].value))&&c(Error(j)):k||c(Error("This template engine does not support the '"+j+"' binding within its templates"))}}a="ko.templateRewriting.applyMemoizedBindingsToNextSibling(function() { return (function() { return { "+r.j.ia(a)+" } })() })";return d.createJavaScriptEvaluatorBlock(a)+b}var b=/(<[a-z]+\d*(\s+(?!data-bind=)[a-z0-9\-]+(=(\"[^\"]*\"|\'[^\']*\'))?)*\s+)data-bind=(["'])([\s\S]*?)\5/gi,
d=/<\!--\s*ko\b\s*([\s\S]*?)\s*--\>/g;return{gb:function(a,b){b.isTemplateRewritten(a)||b.rewriteTemplate(a,function(a){return r.$.ub(a,b)})},ub:function(e,f){return e.replace(b,function(b,e,d,j,k,n,t){return a(t,e,f)}).replace(d,function(b,e){return a(e,"<\!-- ko --\>",f)})},Ua:function(a){return r.r.ka(function(b,d){b.nextSibling&&r.xa(b.nextSibling,a,d)})}}}();r.b("ko.templateRewriting",r.$);r.b("ko.templateRewriting.applyMemoizedBindingsToNextSibling",r.$.Ua);r.m={};r.m.g=function(a){this.g=a};
r.m.g.prototype.text=function(){if(0==arguments.length)return"script"==this.g.tagName.toLowerCase()?this.g.text:this.g.innerHTML;var a=arguments[0];"script"==this.g.tagName.toLowerCase()?this.g.text=a:r.a.Z(this.g,a)};r.m.g.prototype.data=function(a){if(1===arguments.length)return r.a.e.get(this.g,"templateSourceData_"+a);r.a.e.set(this.g,"templateSourceData_"+a,arguments[1])};r.m.I=function(a){this.g=a};r.m.I.prototype=new r.m.g;
r.m.I.prototype.text=function(){if(0==arguments.length)return r.a.e.get(this.g,"__ko_anon_template__");r.a.e.set(this.g,"__ko_anon_template__",arguments[0])};r.b("ko.templateSources",r.m);r.b("ko.templateSources.domElement",r.m.g);r.b("ko.templateSources.anonymousTemplate",r.m.I);
(function(){function a(a,b,d){for(var g=0;node=a[g];g++)node.parentNode===b&&(1===node.nodeType||8===node.nodeType)&&d(node)}function b(a,b,h,g,i){var i=i||{},j=i.templateEngine||d;r.$.gb(h,j);h=j.renderTemplate(h,g,i);("number"!=typeof h.length||0<h.length&&"number"!=typeof h[0].nodeType)&&c("Template engine must return an array of DOM nodes");j=p;switch(b){case "replaceChildren":r.f.oa(a,h);j=m;break;case "replaceNode":r.a.Ja(a,h);j=m;break;case "ignoreTargetNode":break;default:c(Error("Unknown renderMode: "+
b))}j&&(r.ua(h,g),i.afterRender&&i.afterRender(h,g.$data));return h}var d;r.pa=function(a){a!=l&&!(a instanceof r.t)&&c("templateEngine must inherit from ko.templateEngine");d=a};r.ua=function(b,d){var h=r.a.J([],b),g=0<b.length?b[0].parentNode:o;a(h,g,function(a){r.wa(d,a)});a(h,g,function(a){r.r.Sa(a,[d])})};r.na=function(a,f,h,g,i){h=h||{};(h.templateEngine||d)==l&&c("Set a template engine before calling renderTemplate");i=i||"replaceChildren";if(g){var j=g.nodeType?g:0<g.length?g[0]:o;return new r.i(function(){var d=
f&&f instanceof r.K?f:new r.K(r.a.d(f)),n="function"==typeof a?a(d.$data):a,d=b(g,i,n,d,h);"replaceNode"==i&&(g=d,j=g.nodeType?g:0<g.length?g[0]:o)},o,{disposeWhen:function(){return!j||!r.a.ga(j)},disposeWhenNodeIsRemoved:j&&"replaceNode"==i?j.parentNode:j})}return r.r.ka(function(b){r.na(a,f,h,b,"replaceNode")})};r.Ab=function(a,d,h,g,i){function j(a,b){var d=k(a);r.ua(b,d);h.afterRender&&h.afterRender(b,d.$data)}function k(a){return i.createChildContext(r.a.d(a))}return new r.i(function(){var i=
r.a.d(d)||[];"undefined"==typeof i.length&&(i=[i]);i=r.a.aa(i,function(a){return h.includeDestroyed||a===l||a===o||!r.a.d(a._destroy)});r.a.Ka(g,i,function(d){var f="function"==typeof a?a(d):a;return b(o,"ignoreTargetNode",f,k(d),h)},h,j)},o,{disposeWhenNodeIsRemoved:g})};r.c.template={init:function(a,b){var d=r.a.d(b());"string"!=typeof d&&!d.name&&1==a.nodeType&&((new r.m.I(a)).text(a.innerHTML),r.a.U(a));return{controlsDescendantBindings:m}},update:function(a,b,d,g,i){b=r.a.d(b());g=m;"string"==
typeof b?d=b:(d=b.name,"if"in b&&(g=g&&r.a.d(b["if"])),"ifnot"in b&&(g=g&&!r.a.d(b.ifnot)));var j=o;"object"===typeof b&&"foreach"in b?j=r.Ab(d||a,g&&b.foreach||[],b,a,i):g?(i="object"==typeof b&&"data"in b?i.createChildContext(r.a.d(b.data)):i,j=r.na(d||a,i,b,a)):r.f.ha(a);i=j;(b=r.a.e.get(a,"__ko__templateSubscriptionDomDataKey__"))&&"function"==typeof b.v&&b.v();r.a.e.set(a,"__ko__templateSubscriptionDomDataKey__",i)}};r.j.D.template=function(a){a=r.j.Y(a);return 1==a.length&&a[0].unknown?o:r.j.rb(a,
"name")?o:"This template engine does not support anonymous templates nested within its templates"};r.f.C.template=m})();r.b("ko.setTemplateEngine",r.pa);r.b("ko.renderTemplate",r.na);
r.a.N=function(a,b,d){if(d===l)return r.a.N(a,b,1)||r.a.N(a,b,10)||r.a.N(a,b,Number.MAX_VALUE);for(var a=a||[],b=b||[],e=a,f=b,h=[],g=0;g<=f.length;g++)h[g]=[];for(var g=0,i=Math.min(e.length,d);g<=i;g++)h[0][g]=g;g=1;for(i=Math.min(f.length,d);g<=i;g++)h[g][0]=g;for(var i=e.length,j,k=f.length,g=1;g<=i;g++){j=Math.max(1,g-d);for(var n=Math.min(k,g+d);j<=n;j++)h[j][g]=e[g-1]===f[j-1]?h[j-1][g-1]:Math.min(h[j-1][g]===l?Number.MAX_VALUE:h[j-1][g]+1,h[j][g-1]===l?Number.MAX_VALUE:h[j][g-1]+1)}d=a.length;
e=b.length;f=[];g=h[e][d];if(g===l)h=o;else{for(;0<d||0<e;){i=h[e][d];k=0<e?h[e-1][d]:g+1;n=0<d?h[e][d-1]:g+1;j=0<e&&0<d?h[e-1][d-1]:g+1;if(k===l||k<i-1)k=g+1;if(n===l||n<i-1)n=g+1;j<i-1&&(j=g+1);k<=n&&k<j?(f.push({status:"added",value:b[e-1]}),e--):(n<k&&n<j?f.push({status:"deleted",value:a[d-1]}):(f.push({status:"retained",value:a[d-1]}),e--),d--)}h=f.reverse()}return h};r.b("ko.utils.compareArrays",r.a.N);
(function(){function a(a){if(2<a.length){for(var b=a[0],f=a[a.length-1],h=[b];b!==f;){b=b.nextSibling;if(!b)return;h.push(b)}Array.prototype.splice.apply(a,[0,a.length].concat(h))}}function b(b,e,f,h){var g=[],b=r.i(function(){var b=e(f)||[];0<g.length&&(a(g),r.a.Ja(g,b),h&&h(f,b));g.splice(0,g.length);r.a.J(g,b)},o,{disposeWhenNodeIsRemoved:b,disposeWhen:function(){return 0==g.length||!r.a.ga(g[0])}});return{sb:g,i:b}}r.a.Ka=function(d,e,f,h,g){for(var e=e||[],h=h||{},i=r.a.e.get(d,"setDomNodeChildrenFromArrayMapping_lastMappingResult")===
l,j=r.a.e.get(d,"setDomNodeChildrenFromArrayMapping_lastMappingResult")||[],k=r.a.ba(j,function(a){return a.Va}),n=r.a.N(k,e),e=[],t=0,q=[],k=[],v=o,s=0,w=n.length;s<w;s++)switch(n[s].status){case "retained":var x=j[t];e.push(x);0<x.O.length&&(v=x.O[x.O.length-1]);t++;break;case "deleted":j[t].i.v();a(j[t].O);r.a.n(j[t].O,function(a){q.push({element:a,index:s,value:n[s].value});v=a});t++;break;case "added":var x=n[s].value,z=b(d,f,x,g),u=z.sb;e.push({Va:n[s].value,O:u,i:z.i});for(var z=0,y=u.length;z<
y;z++){var A=u[z];k.push({element:A,index:s,value:n[s].value});v==o?r.f.xb(d,A):r.f.mb(d,A,v);v=A}g&&g(x,u)}r.a.n(q,function(a){r.F(a.element)});f=p;if(!i){if(h.afterAdd)for(s=0;s<k.length;s++)h.afterAdd(k[s].element,k[s].index,k[s].value);if(h.beforeRemove){for(s=0;s<q.length;s++)h.beforeRemove(q[s].element,q[s].index,q[s].value);f=m}}f||r.a.n(q,function(a){r.removeNode(a.element)});r.a.e.set(d,"setDomNodeChildrenFromArrayMapping_lastMappingResult",e)}})();
r.b("ko.utils.setDomNodeChildrenFromArrayMapping",r.a.Ka);r.p=function(){this.allowTemplateRewriting=p};r.p.prototype=new r.t;r.p.prototype.renderTemplateSource=function(a){a=a.text();return r.a.ma(a)};r.p.M=new r.p;r.pa(r.p.M);r.b("ko.nativeTemplateEngine",r.p);
(function(){r.ja=function(){var a=this.qb=function(){if("undefined"==typeof jQuery||!jQuery.tmpl)return 0;try{if(0<=jQuery.tmpl.tag.tmpl.open.toString().indexOf("__"))return 2}catch(a){}return 1}();this.renderTemplateSource=function(d,e,f){f=f||{};2>a&&c(Error("Your version of jQuery.tmpl is too old. Please upgrade to jQuery.tmpl 1.0.0pre or later."));var h=d.data("precompiled");h||(h=d.text()||"",h=jQuery.template(o,"{{ko_with $item.koBindingContext}}"+h+"{{/ko_with}}"),d.data("precompiled",h));
d=[e.$data];e=jQuery.extend({koBindingContext:e},f.templateOptions);e=jQuery.tmpl(h,d,e);e.appendTo(document.createElement("div"));jQuery.fragments={};return e};this.createJavaScriptEvaluatorBlock=function(a){return"{{ko_code ((function() { return "+a+" })()) }}"};this.addTemplate=function(a,b){document.write("<script type='text/html' id='"+a+"'>"+b+"<\/script>")};if(0<a)jQuery.tmpl.tag.ko_code={open:"__.push($1 || '');"},jQuery.tmpl.tag.ko_with={open:"with($1) {",close:"} "}};r.ja.prototype=new r.t;
var a=new r.ja;0<a.qb&&r.pa(a);r.b("ko.jqueryTmplTemplateEngine",r.ja)})();
})(window);

976
bench/markermanager.js Normal file
View File

@ -0,0 +1,976 @@
/**
* @name MarkerManager v3
* @version 1.0
* @copyright (c) 2007 Google Inc.
* @author Doug Ricket, Bjorn Brala (port to v3), others,
*
* @fileoverview Marker manager is an interface between the map and the user,
* designed to manage adding and removing many points when the viewport changes.
* <br /><br />
* <b>How it Works</b>:<br/>
* The MarkerManager places its markers onto a grid, similar to the map tiles.
* When the user moves the viewport, it computes which grid cells have
* entered or left the viewport, and shows or hides all the markers in those
* cells.
* (If the users scrolls the viewport beyond the markers that are loaded,
* no markers will be visible until the <code>EVENT_moveend</code>
* triggers an update.)
* In practical consequences, this allows 10,000 markers to be distributed over
* a large area, and as long as only 100-200 are visible in any given viewport,
* the user will see good performance corresponding to the 100 visible markers,
* rather than poor performance corresponding to the total 10,000 markers.
* Note that some code is optimized for speed over space,
* with the goal of accommodating thousands of markers.
*/
/*
* Licensed 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.
*/
/**
* @name MarkerManagerOptions
* @class This class represents optional arguments to the {@link MarkerManager}
* constructor.
* @property {Number} maxZoom Sets the maximum zoom level monitored by a
* marker manager. If not given, the manager assumes the maximum map zoom
* level. This value is also used when markers are added to the manager
* without the optional {@link maxZoom} parameter.
* @property {Number} borderPadding Specifies, in pixels, the extra padding
* outside the map's current viewport monitored by a manager. Markers that
* fall within this padding are added to the map, even if they are not fully
* visible.
* @property {Boolean} trackMarkers=false Indicates whether or not a marker
* manager should track markers' movements. If you wish to move managed
* markers using the {@link setPoint}/{@link setLatLng} methods,
* this option should be set to {@link true}.
*/
/**
* Creates a new MarkerManager that will show/hide markers on a map.
*
* Events:
* @event changed (Parameters: shown bounds, shown markers) Notify listeners when the state of what is displayed changes.
* @event loaded MarkerManager has succesfully been initialized.
*
* @constructor
* @param {Map} map The map to manage.
* @param {Object} opt_opts A container for optional arguments:
* {Number} maxZoom The maximum zoom level for which to create tiles.
* {Number} borderPadding The width in pixels beyond the map border,
* where markers should be display.
* {Boolean} trackMarkers Whether or not this manager should track marker
* movements.
*/
function MarkerManager(map, opt_opts) {
var me = this;
me.map_ = map;
me.mapZoom_ = map.getZoom();
me.projectionHelper_ = new ProjectionHelperOverlay(map);
google.maps.event.addListener(me.projectionHelper_, 'ready', function () {
me.projection_ = this.getProjection();
me.initialize(map, opt_opts);
});
}
MarkerManager.prototype.initialize = function (map, opt_opts) {
var me = this;
opt_opts = opt_opts || {};
me.tileSize_ = MarkerManager.DEFAULT_TILE_SIZE_;
var mapTypes = map.mapTypes;
// Find max zoom level
var mapMaxZoom = 1;
for (var sType in mapTypes ) {
if (typeof map.mapTypes.get(sType) === 'object' && typeof map.mapTypes.get(sType).maxZoom === 'number') {
var mapTypeMaxZoom = map.mapTypes.get(sType).maxZoom;
if (mapTypeMaxZoom > mapMaxZoom) {
mapMaxZoom = mapTypeMaxZoom;
}
}
}
me.maxZoom_ = opt_opts.maxZoom || 19;
me.trackMarkers_ = opt_opts.trackMarkers;
me.show_ = opt_opts.show || true;
var padding;
if (typeof opt_opts.borderPadding === 'number') {
padding = opt_opts.borderPadding;
} else {
padding = MarkerManager.DEFAULT_BORDER_PADDING_;
}
// The padding in pixels beyond the viewport, where we will pre-load markers.
me.swPadding_ = new google.maps.Size(-padding, padding);
me.nePadding_ = new google.maps.Size(padding, -padding);
me.borderPadding_ = padding;
me.gridWidth_ = {};
me.grid_ = {};
me.grid_[me.maxZoom_] = {};
me.numMarkers_ = {};
me.numMarkers_[me.maxZoom_] = 0;
google.maps.event.addListener(map, 'dragend', function () {
me.onMapMoveEnd_();
});
google.maps.event.addListener(map, 'zoom_changed', function () {
me.onMapMoveEnd_();
});
/**
* This closure provide easy access to the map.
* They are used as callbacks, not as methods.
* @param GMarker marker Marker to be removed from the map
* @private
*/
me.removeOverlay_ = function (marker) {
marker.setMap(null);
me.shownMarkers_--;
};
/**
* This closure provide easy access to the map.
* They are used as callbacks, not as methods.
* @param GMarker marker Marker to be added to the map
* @private
*/
me.addOverlay_ = function (marker) {
if (me.show_) {
marker.setMap(me.map_);
me.shownMarkers_++;
}
};
me.resetManager_();
me.shownMarkers_ = 0;
me.shownBounds_ = me.getMapGridBounds_();
google.maps.event.trigger(me, 'loaded');
};
/**
* Default tile size used for deviding the map into a grid.
*/
MarkerManager.DEFAULT_TILE_SIZE_ = 1024;
/*
* How much extra space to show around the map border so
* dragging doesn't result in an empty place.
*/
MarkerManager.DEFAULT_BORDER_PADDING_ = 100;
/**
* Default tilesize of single tile world.
*/
MarkerManager.MERCATOR_ZOOM_LEVEL_ZERO_RANGE = 256;
/**
* Initializes MarkerManager arrays for all zoom levels
* Called by constructor and by clearAllMarkers
*/
MarkerManager.prototype.resetManager_ = function () {
var mapWidth = MarkerManager.MERCATOR_ZOOM_LEVEL_ZERO_RANGE;
for (var zoom = 0; zoom <= this.maxZoom_; ++zoom) {
this.grid_[zoom] = {};
this.numMarkers_[zoom] = 0;
this.gridWidth_[zoom] = Math.ceil(mapWidth / this.tileSize_);
mapWidth <<= 1;
}
};
/**
* Removes all markers in the manager, and
* removes any visible markers from the map.
*/
MarkerManager.prototype.clearMarkers = function () {
this.processAll_(this.shownBounds_, this.removeOverlay_);
this.resetManager_();
};
/**
* Gets the tile coordinate for a given latlng point.
*
* @param {LatLng} latlng The geographical point.
* @param {Number} zoom The zoom level.
* @param {google.maps.Size} padding The padding used to shift the pixel coordinate.
* Used for expanding a bounds to include an extra padding
* of pixels surrounding the bounds.
* @return {GPoint} The point in tile coordinates.
*
*/
MarkerManager.prototype.getTilePoint_ = function (latlng, zoom, padding) {
var pixelPoint = this.projectionHelper_.LatLngToPixel(latlng, zoom);
var point = new google.maps.Point(
Math.floor((pixelPoint.x + padding.width) / this.tileSize_),
Math.floor((pixelPoint.y + padding.height) / this.tileSize_)
);
return point;
};
/**
* Finds the appropriate place to add the marker to the grid.
* Optimized for speed; does not actually add the marker to the map.
* Designed for batch-processing thousands of markers.
*
* @param {Marker} marker The marker to add.
* @param {Number} minZoom The minimum zoom for displaying the marker.
* @param {Number} maxZoom The maximum zoom for displaying the marker.
*/
MarkerManager.prototype.addMarkerBatch_ = function (marker, minZoom, maxZoom) {
var me = this;
var mPoint = marker.getPosition();
marker.MarkerManager_minZoom = minZoom;
// Tracking markers is expensive, so we do this only if the
// user explicitly requested it when creating marker manager.
if (this.trackMarkers_) {
google.maps.event.addListener(marker, 'changed', function (a, b, c) {
me.onMarkerMoved_(a, b, c);
});
}
var gridPoint = this.getTilePoint_(mPoint, maxZoom, new google.maps.Size(0, 0, 0, 0));
for (var zoom = maxZoom; zoom >= minZoom; zoom--) {
var cell = this.getGridCellCreate_(gridPoint.x, gridPoint.y, zoom);
cell.push(marker);
gridPoint.x = gridPoint.x >> 1;
gridPoint.y = gridPoint.y >> 1;
}
};
/**
* Returns whether or not the given point is visible in the shown bounds. This
* is a helper method that takes care of the corner case, when shownBounds have
* negative minX value.
*
* @param {Point} point a point on a grid.
* @return {Boolean} Whether or not the given point is visible in the currently
* shown bounds.
*/
MarkerManager.prototype.isGridPointVisible_ = function (point) {
var vertical = this.shownBounds_.minY <= point.y &&
point.y <= this.shownBounds_.maxY;
var minX = this.shownBounds_.minX;
var horizontal = minX <= point.x && point.x <= this.shownBounds_.maxX;
if (!horizontal && minX < 0) {
// Shifts the negative part of the rectangle. As point.x is always less
// than grid width, only test shifted minX .. 0 part of the shown bounds.
var width = this.gridWidth_[this.shownBounds_.z];
horizontal = minX + width <= point.x && point.x <= width - 1;
}
return vertical && horizontal;
};
/**
* Reacts to a notification from a marker that it has moved to a new location.
* It scans the grid all all zoom levels and moves the marker from the old grid
* location to a new grid location.
*
* @param {Marker} marker The marker that moved.
* @param {LatLng} oldPoint The old position of the marker.
* @param {LatLng} newPoint The new position of the marker.
*/
MarkerManager.prototype.onMarkerMoved_ = function (marker, oldPoint, newPoint) {
// NOTE: We do not know the minimum or maximum zoom the marker was
// added at, so we start at the absolute maximum. Whenever we successfully
// remove a marker at a given zoom, we add it at the new grid coordinates.
var zoom = this.maxZoom_;
var changed = false;
var oldGrid = this.getTilePoint_(oldPoint, zoom, new google.maps.Size(0, 0, 0, 0));
var newGrid = this.getTilePoint_(newPoint, zoom, new google.maps.Size(0, 0, 0, 0));
while (zoom >= 0 && (oldGrid.x !== newGrid.x || oldGrid.y !== newGrid.y)) {
var cell = this.getGridCellNoCreate_(oldGrid.x, oldGrid.y, zoom);
if (cell) {
if (this.removeFromArray_(cell, marker)) {
this.getGridCellCreate_(newGrid.x, newGrid.y, zoom).push(marker);
}
}
// For the current zoom we also need to update the map. Markers that no
// longer are visible are removed from the map. Markers that moved into
// the shown bounds are added to the map. This also lets us keep the count
// of visible markers up to date.
if (zoom === this.mapZoom_) {
if (this.isGridPointVisible_(oldGrid)) {
if (!this.isGridPointVisible_(newGrid)) {
this.removeOverlay_(marker);
changed = true;
}
} else {
if (this.isGridPointVisible_(newGrid)) {
this.addOverlay_(marker);
changed = true;
}
}
}
oldGrid.x = oldGrid.x >> 1;
oldGrid.y = oldGrid.y >> 1;
newGrid.x = newGrid.x >> 1;
newGrid.y = newGrid.y >> 1;
--zoom;
}
if (changed) {
this.notifyListeners_();
}
};
/**
* Removes marker from the manager and from the map
* (if it's currently visible).
* @param {GMarker} marker The marker to delete.
*/
MarkerManager.prototype.removeMarker = function (marker) {
var zoom = this.maxZoom_;
var changed = false;
var point = marker.getPosition();
var grid = this.getTilePoint_(point, zoom, new google.maps.Size(0, 0, 0, 0));
while (zoom >= 0) {
var cell = this.getGridCellNoCreate_(grid.x, grid.y, zoom);
if (cell) {
this.removeFromArray_(cell, marker);
}
// For the current zoom we also need to update the map. Markers that no
// longer are visible are removed from the map. This also lets us keep the count
// of visible markers up to date.
if (zoom === this.mapZoom_) {
if (this.isGridPointVisible_(grid)) {
this.removeOverlay_(marker);
changed = true;
}
}
grid.x = grid.x >> 1;
grid.y = grid.y >> 1;
--zoom;
}
if (changed) {
this.notifyListeners_();
}
this.numMarkers_[marker.MarkerManager_minZoom]--;
};
/**
* Add many markers at once.
* Does not actually update the map, just the internal grid.
*
* @param {Array of Marker} markers The markers to add.
* @param {Number} minZoom The minimum zoom level to display the markers.
* @param {Number} opt_maxZoom The maximum zoom level to display the markers.
*/
MarkerManager.prototype.addMarkers = function (markers, minZoom, opt_maxZoom) {
var maxZoom = this.getOptMaxZoom_(opt_maxZoom);
for (var i = markers.length - 1; i >= 0; i--) {
this.addMarkerBatch_(markers[i], minZoom, maxZoom);
}
this.numMarkers_[minZoom] += markers.length;
};
/**
* Returns the value of the optional maximum zoom. This method is defined so
* that we have just one place where optional maximum zoom is calculated.
*
* @param {Number} opt_maxZoom The optinal maximum zoom.
* @return The maximum zoom.
*/
MarkerManager.prototype.getOptMaxZoom_ = function (opt_maxZoom) {
return opt_maxZoom || this.maxZoom_;
};
/**
* Calculates the total number of markers potentially visible at a given
* zoom level.
*
* @param {Number} zoom The zoom level to check.
*/
MarkerManager.prototype.getMarkerCount = function (zoom) {
var total = 0;
for (var z = 0; z <= zoom; z++) {
total += this.numMarkers_[z];
}
return total;
};
/**
* Returns a marker given latitude, longitude and zoom. If the marker does not
* exist, the method will return a new marker. If a new marker is created,
* it will NOT be added to the manager.
*
* @param {Number} lat - the latitude of a marker.
* @param {Number} lng - the longitude of a marker.
* @param {Number} zoom - the zoom level
* @return {GMarker} marker - the marker found at lat and lng
*/
MarkerManager.prototype.getMarker = function (lat, lng, zoom) {
var mPoint = new google.maps.LatLng(lat, lng);
var gridPoint = this.getTilePoint_(mPoint, zoom, new google.maps.Size(0, 0, 0, 0));
var marker = new google.maps.Marker({position: mPoint});
var cellArray = this.getGridCellNoCreate_(gridPoint.x, gridPoint.y, zoom);
if (cellArray !== undefined) {
for (var i = 0; i < cellArray.length; i++)
{
if (lat === cellArray[i].getLatLng().lat() && lng === cellArray[i].getLatLng().lng()) {
marker = cellArray[i];
}
}
}
return marker;
};
/**
* Add a single marker to the map.
*
* @param {Marker} marker The marker to add.
* @param {Number} minZoom The minimum zoom level to display the marker.
* @param {Number} opt_maxZoom The maximum zoom level to display the marker.
*/
MarkerManager.prototype.addMarker = function (marker, minZoom, opt_maxZoom) {
var maxZoom = this.getOptMaxZoom_(opt_maxZoom);
this.addMarkerBatch_(marker, minZoom, maxZoom);
var gridPoint = this.getTilePoint_(marker.getPosition(), this.mapZoom_, new google.maps.Size(0, 0, 0, 0));
if (this.isGridPointVisible_(gridPoint) &&
minZoom <= this.shownBounds_.z &&
this.shownBounds_.z <= maxZoom) {
this.addOverlay_(marker);
this.notifyListeners_();
}
this.numMarkers_[minZoom]++;
};
/**
* Helper class to create a bounds of INT ranges.
* @param bounds Array.<Object.<string, number>> Bounds object.
* @constructor
*/
function GridBounds(bounds) {
// [sw, ne]
this.minX = Math.min(bounds[0].x, bounds[1].x);
this.maxX = Math.max(bounds[0].x, bounds[1].x);
this.minY = Math.min(bounds[0].y, bounds[1].y);
this.maxY = Math.max(bounds[0].y, bounds[1].y);
}
/**
* Returns true if this bounds equal the given bounds.
* @param {GridBounds} gridBounds GridBounds The bounds to test.
* @return {Boolean} This Bounds equals the given GridBounds.
*/
GridBounds.prototype.equals = function (gridBounds) {
if (this.maxX === gridBounds.maxX && this.maxY === gridBounds.maxY && this.minX === gridBounds.minX && this.minY === gridBounds.minY) {
return true;
} else {
return false;
}
};
/**
* Returns true if this bounds (inclusively) contains the given point.
* @param {Point} point The point to test.
* @return {Boolean} This Bounds contains the given Point.
*/
GridBounds.prototype.containsPoint = function (point) {
var outer = this;
return (outer.minX <= point.x && outer.maxX >= point.x && outer.minY <= point.y && outer.maxY >= point.y);
};
/**
* Get a cell in the grid, creating it first if necessary.
*
* Optimization candidate
*
* @param {Number} x The x coordinate of the cell.
* @param {Number} y The y coordinate of the cell.
* @param {Number} z The z coordinate of the cell.
* @return {Array} The cell in the array.
*/
MarkerManager.prototype.getGridCellCreate_ = function (x, y, z) {
var grid = this.grid_[z];
if (x < 0) {
x += this.gridWidth_[z];
}
var gridCol = grid[x];
if (!gridCol) {
gridCol = grid[x] = [];
return (gridCol[y] = []);
}
var gridCell = gridCol[y];
if (!gridCell) {
return (gridCol[y] = []);
}
return gridCell;
};
/**
* Get a cell in the grid, returning undefined if it does not exist.
*
* NOTE: Optimized for speed -- otherwise could combine with getGridCellCreate_.
*
* @param {Number} x The x coordinate of the cell.
* @param {Number} y The y coordinate of the cell.
* @param {Number} z The z coordinate of the cell.
* @return {Array} The cell in the array.
*/
MarkerManager.prototype.getGridCellNoCreate_ = function (x, y, z) {
var grid = this.grid_[z];
if (x < 0) {
x += this.gridWidth_[z];
}
var gridCol = grid[x];
return gridCol ? gridCol[y] : undefined;
};
/**
* Turns at geographical bounds into a grid-space bounds.
*
* @param {LatLngBounds} bounds The geographical bounds.
* @param {Number} zoom The zoom level of the bounds.
* @param {google.maps.Size} swPadding The padding in pixels to extend beyond the
* given bounds.
* @param {google.maps.Size} nePadding The padding in pixels to extend beyond the
* given bounds.
* @return {GridBounds} The bounds in grid space.
*/
MarkerManager.prototype.getGridBounds_ = function (bounds, zoom, swPadding, nePadding) {
zoom = Math.min(zoom, this.maxZoom_);
var bl = bounds.getSouthWest();
var tr = bounds.getNorthEast();
var sw = this.getTilePoint_(bl, zoom, swPadding);
var ne = this.getTilePoint_(tr, zoom, nePadding);
var gw = this.gridWidth_[zoom];
// Crossing the prime meridian requires correction of bounds.
if (tr.lng() < bl.lng() || ne.x < sw.x) {
sw.x -= gw;
}
if (ne.x - sw.x + 1 >= gw) {
// Computed grid bounds are larger than the world; truncate.
sw.x = 0;
ne.x = gw - 1;
}
var gridBounds = new GridBounds([sw, ne]);
gridBounds.z = zoom;
return gridBounds;
};
/**
* Gets the grid-space bounds for the current map viewport.
*
* @return {Bounds} The bounds in grid space.
*/
MarkerManager.prototype.getMapGridBounds_ = function () {
return this.getGridBounds_(this.map_.getBounds(), this.mapZoom_, this.swPadding_, this.nePadding_);
};
/**
* Event listener for map:movend.
* NOTE: Use a timeout so that the user is not blocked
* from moving the map.
*
* Removed this because a a lack of a scopy override/callback function on events.
*/
MarkerManager.prototype.onMapMoveEnd_ = function () {
this.objectSetTimeout_(this, this.updateMarkers_, 0);
};
/**
* Call a function or evaluate an expression after a specified number of
* milliseconds.
*
* Equivalent to the standard window.setTimeout function, but the given
* function executes as a method of this instance. So the function passed to
* objectSetTimeout can contain references to this.
* objectSetTimeout(this, function () { alert(this.x) }, 1000);
*
* @param {Object} object The target object.
* @param {Function} command The command to run.
* @param {Number} milliseconds The delay.
* @return {Boolean} Success.
*/
MarkerManager.prototype.objectSetTimeout_ = function (object, command, milliseconds) {
return window.setTimeout(function () {
command.call(object);
}, milliseconds);
};
/**
* Is this layer visible?
*
* Returns visibility setting
*
* @return {Boolean} Visible
*/
MarkerManager.prototype.visible = function () {
return this.show_ ? true : false;
};
/**
* Returns true if the manager is hidden.
* Otherwise returns false.
* @return {Boolean} Hidden
*/
MarkerManager.prototype.isHidden = function () {
return !this.show_;
};
/**
* Shows the manager if it's currently hidden.
*/
MarkerManager.prototype.show = function () {
this.show_ = true;
this.refresh();
};
/**
* Hides the manager if it's currently visible
*/
MarkerManager.prototype.hide = function () {
this.show_ = false;
this.refresh();
};
/**
* Toggles the visibility of the manager.
*/
MarkerManager.prototype.toggle = function () {
this.show_ = !this.show_;
this.refresh();
};
/**
* Refresh forces the marker-manager into a good state.
* <ol>
* <li>If never before initialized, shows all the markers.</li>
* <li>If previously initialized, removes and re-adds all markers.</li>
* </ol>
*/
MarkerManager.prototype.refresh = function () {
if (this.shownMarkers_ > 0) {
this.processAll_(this.shownBounds_, this.removeOverlay_);
}
// An extra check on this.show_ to increase performance (no need to processAll_)
if (this.show_) {
this.processAll_(this.shownBounds_, this.addOverlay_);
}
this.notifyListeners_();
};
/**
* After the viewport may have changed, add or remove markers as needed.
*/
MarkerManager.prototype.updateMarkers_ = function () {
this.mapZoom_ = this.map_.getZoom();
var newBounds = this.getMapGridBounds_();
// If the move does not include new grid sections,
// we have no work to do:
if (newBounds.equals(this.shownBounds_) && newBounds.z === this.shownBounds_.z) {
return;
}
if (newBounds.z !== this.shownBounds_.z) {
this.processAll_(this.shownBounds_, this.removeOverlay_);
if (this.show_) { // performance
this.processAll_(newBounds, this.addOverlay_);
}
} else {
// Remove markers:
this.rectangleDiff_(this.shownBounds_, newBounds, this.removeCellMarkers_);
// Add markers:
if (this.show_) { // performance
this.rectangleDiff_(newBounds, this.shownBounds_, this.addCellMarkers_);
}
}
this.shownBounds_ = newBounds;
this.notifyListeners_();
};
/**
* Notify listeners when the state of what is displayed changes.
*/
MarkerManager.prototype.notifyListeners_ = function () {
google.maps.event.trigger(this, 'changed', this.shownBounds_, this.shownMarkers_);
};
/**
* Process all markers in the bounds provided, using a callback.
*
* @param {Bounds} bounds The bounds in grid space.
* @param {Function} callback The function to call for each marker.
*/
MarkerManager.prototype.processAll_ = function (bounds, callback) {
for (var x = bounds.minX; x <= bounds.maxX; x++) {
for (var y = bounds.minY; y <= bounds.maxY; y++) {
this.processCellMarkers_(x, y, bounds.z, callback);
}
}
};
/**
* Process all markers in the grid cell, using a callback.
*
* @param {Number} x The x coordinate of the cell.
* @param {Number} y The y coordinate of the cell.
* @param {Number} z The z coordinate of the cell.
* @param {Function} callback The function to call for each marker.
*/
MarkerManager.prototype.processCellMarkers_ = function (x, y, z, callback) {
var cell = this.getGridCellNoCreate_(x, y, z);
if (cell) {
for (var i = cell.length - 1; i >= 0; i--) {
callback(cell[i]);
}
}
};
/**
* Remove all markers in a grid cell.
*
* @param {Number} x The x coordinate of the cell.
* @param {Number} y The y coordinate of the cell.
* @param {Number} z The z coordinate of the cell.
*/
MarkerManager.prototype.removeCellMarkers_ = function (x, y, z) {
this.processCellMarkers_(x, y, z, this.removeOverlay_);
};
/**
* Add all markers in a grid cell.
*
* @param {Number} x The x coordinate of the cell.
* @param {Number} y The y coordinate of the cell.
* @param {Number} z The z coordinate of the cell.
*/
MarkerManager.prototype.addCellMarkers_ = function (x, y, z) {
this.processCellMarkers_(x, y, z, this.addOverlay_);
};
/**
* Use the rectangleDiffCoords_ function to process all grid cells
* that are in bounds1 but not bounds2, using a callback, and using
* the current MarkerManager object as the instance.
*
* Pass the z parameter to the callback in addition to x and y.
*
* @param {Bounds} bounds1 The bounds of all points we may process.
* @param {Bounds} bounds2 The bounds of points to exclude.
* @param {Function} callback The callback function to call
* for each grid coordinate (x, y, z).
*/
MarkerManager.prototype.rectangleDiff_ = function (bounds1, bounds2, callback) {
var me = this;
me.rectangleDiffCoords_(bounds1, bounds2, function (x, y) {
callback.apply(me, [x, y, bounds1.z]);
});
};
/**
* Calls the function for all points in bounds1, not in bounds2
*
* @param {Bounds} bounds1 The bounds of all points we may process.
* @param {Bounds} bounds2 The bounds of points to exclude.
* @param {Function} callback The callback function to call
* for each grid coordinate.
*/
MarkerManager.prototype.rectangleDiffCoords_ = function (bounds1, bounds2, callback) {
var minX1 = bounds1.minX;
var minY1 = bounds1.minY;
var maxX1 = bounds1.maxX;
var maxY1 = bounds1.maxY;
var minX2 = bounds2.minX;
var minY2 = bounds2.minY;
var maxX2 = bounds2.maxX;
var maxY2 = bounds2.maxY;
var x, y;
for (x = minX1; x <= maxX1; x++) { // All x in R1
// All above:
for (y = minY1; y <= maxY1 && y < minY2; y++) { // y in R1 above R2
callback(x, y);
}
// All below:
for (y = Math.max(maxY2 + 1, minY1); // y in R1 below R2
y <= maxY1; y++) {
callback(x, y);
}
}
for (y = Math.max(minY1, minY2);
y <= Math.min(maxY1, maxY2); y++) { // All y in R2 and in R1
// Strictly left:
for (x = Math.min(maxX1 + 1, minX2) - 1;
x >= minX1; x--) { // x in R1 left of R2
callback(x, y);
}
// Strictly right:
for (x = Math.max(minX1, maxX2 + 1); // x in R1 right of R2
x <= maxX1; x++) {
callback(x, y);
}
}
};
/**
* Removes value from array. O(N).
*
* @param {Array} array The array to modify.
* @param {any} value The value to remove.
* @param {Boolean} opt_notype Flag to disable type checking in equality.
* @return {Number} The number of instances of value that were removed.
*/
MarkerManager.prototype.removeFromArray_ = function (array, value, opt_notype) {
var shift = 0;
for (var i = 0; i < array.length; ++i) {
if (array[i] === value || (opt_notype && array[i] === value)) {
array.splice(i--, 1);
shift++;
}
}
return shift;
};
/**
* Projection overlay helper. Helps in calculating
* that markers get into the right grid.
* @constructor
* @param {Map} map The map to manage.
**/
function ProjectionHelperOverlay(map) {
this.setMap(map);
var TILEFACTOR = 8;
var TILESIDE = 1 << TILEFACTOR;
var RADIUS = 7;
this._map = map;
this._zoom = -1;
this._X0 =
this._Y0 =
this._X1 =
this._Y1 = -1;
}
if (typeof(google) != 'undefined' && google.maps) { // make sure it exists -- amalo
ProjectionHelperOverlay.prototype = new google.maps.OverlayView();
}
/**
* Helper function to convert Lng to X
* @private
* @param {float} lng
**/
ProjectionHelperOverlay.prototype.LngToX_ = function (lng) {
return (1 + lng / 180);
};
/**
* Helper function to convert Lat to Y
* @private
* @param {float} lat
**/
ProjectionHelperOverlay.prototype.LatToY_ = function (lat) {
var sinofphi = Math.sin(lat * Math.PI / 180);
return (1 - 0.5 / Math.PI * Math.log((1 + sinofphi) / (1 - sinofphi)));
};
/**
* Old school LatLngToPixel
* @param {LatLng} latlng google.maps.LatLng object
* @param {Number} zoom Zoom level
* @return {position} {x: pixelPositionX, y: pixelPositionY}
**/
ProjectionHelperOverlay.prototype.LatLngToPixel = function (latlng, zoom) {
var map = this._map;
var div = this.getProjection().fromLatLngToDivPixel(latlng);
var abs = {x: ~~(0.5 + this.LngToX_(latlng.lng()) * (2 << (zoom + 6))), y: ~~(0.5 + this.LatToY_(latlng.lat()) * (2 << (zoom + 6)))};
return abs;
};
/**
* Draw function only triggers a ready event for
* MarkerManager to know projection can proceed to
* initialize.
*/
ProjectionHelperOverlay.prototype.draw = function () {
if (!this.ready) {
this.ready = true;
google.maps.event.trigger(this, 'ready');
}
};

5
compile-dev Executable file
View File

@ -0,0 +1,5 @@
#!/bin/sh
# -Wwrite-strings
# -Wconversion
CFLAGS="-ggdb -std=c89 -pedantic -Wnested-externs -Wmissing-declarations -Wmissing-prototypes -Wcast-qual -Wcast-align -Wbad-function-cast -Wshadow -Wundef -Wdeclaration-after-statement -Wstrict-overflow=4 -Wmissing-include-dirs -Winit-self -Wextra -Wall -Werror -Wno-overlength-strings -Wno-long-long -Wno-unused-parameter -Wno-missing-field-initializers" exec make clean compile

190
docs/BENCHMARKS Normal file
View File

@ -0,0 +1,190 @@
$ python3.3 -OO bench.py bench/*.js
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
slimit_0_7 not available for python 3...
Python Release: 3.3.2
Benchmarking 'bench/apiviewer.js'... (953.2 KiB)
Timing simple_port ... (951.5 KiB *) 3072.57 ms
Timing jsmin_2_0_2 ... (951.4 KiB <) 617.54 ms (factor: 4.98)
Timing rjsmin ... (951.5 KiB =) 87.38 ms (factor: 35.16, 7.07)
Timing _rjsmin ... (951.5 KiB =) 3.54 ms (factor: 868.91, 174.64, 24.71)
Benchmarking 'bench/bootstrap.js'... (49.0 KiB)
Timing simple_port ... ( 26.4 KiB *) 130.17 ms
Timing jsmin_2_0_2 ... ( 26.4 KiB >) 27.26 ms (factor: 4.78)
Timing rjsmin ... ( 26.4 KiB >) 21.41 ms (factor: 6.08, 1.27)
Timing _rjsmin ... ( 26.4 KiB >) 0.24 ms (factor: 543.67, 113.84, 89.44)
Benchmarking 'bench/jquery-1.7.1.js'... (242.4 KiB)
Timing simple_port ... (135.9 KiB *) 682.02 ms
Timing jsmin_2_0_2 ... (136.5 KiB >) 142.79 ms (factor: 4.78)
Timing rjsmin ... (135.9 KiB =) 143.68 ms (factor: 4.75, 0.99)
Timing _rjsmin ... (135.9 KiB =) 1.28 ms (factor: 533.42, 111.68, 112.37)
Benchmarking 'bench/knockout-2.0.0.js'... (38.9 KiB)
Timing simple_port ... ( 38.6 KiB *) 122.96 ms
Timing jsmin_2_0_2 ... ( 38.6 KiB >) 26.48 ms (factor: 4.64)
Timing rjsmin ... ( 38.6 KiB >) 4.81 ms (factor: 25.58, 5.51)
Timing _rjsmin ... ( 38.6 KiB >) 0.14 ms (factor: 874.54, 188.31, 34.19)
Benchmarking 'bench/markermanager.js'... (28.6 KiB)
Timing simple_port ... ( 11.6 KiB *) 63.52 ms
Timing jsmin_2_0_2 ... ( 11.6 KiB >) 14.63 ms (factor: 4.34)
Timing rjsmin ... ( 11.6 KiB =) 9.14 ms (factor: 6.95, 1.60)
Timing _rjsmin ... ( 11.6 KiB =) 0.12 ms (factor: 524.54, 120.83, 75.46)
$ python3.2 -OO bench.py bench/*.js
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
slimit_0_7 not available for python 3...
Python Release: 3.2.3
Benchmarking 'bench/apiviewer.js'... (953.2 KiB)
Timing simple_port ... (951.5 KiB *) 2880.13 ms
Timing jsmin_2_0_2 ... (951.4 KiB <) 503.52 ms (factor: 5.72)
Timing rjsmin ... (951.5 KiB =) 75.16 ms (factor: 38.32, 6.70)
Timing _rjsmin ... (951.5 KiB =) 2.60 ms (factor: 1108.00, 193.71, 28.92)
Benchmarking 'bench/bootstrap.js'... (49.0 KiB)
Timing simple_port ... ( 26.4 KiB *) 118.18 ms
Timing jsmin_2_0_2 ... ( 26.4 KiB >) 21.84 ms (factor: 5.41)
Timing rjsmin ... ( 26.4 KiB >) 18.23 ms (factor: 6.48, 1.20)
Timing _rjsmin ... ( 26.4 KiB >) 0.19 ms (factor: 618.06, 114.22, 95.31)
Benchmarking 'bench/jquery-1.7.1.js'... (242.4 KiB)
Timing simple_port ... (135.9 KiB *) 620.88 ms
Timing jsmin_2_0_2 ... (136.5 KiB >) 115.48 ms (factor: 5.38)
Timing rjsmin ... (135.9 KiB =) 122.68 ms (factor: 5.06, 0.94)
Timing _rjsmin ... (135.9 KiB =) 1.11 ms (factor: 560.97, 104.34, 110.84)
Benchmarking 'bench/knockout-2.0.0.js'... (38.9 KiB)
Timing simple_port ... ( 38.6 KiB *) 115.03 ms
Timing jsmin_2_0_2 ... ( 38.6 KiB >) 21.07 ms (factor: 5.46)
Timing rjsmin ... ( 38.6 KiB >) 3.94 ms (factor: 29.18, 5.35)
Timing _rjsmin ... ( 38.6 KiB >) 0.10 ms (factor: 1158.40, 212.23, 39.70)
Benchmarking 'bench/markermanager.js'... (28.6 KiB)
Timing simple_port ... ( 11.6 KiB *) 56.81 ms
Timing jsmin_2_0_2 ... ( 11.6 KiB >) 11.61 ms (factor: 4.89)
Timing rjsmin ... ( 11.6 KiB =) 7.61 ms (factor: 7.46, 1.52)
Timing _rjsmin ... ( 11.6 KiB =) 0.09 ms (factor: 642.56, 131.31, 86.11)
i$ python3.1 -OO bench.py bench/*.js
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
slimit_0_7 not available for python 3...
Python Release: 3.1.5
Benchmarking 'bench/apiviewer.js'... (953.2 KiB)
Timing simple_port ... (951.5 KiB *) 3006.80 ms
Timing jsmin_2_0_2 ... (951.4 KiB <) 505.56 ms (factor: 5.95)
Timing rjsmin ... (951.5 KiB =) 83.47 ms (factor: 36.02, 6.06)
Timing _rjsmin ... (951.5 KiB =) 2.60 ms (factor: 1155.26, 194.24, 32.07)
Benchmarking 'bench/bootstrap.js'... (49.0 KiB)
Timing simple_port ... ( 26.4 KiB *) 123.10 ms
Timing jsmin_2_0_2 ... ( 26.4 KiB >) 21.98 ms (factor: 5.60)
Timing rjsmin ... ( 26.4 KiB >) 19.52 ms (factor: 6.31, 1.13)
Timing _rjsmin ... ( 26.4 KiB >) 0.19 ms (factor: 643.17, 114.86, 101.97)
Benchmarking 'bench/jquery-1.7.1.js'... (242.4 KiB)
Timing simple_port ... (135.9 KiB *) 647.61 ms
Timing jsmin_2_0_2 ... (136.5 KiB >) 116.21 ms (factor: 5.57)
Timing rjsmin ... (135.9 KiB =) 131.60 ms (factor: 4.92, 0.88)
Timing _rjsmin ... (135.9 KiB =) 1.11 ms (factor: 584.97, 104.96, 118.87)
Benchmarking 'bench/knockout-2.0.0.js'... (38.9 KiB)
Timing simple_port ... ( 38.6 KiB *) 120.51 ms
Timing jsmin_2_0_2 ... ( 38.6 KiB >) 21.28 ms (factor: 5.66)
Timing rjsmin ... ( 38.6 KiB >) 4.34 ms (factor: 27.78, 4.91)
Timing _rjsmin ... ( 38.6 KiB >) 0.10 ms (factor: 1212.43, 214.10, 43.64)
Benchmarking 'bench/markermanager.js'... (28.6 KiB)
Timing simple_port ... ( 11.6 KiB *) 59.60 ms
Timing jsmin_2_0_2 ... ( 11.6 KiB >) 11.63 ms (factor: 5.13)
Timing rjsmin ... ( 11.6 KiB =) 8.20 ms (factor: 7.27, 1.42)
Timing _rjsmin ... ( 11.6 KiB =) 0.09 ms (factor: 671.95, 131.11, 92.48)
$ python2.7 -OO bench.py bench/*.js
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Python Release: 2.7.3
Benchmarking 'bench/apiviewer.js'... (953.2 KiB)
Timing simple_port ... (951.5 KiB *) 3598.04 ms
Timing jsmin_2_0_2 ... (951.4 KiB <) 733.59 ms (factor: 4.90)
Timing slimit_0_7 ... (944.3 KiB <) 16410.85 ms (factor: 0.22, 0.04)
Timing slimit_0_7_mangle ... (922.8 KiB <) 20213.29 ms (factor: 0.18, 0.04, 0.81)
Timing rjsmin ... (951.5 KiB =) 65.71 ms (factor: 54.76, 11.16, 249.76, 307.64)
Timing _rjsmin ... (951.5 KiB =) 3.17 ms (factor: 1136.32, 231.68, 5182.83, 6383.70, 20.75)
Benchmarking 'bench/bootstrap.js'... (49.0 KiB)
Timing simple_port ... ( 26.4 KiB *) 145.62 ms
Timing jsmin_2_0_2 ... ( 26.4 KiB >) 31.66 ms (factor: 4.60)
Timing slimit_0_7 ... ( 26.5 KiB >) 465.21 ms (factor: 0.31, 0.07)
Timing slimit_0_7_mangle ... ( 22.2 KiB <) 496.30 ms (factor: 0.29, 0.06, 0.94)
Timing rjsmin ... ( 26.4 KiB >) 17.40 ms (factor: 8.37, 1.82, 26.73, 28.52)
Timing _rjsmin ... ( 26.4 KiB >) 0.22 ms (factor: 663.08, 144.16, 2118.35, 2259.92, 79.24)
Benchmarking 'bench/jquery-1.7.1.js'... (242.4 KiB)
Timing simple_port ... (135.9 KiB *) 765.49 ms
Timing jsmin_2_0_2 ... (136.5 KiB >) 171.20 ms (factor: 4.47)
Timing slimit_0_7 ... (134.0 KiB <) 2187.47 ms (factor: 0.35, 0.08)
Timing slimit_0_7_mangle ... ( 95.0 KiB <) 2614.89 ms (factor: 0.29, 0.07, 0.84)
Timing rjsmin ... (135.9 KiB =) 117.15 ms (factor: 6.53, 1.46, 18.67, 22.32)
Timing _rjsmin ... (135.9 KiB =) 1.22 ms (factor: 628.38, 140.53, 1795.66, 2146.52, 96.17)
Benchmarking 'bench/knockout-2.0.0.js'... (38.9 KiB)
Timing simple_port ... ( 38.6 KiB *) 146.34 ms
Timing jsmin_2_0_2 ... ( 38.6 KiB >) 31.57 ms (factor: 4.64)
Timing slimit_0_7 ... ( 39.0 KiB >) 858.22 ms (factor: 0.17, 0.04)
Timing slimit_0_7_mangle ... ( 38.9 KiB >) 1036.05 ms (factor: 0.14, 0.03, 0.83)
Timing rjsmin ... ( 38.6 KiB >) 3.73 ms (factor: 39.29, 8.47, 230.39, 278.13)
Timing _rjsmin ... ( 38.6 KiB >) 0.14 ms (factor: 1057.38, 228.08, 6200.89, 7485.80, 26.91)
Benchmarking 'bench/markermanager.js'... (28.6 KiB)
Timing simple_port ... ( 11.6 KiB *) 72.23 ms
Timing jsmin_2_0_2 ... ( 11.6 KiB >) 17.08 ms (factor: 4.23)
Timing slimit_0_7 ... ( 11.5 KiB <) 177.14 ms (factor: 0.41, 0.10)
Timing slimit_0_7_mangle ... ( 9.3 KiB <) 202.09 ms (factor: 0.36, 0.08, 0.88)
Timing rjsmin ... ( 11.6 KiB =) 7.32 ms (factor: 9.86, 2.33, 24.18, 27.59)
Timing _rjsmin ... ( 11.6 KiB =) 0.10 ms (factor: 698.55, 165.22, 1713.12, 1954.45, 70.84)
$ python2.6 -OO bench.py bench/*.js
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
slimit_0_7 not installed for python 2.6...
Python Release: 2.6.8
Benchmarking 'bench/apiviewer.js'... (953.2 KiB)
Timing simple_port ... (951.5 KiB *) 3400.55 ms
Timing jsmin_2_0_2 ... (951.4 KiB <) 775.37 ms (factor: 4.39)
Timing rjsmin ... (951.5 KiB =) 68.39 ms (factor: 49.72, 11.34)
Timing _rjsmin ... (951.5 KiB =) 3.16 ms (factor: 1074.49, 245.00, 21.61)
Benchmarking 'bench/bootstrap.js'... (49.0 KiB)
Timing simple_port ... ( 26.4 KiB *) 138.10 ms
Timing jsmin_2_0_2 ... ( 26.4 KiB >) 33.80 ms (factor: 4.09)
Timing rjsmin ... ( 26.4 KiB >) 17.47 ms (factor: 7.90, 1.93)
Timing _rjsmin ... ( 26.4 KiB >) 0.22 ms (factor: 629.45, 154.05, 79.64)
Benchmarking 'bench/jquery-1.7.1.js'... (242.4 KiB)
Timing simple_port ... (135.9 KiB *) 728.82 ms
Timing jsmin_2_0_2 ... (136.5 KiB >) 182.44 ms (factor: 3.99)
Timing rjsmin ... (135.9 KiB =) 118.96 ms (factor: 6.13, 1.53)
Timing _rjsmin ... (135.9 KiB =) 1.22 ms (factor: 597.89, 149.67, 97.59)
Benchmarking 'bench/knockout-2.0.0.js'... (38.9 KiB)
Timing simple_port ... ( 38.6 KiB *) 135.16 ms
Timing jsmin_2_0_2 ... ( 38.6 KiB >) 33.30 ms (factor: 4.06)
Timing rjsmin ... ( 38.6 KiB >) 3.73 ms (factor: 36.21, 8.92)
Timing _rjsmin ... ( 38.6 KiB >) 0.14 ms (factor: 981.50, 241.80, 27.11)
Benchmarking 'bench/markermanager.js'... (28.6 KiB)
Timing simple_port ... ( 11.6 KiB *) 68.13 ms
Timing jsmin_2_0_2 ... ( 11.6 KiB >) 18.29 ms (factor: 3.72)
Timing rjsmin ... ( 11.6 KiB =) 7.52 ms (factor: 9.06, 2.43)
Timing _rjsmin ... ( 11.6 KiB =) 0.10 ms (factor: 660.88, 177.46, 72.95)
# vim: nowrap

58
docs/CHANGES Normal file
View File

@ -0,0 +1,58 @@
Changes with version 1.0.7
*) Fix inconsistency between Python and C (Python implementation was buggy).
Spotted by: Dave Smith <dave thesmithfam.org>
*) Added support for jython 2.7
Changes with version 1.0.6
*) Added compat option to setup.py supporting the pip installer
*) Added support for pypy (1.9, 2.0)
*) Added support for jython (2.5)
Changes with version 1.0.5
*) Newline removal before ! operator was made more sensible.
Changes with version 1.0.4
*) Added support for Python 3.3
*) Collapsion protection was reduced to "+ +" and "- -" sequences (which
still includes longer sequences like "+ ++")
Changes with version 1.0.3
*) "+ ++" and "- --" sequences are no longer collapsed. They were before,
because the original jsmin collapsed them, too.
*) Updated benchmarks, added slimit and removed jsmin v8 (because it produced
invalid results).
*) Removed "classic" regex variant.
Changes with version 1.0.2
*) Although it should work, python 2.3 is no longer supported.
(No suitable test environment)
*) "return /regex/" is now recognized as regex expression. It wasn't before,
because the original jsmin ignored that, too.
Changes with version 1.0.1
*) Add C extension reimplementing the regex from rjsmin.py
Changes with version 1.0.0
*) First stable release.

19
docs/CLASSIFIERS Normal file
View File

@ -0,0 +1,19 @@
Development Status :: 5 - Production/Stable
Environment :: Web Environment
Intended Audience :: Developers
License :: OSI Approved
License :: OSI Approved :: Apache License, Version 2.0
Operating System :: OS Independent
Programming Language :: C
Programming Language :: Python
Programming Language :: Python :: 2
Programming Language :: Python :: 3
Programming Language :: Python :: Implementation :: CPython
Programming Language :: Python :: Implementation :: Jython
Programming Language :: Python :: Implementation :: PyPy
Topic :: Internet :: WWW/HTTP :: Dynamic Content
Topic :: Software Development :: Libraries
Topic :: Software Development :: Libraries :: Python Modules
Topic :: Text Processing
Topic :: Text Processing :: Filters
Topic :: Utilities

70
docs/DESCRIPTION Normal file
View File

@ -0,0 +1,70 @@
=====================
Javascript Minifier
=====================
rJSmin is a javascript minifier written in python.
The minifier is based on the semantics of `jsmin.c by Douglas Crockford`_\.
The module is a re-implementation aiming for speed, so it can be used at
runtime (rather than during a preprocessing step). Usually it produces the
same results as the original ``jsmin.c``. It differs in the following ways:
- there is no error detection: unterminated string, regex and comment
literals are treated as regular javascript code and minified as such.
- Control characters inside string and regex literals are left untouched; they
are not converted to spaces (nor to \n)
- Newline characters are not allowed inside string and regex literals, except
for line continuations in string literals (ECMA-5).
- "return /regex/" is recognized correctly.
- "+ +" and "- -" sequences are not collapsed to '++' or '--'
- Newlines before ! operators are removed more sensibly
- rJSmin does not handle streams, but only complete strings. (However, the
module provides a "streamy" interface).
Since most parts of the logic are handled by the regex engine it's way
faster than the original python port of ``jsmin.c`` by Baruch Even. The speed
factor varies between about 6 and 55 depending on input and python version
(it gets faster the more compressed the input already is). Compared to the
speed-refactored python port by Dave St.Germain the performance gain is less
dramatic but still between 1.2 and 7. See the docs/BENCHMARKS file for
details.
rjsmin.c is a reimplementation of rjsmin.py in C and speeds it up even more.
Both python 2 (>=2.4) and python 3 are supported.
.. _jsmin.c by Douglas Crockford: http://www.crockford.com/javascript/jsmin.c
Copyright and License
~~~~~~~~~~~~~~~~~~~~~
Copyright 2011 - 2013
André Malo or his licensors, as applicable.
The whole package (except for the files in the bench/ directory) is
distributed under the Apache License Version 2.0. You'll find a copy in the
root directory of the distribution or online at:
<http://www.apache.org/licenses/LICENSE-2.0>.
Bugs
~~~~
No bugs, of course. ;-)
But if you've found one or have an idea how to improve rjsmin, please
send a mail to <rjsmin-bugs@perlig.de>.
Author Information
~~~~~~~~~~~~~~~~~~
André "nd" Malo <nd perlig.de>
GPG: 0x8103A37E
If God intended people to be naked, they would be born that way.
-- Oscar Wilde
.. vim:tw=72 syntax=rest

1
docs/PROVIDES Normal file
View File

@ -0,0 +1 @@
rjsmin (1.0)

1
docs/SUMMARY Normal file
View File

@ -0,0 +1 @@
Javascript Minifier

View File

@ -0,0 +1,23 @@
.ci {
font-variant: small-caps;
font-family: serif;
font-style: normal;
}
table.benchmark {
width: 40em;
}
table.benchmark th {
text-align: center;
white-space: nowrap;
}
table.benchmark td {
white-space: nowrap;
}
table.benchmark td + td {
text-align: right;
font-family: monospace;
}

View File

@ -0,0 +1,2 @@
{% extends "default/layout.html" %}
{% set css_files = css_files + ['_static/ci.css'] %}

174
docs/_userdoc/benchmark.txt Normal file
View File

@ -0,0 +1,174 @@
.. license:
Copyright 2011 - 2013
André Malo or his licensors, as applicable
Licensed 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.
:orphan:
====================
rJSmin - Benchmark
====================
The following numbers have been measured with the bench.py script
provided in the source distribution. Since the numbers don't vary much
between python minor releases (e.g. 2.6 vs 2.7), only the benchmarks for
2.7 and 3.3 are given below. The :file:`docs/BENCHMARKS` file in the source
distribution contains the full list.
Here's the list of benchmarked implementations:
- Simple port is the original jsmin.py port by Baruch Even
- jsmin 2.0.2 is a speed-refactored python port by Dave St.Germain
- slimit 0.7 is a minifier based on a parse/generate-iteration. It's
available for python 2 only.
- slimit 0.7 (mangle) is slimit 0.7 with name mangeling enabled
- |rjsmin| is this very project
- _\ |rjsmin| is the C reimplementation of |rjsmin|
Note that jsmin 2.0.2 and slimit produce output different from
the original jsmin.c. Also the simple port was modified to use cStringIO
if available (it's faster then) or io (for python 3).
And here's a list of the benchmarked javascript files:
- apiviewer is a file from the qooxdoo framework. Very big and already
compressed.
- bootstrap is the popular twitter toolkit, version 2.0.4
- jquery is jquery-1.7.1.js; the uncompressed development download.
- knockout is knockout-2.0.0.js, the compressed download.
- markermanager is the V3 port of the google maps markermanager.
Inside the parentheses are size information in KiB (actually: number of
characters/1024). The sign behind the size value denotes the size difference
in relation to the simple port (i.e. jsmin itself).
Python 3.3.2
~~~~~~~~~~~~
.. rst-class:: benchmark
+---------------------+-----------------------+----------------------+
| Name | apiviewer (953.2) | bootstrap (49.0) |
+=====================+=======================+======================+
| Simple Port | 3072.57 ms (951.5 \*)| 130.17 ms (26.4 \*) |
+---------------------+-----------------------+----------------------+
| jsmin 2.0.2 | 617.54 ms (951.4 <) | 21.93 ms (26.4 >) |
+---------------------+-----------------------+----------------------+
| slimit 0.7 | n/a | n/a |
+---------------------+-----------------------+----------------------+
| slimit 0.7 (mangle) | n/a | n/a |
+---------------------+-----------------------+----------------------+
| |rjsmin| | 87.38 ms (951.5 =) | 21.41 ms (26.4 >) |
+---------------------+-----------------------+----------------------+
| _\ |rjsmin| | 3.54 ms (951.5 =) | 0.24 ms (26.4 >) |
+---------------------+-----------------------+----------------------+
.. rst-class:: benchmark
+---------------------+-----------------------+----------------------+
| Name | jquery (242.4) | knockout (38.9) |
+=====================+=======================+======================+
| Simple Port | 682.02 ms (135.9 \*)| 122.96 ms (38.6 \*) |
+---------------------+-----------------------+----------------------+
| jsmin 2.0.2 | 142.79 ms (136.5 >) | 26.48 ms (38.6 >) |
+---------------------+-----------------------+----------------------+
| slimit 0.7 | n/a | n/a |
+---------------------+-----------------------+----------------------+
| slimit 0.7 (mangle) | n/a | n/a |
+---------------------+-----------------------+----------------------+
| |rjsmin| | 143.68 ms (135.9 =) | 4.81 ms (38.6 >) |
+---------------------+-----------------------+----------------------+
| _\ |rjsmin| | 1.28 ms (135.9 =) | 0.14 ms (38.6 >) |
+---------------------+-----------------------+----------------------+
.. rst-class:: benchmark
+---------------------+-----------------------+----------------------+
| Name | markermanager (28.6) | |
+=====================+=======================+======================+
| Simple Port | 63.52 ms (11.6 \*) | |
+---------------------+-----------------------+----------------------+
| jsmin 2.0.2 | 14.63 ms (11.6 >) | |
+---------------------+-----------------------+----------------------+
| slimit 0.7 | n/a | |
+---------------------+-----------------------+----------------------+
| slimit 0.7 (mangle) | n/a | |
+---------------------+-----------------------+----------------------+
| |rjsmin| | 9.14 ms (11.6 =) | |
+---------------------+-----------------------+----------------------+
| _\ |rjsmin| | 0.12 ms (11.6 =) | |
+---------------------+-----------------------+----------------------+
Python 2.7.3
~~~~~~~~~~~~
.. rst-class:: benchmark
+---------------------+-----------------------+----------------------+
| Name | apiviewer (953.2) | bootstrap (49.0) |
+=====================+=======================+======================+
| Simple Port | 3598.04 ms (951.5 \*)| 145.62 ms (26.4 \*) |
+---------------------+-----------------------+----------------------+
| jsmin 2.0.2 | 733.59 ms (951.4 <) | 31.66 ms (26.4 >) |
+---------------------+-----------------------+----------------------+
| slimit 0.7 | 16410.85 ms (944.3 <) | 465.21 ms (26.5 >) |
+---------------------+-----------------------+----------------------+
| slimit 0.7 (mangle) | 20213.29 ms (922.8 <) | 496.30 ms (22.2 <) |
+---------------------+-----------------------+----------------------+
| |rjsmin| | 65.71 ms (951.5 =) | 17.40 ms (26.4 >) |
+---------------------+-----------------------+----------------------+
| _\ |rjsmin| | 3.17 ms (951.5 =) | 0.22 ms (26.4 >) |
+---------------------+-----------------------+----------------------+
.. rst-class:: benchmark
+---------------------+-----------------------+----------------------+
| Name | jquery (242.4) | knockout (38.9) |
+=====================+=======================+======================+
| Simple Port | 765.49 ms (135.9 \*)| 146.34 ms (38.6 \*) |
+---------------------+-----------------------+----------------------+
| jsmin 2.0.2 | 171.20 ms (136.5 >) | 31.57 ms (38.6 >) |
+---------------------+-----------------------+----------------------+
| slimit 0.7 | 2187.47 ms (134.0 <) | 858.22 ms (39.0 >) |
+---------------------+-----------------------+----------------------+
| slimit 0.7 (mangle) | 2614.89 ms ( 95.0 <) | 1036.05 ms (38.9 >) |
+---------------------+-----------------------+----------------------+
| |rjsmin| | 117.15 ms (135.9 =) | 3.73 ms (38.6 >) |
+---------------------+-----------------------+----------------------+
| _\ |rjsmin| | 1.22 ms (135.9 =) | 0.14 ms (38.6 >) |
+---------------------+-----------------------+----------------------+
.. rst-class:: benchmark
+---------------------+-----------------------+----------------------+
| Name | markermanager (28.6) | |
+=====================+=======================+======================+
| Simple Port | 72.23 ms (11.6 \*) | |
+---------------------+-----------------------+----------------------+
| jsmin 2.0.2 | 17.08 ms (11.6 >) | |
+---------------------+-----------------------+----------------------+
| slimit 0.7 | 177.14 ms (11.5 <) | |
+---------------------+-----------------------+----------------------+
| slimit 0.7 (mangle) | 202.09 ms ( 9.3 <) | |
+---------------------+-----------------------+----------------------+
| |rjsmin| | 7.32 ms (11.6 =) | |
+---------------------+-----------------------+----------------------+
| _\ |rjsmin| | 0.10 ms (11.6 =) | |
+---------------------+-----------------------+----------------------+
.. vim: ft=rest tw=72

228
docs/_userdoc/conf.py Normal file
View File

@ -0,0 +1,228 @@
# -*- coding: utf-8 -*-
#
# This file is execfile()d with the current directory set to its containing dir.
#
# Note that not all possible configuration values are present in this
# autogenerated file.
#
# All configuration values have a default; values that are commented out
# serve to show the default.
import sys, os
# If extensions (or modules to document with autodoc) are in another directory,
# add these directories to sys.path here. If the directory is relative to the
# documentation root, use os.path.abspath to make it absolute, like shown here.
sys.path.append(os.path.abspath('.'))
# -- General configuration -----------------------------------------------------
# Add any Sphinx extension module names here, as strings. They can be extensions
# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
extensions = ['epydoc_sphinx']
# Add any paths that contain templates here, relative to this directory.
templates_path = ['_templates']
# The suffix of source filenames.
source_suffix = '.txt'
# The encoding of source files.
#source_encoding = 'utf-8'
# The master toctree document.
master_doc = 'index'
# General information about the project.
project = u'rJSmin'
copyright = u'2012 Andr\xe9 Malo'
# The version info for the project you're documenting, acts as replacement for
# |version| and |release|, also used in various other places throughout the
# built documents.
#
# The short X.Y version.
version = '1.0'
# The full version, including alpha/beta/rc tags.
release = '1.0.7'
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
#language = None
# There are two options for replacing |today|: either, you set today to some
# non-false value, then it is used:
#today = ''
# Else, today_fmt is used as the format for a strftime call.
#today_fmt = '%B %d, %Y'
# List of documents that shouldn't be included in the build.
unused_docs = ['website_download']
# List of directories, relative to source directory, that shouldn't be searched
# for source files.
exclude_trees = ['_build']
# The reST default role (used for this markup: `text`) to use for all documents.
#default_role = None
# If true, '()' will be appended to :func: etc. cross-reference text.
#add_function_parentheses = True
# If true, the current module name will be prepended to all description
# unit titles (such as .. function::).
#add_module_names = True
# If true, sectionauthor and moduleauthor directives will be shown in the
# output. They are ignored by default.
#show_authors = False
# The name of the Pygments (syntax highlighting) style to use.
pygments_style = 'sphinx'
# A list of ignored prefixes for module index sorting.
#modindex_common_prefix = []
rst_prolog = """
.. role:: product(emphasis)
:class: ci
.. |rjsmin| replace:: :product:`rJSmin`
.. role:: productb(strong)
:class: ci
.. |**rjsmin**| replace:: :productb:`rJSmin`
"""
# -- Options for epydoc extension-----------------------------------------------
epydoc = dict(
rjsmin=os.path.join(os.path.abspath(os.path.pardir), 'apidoc'),
)
# -- Options for HTML output ---------------------------------------------------
# The theme to use for HTML and HTML Help pages. Major themes that come with
# Sphinx are currently 'default' and 'sphinxdoc'.
html_theme = 'default'
# Theme options are theme-specific and customize the look and feel of a theme
# further. For a list of options available for each theme, see the
# documentation.
if html_theme == 'nature':
html_theme_options = {}
elif html_theme == 'agogo':
html_theme_options = dict(
pagewidth='100%',
documentwidth='80%',
sidebarwidth='20%',
)
elif html_theme == 'scrolls':
html_theme_options = {}
elif html_theme == 'haiku':
html_theme_options = {}
else:
html_theme_options = dict(
rightsidebar=True,
)
html_sidebars = {
'**': ['localtoc.html', 'relations.html'],
}
# Add any paths that contain custom themes here, relative to this directory.
#html_theme_path = []
# The name for this set of Sphinx documents. If None, it defaults to
# "<project> v<release> documentation".
#html_title = None
# A shorter title for the navigation bar. Default is the same as html_title.
#html_short_title = None
# The name of an image file (relative to this directory) to place at the top
# of the sidebar.
#html_logo = None
# The name of an image file (within the static path) to use as favicon of the
# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
# pixels large.
#html_favicon = None
# Add any paths that contain custom static files (such as style sheets) here,
# relative to this directory. They are copied after the builtin static files,
# so a file named "default.css" will overwrite the builtin "default.css".
html_static_path = ['_static']
# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
# using the given strftime format.
#html_last_updated_fmt = '%b %d, %Y'
# If true, SmartyPants will be used to convert quotes and dashes to
# typographically correct entities.
#html_use_smartypants = True
# Custom sidebar templates, maps document names to template names.
#html_sidebars = {}
# Additional templates that should be rendered to pages, maps page names to
# template names.
#html_additional_pages = {}
# If false, no module index is generated.
html_use_modindex = False
# If false, no index is generated.
html_use_index = False
# If true, the index is split into individual pages for each letter.
#html_split_index = False
# If true, links to the reST sources are added to the pages.
html_show_sourcelink = False
# If true, an OpenSearch description file will be output, and all pages will
# contain a <link> tag referring to it. The value of this option must be the
# base URL from which the finished HTML is served.
#html_use_opensearch = ''
# If nonempty, this is the file name suffix for HTML files (e.g. ".xhtml").
#html_file_suffix = ''
# Output file base name for HTML help builder.
htmlhelp_basename = 'rJSmindoc'
# -- Options for LaTeX output --------------------------------------------------
# The paper size ('letter' or 'a4').
#latex_paper_size = 'letter'
# The font size ('10pt', '11pt' or '12pt').
#latex_font_size = '10pt'
# Grouping the document tree into LaTeX files. List of tuples
# (source start file, target name, title, author, documentclass [howto/manual]).
latex_documents = [
('index', 'rjsmin.tex', u'rJSmin Documentation',
u'Andr\xe9 "nd" Malo', 'manual'),
]
# The name of an image file (relative to this directory) to place at the top of
# the title page.
#latex_logo = None
# For "manual" documents, if this is true, then toplevel headings are parts,
# not chapters.
#latex_use_parts = False
# Additional stuff for the LaTeX preamble.
#latex_preamble = ''
# Documents to append as an appendix to all manuals.
#latex_appendices = []
# If false, no module index is generated.
#latex_use_modindex = True

View File

@ -0,0 +1,130 @@
# -*- coding: ascii -*-
#
# Copyright 2010, 2011
# Andr\xe9 Malo or his licensors, as applicable
#
# Licensed 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.
import os
import posixpath
from docutils import nodes
from sphinx.util import caption_ref_re
def relpath(path, start=os.path.curdir):
"""Return a relative version of a path - stolen from python2.6 """
if not path:
raise ValueError("no path specified")
start_list = os.path.abspath(start).split(sep)
path_list = os.path.abspath(path).split(sep)
# Work out how much of the filepath is shared by start and path.
i = len(os.path.commonprefix([start_list, path_list]))
rel_list = [os.path.pardir] * (len(start_list)-i) + path_list[i:]
if not rel_list:
return os.path.curdir
return os.path.join(*rel_list)
try:
relpath = os.path.relpath
except AttributeError:
pass
def make_roles(app):
""" Make roles """
epydoc = app.config.epydoc
if epydoc is not None:
for name, basedir in epydoc.iteritems():
app.add_role(name, make_epydoc_role(app, basedir))
def make_epydoc_role(app, epydoc):
""" Make a single role """
try:
fp = open(os.path.join(epydoc, 'api-objects.txt'))
try:
apis = dict([
line.strip().split(None, 1) for line in fp if line.strip()
])
finally:
fp.close()
except IOError:
app.warn("Epydoc description at %s not found" % (epydoc,))
apis = {}
def epydoc_role(role, rawtext, text, lineno, inliner, options={},
content=[]):
""" Actual role callback """
match = caption_ref_re.match(text)
if match:
extra, (text, ref) = True, match.group(1, 2)
text = text.strip()
if text.startswith('|') and text.endswith('|'):
text = text[1:-1]
extra = False
else:
extra, text, ref = False, None, text
if ref.endswith('()'):
ref = ref[:-2].strip()
parens = text is None
else:
parens = False
if '/' in ref:
chunks = ref.split('/', 1)
if not chunks[0]: # Main page
uri = 'index.html'
else:
uri = apis.get(''.join(chunks))
if text is None:
text = chunks[1]
else:
uri = apis.get(ref)
if not text:
text = ref
if parens:
text += '()'
if uri is None:
node = nodes.literal(rawtext, text)
else:
baseuri = relpath(
epydoc,
os.path.dirname(inliner.document.current_source)
).split(os.path.sep)
for idx, elem in enumerate(baseuri):
if elem == os.path.curdir:
baseuri[idx] = '.'
elif elem == os.path.pardir:
baseuri[idx] = '..'
baseuri = '/'.join(baseuri)
uri = posixpath.join(baseuri, uri)
if not extra:
text =u'\u2192\xa0' + text
node = nodes.reference(rawtext, text, refuri=uri, **options)
if not extra:
node = nodes.literal(rawtext, '', node)
return [node], []
return epydoc_role
def setup(app):
app.add_config_value('epydoc', None, 'html')
app.connect('builder-inited', make_roles)

149
docs/_userdoc/index.txt Normal file
View File

@ -0,0 +1,149 @@
.. license:
Copyright 2011 - 2013
André Malo or his licensors, as applicable
Licensed 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.
==============================
rJSmin - Javascript Minifier
==============================
|**rJSmin**| is a javascript minifier written in python.
The minifier is based on the semantics of `jsmin.c by Douglas Crockford`_\.
The module is a re-implementation aiming for :doc:`speed <benchmark>`, so it
can be used at runtime (rather than during a preprocessing step). Usually it
produces the same results as the original ``jsmin.c``. It differs in the
following ways:
- there is no error detection: unterminated string, regex and comment
literals are treated as regular javascript code and minified as such.
- Control characters inside string and regex literals are left untouched; they
are not converted to spaces (nor to \n)
- Newline characters are not allowed inside string and regex literals, except
for line continuations in string literals (ECMA-5).
- "``return /regex/``" is recognized correctly.
- "``+ +``" and "``- -``" sequences are not collapsed to '``++``' or
'``--``'
- Newlines before ``!`` operators are removed more sensibly
- |rJSmin| does not handle streams, but only complete strings. (However, the
module provides a "streamy" interface).
Since most parts of the logic are handled by the regex engine it's way
faster than the original python port of ``jsmin.c`` by Baruch Even. The speed
factor varies between about 6 and 55 depending on input and python version
(it gets faster the more compressed the input already is). Compared to the
speed-refactored python port by Dave St.Germain the performance gain is less
dramatic but still between 1.2 and 7.
|rjsmin| comes with an optional C-reimplementation of the python/regex
implementation, which speeds up the minifying process even more.
|rjsmin| works with both python 2 (starting with python 2.4) and python 3.
.. _jsmin.c by Douglas Crockford: http://www.crockford.com/javascript/jsmin.c
Documentation
~~~~~~~~~~~~~
A :rjsmin:`generated API documentation </>` is available. But you can
just look into the module. It provides a simple function, called
``jsmin`` which takes the script as a string and returns the minified
script as a string.
The module additionally provides a "streamy" interface similar to the
one jsmin.c provides:
.. sourcecode:: console
$ python -mrjsmin <script >minified
Development Status
~~~~~~~~~~~~~~~~~~
|rjsmin| is stable.
License
~~~~~~~
|rjsmin| is available under the terms and conditions of the "Apache License,
Version 2.0." You'll find the detailed licensing terms in the root
directory of the source distribution package or online at
`http://www.apache.org/licenses/LICENSE-2.0
<http://www.apache.org/licenses/LICENSE-2.0>`_.
.. placeholder: Download
Author Information
~~~~~~~~~~~~~~~~~~
|rjsmin| was written and is maintained by André Malo.
Acknowledgements
----------------
- `Douglas Crockford <http://www.crockford.com/>`_
- `Jeffrey Friedl <http://regex.info/>`_
Trivia / Fun
~~~~~~~~~~~~
|rJSmin| is a single pass substitution using a simple regular expression,
which looks like this:
.. sourcecode:: text
pattern = (
r'([^\047"/\000-\040]+)|((?:(?:\047[^\047\\\r\n]*(?:\\(?:[^\r\n]|\r?'
r'\n|\r)[^\047\\\r\n]*)*\047)|(?:"[^"\\\r\n]*(?:\\(?:[^\r\n]|\r?\n|'
r'\r)[^"\\\r\n]*)*"))[^\047"/\000-\040]*)|(?<=[(,=:\[!&|?{};\r\n])(?'
r':[\000-\011\013\014\016-\040]|(?:/\*[^*]*\*+(?:[^/*][^*]*\*+)*/))*'
r'(?:(?:(?://[^\r\n]*)?[\r\n])(?:[\000-\011\013\014\016-\040]|(?:/\*'
r'[^*]*\*+(?:[^/*][^*]*\*+)*/))*)*((?:/(?![\r\n/*])[^/\\\[\r\n]*(?:('
r'?:\\[^\r\n]|(?:\[[^\\\]\r\n]*(?:\\[^\r\n][^\\\]\r\n]*)*\]))[^/\\\['
r'\r\n]*)*/)[^\047"/\000-\040]*)|(?<=[\000-#%-,./:-@\[-^`{-~-]return'
r')(?:[\000-\011\013\014\016-\040]|(?:/\*[^*]*\*+(?:[^/*][^*]*\*+)*/'
r'))*(?:(?:(?://[^\r\n]*)?[\r\n])(?:[\000-\011\013\014\016-\040]|(?:'
r'/\*[^*]*\*+(?:[^/*][^*]*\*+)*/)))*((?:/(?![\r\n/*])[^/\\\[\r\n]*(?'
r':(?:\\[^\r\n]|(?:\[[^\\\]\r\n]*(?:\\[^\r\n][^\\\]\r\n]*)*\]))[^/'
r'\\\[\r\n]*)*/)[^\047"/\000-\040]*)|(?<=[^\000-!#%&(*,./:-@\[\\^`{|'
r'~])(?:[\000-\011\013\014\016-\040]|(?:/\*[^*]*\*+(?:[^/*][^*]*\*+)'
r'*/))*(?:((?:(?://[^\r\n]*)?[\r\n]))(?:[\000-\011\013\014\016-\040]'
r'|(?:/\*[^*]*\*+(?:[^/*][^*]*\*+)*/))*)+(?=[^\000-\040"#%-\047)*,./'
r':-@\\-^`|-~])|(?<=[^\000-#%-,./:-@\[-^`{-~-])((?:[\000-\011\013\01'
r'4\016-\040]|(?:/\*[^*]*\*+(?:[^/*][^*]*\*+)*/)))+(?=[^\000-#%-,./:'
r'-@\[-^`{-~-])|(?<=\+)((?:[\000-\011\013\014\016-\040]|(?:/\*[^*]*'
r'\*+(?:[^/*][^*]*\*+)*/)))+(?=\+)|(?<=-)((?:[\000-\011\013\014\016-'
r'\040]|(?:/\*[^*]*\*+(?:[^/*][^*]*\*+)*/)))+(?=-)|(?:[\000-\011\013'
r'\014\016-\040]|(?:/\*[^*]*\*+(?:[^/*][^*]*\*+)*/))+|(?:(?:(?://[^'
r'\r\n]*)?[\r\n])(?:[\000-\011\013\014\016-\040]|(?:/\*[^*]*\*+(?:[^'
r'/*][^*]*\*+)*/))*)+'
)
Related
~~~~~~~
- `CSS Minifier rCSSmin <http://opensource.perlig.de/rcssmin/>`_
.. vim: ft=rest tw=72

View File

@ -0,0 +1,57 @@
Download
~~~~~~~~
Change Log
----------
`CHANGES file <http://storage.perlig.de/rjsmin/CHANGES-1.0.7>`_
Source Packages
---------------
.. begin stable
Current Stable Version
''''''''''''''''''''''
- `rjsmin-1.0.7.tar.xz <http://storage.perlig.de/rjsmin/rjsmin-1.0.7.tar.xz>`_
- `rjsmin-1.0.7.tar.bz2 <http://storage.perlig.de/rjsmin/rjsmin-1.0.7.tar.bz2>`_
- `rjsmin-1.0.7.tar.gz <http://storage.perlig.de/rjsmin/rjsmin-1.0.7.tar.gz>`_
- `rjsmin-1.0.7.zip <http://storage.perlig.de/rjsmin/rjsmin-1.0.7.zip>`_
- `rjsmin-1.0.7.digests <http://storage.perlig.de/rjsmin/rjsmin-1.0.7.digests>`_
.. end stable
Integrity Check
---------------
There are hashes (MD5, SHA1 and SHA256) of the download packages stored
in the `digests file
<http://storage.perlig.de/rjsmin/rjsmin-1.0.7.digests>`_\.
In order to check the integrity of the downloaded file, use a tool like
md5sum (or sha1sum, sha256sum accordingly), e.g.:
.. sourcecode:: console
$ md5sum -c rjsmin-1.0.7.digests
rjsmin-1.0.7.tar.bz2: OK
rjsmin-1.0.7.tar.gz: OK
rjsmin-1.0.7.tar.xz: OK
rjsmin-1.0.7.zip: OK
In order to check the integrity of the digest file itself, you can check
the PGP signature of that file. The file is signed by André Malo, Key-ID
0x8103A37E:
.. sourcecode:: console
$ gpg --verify rjsmin-1.0.7.digests
gpg: Signature made Sun Jun 30 16:10:42 2013 CEST using DSA key ID 8103A37E
gpg: Good signature from "Andre Malo <nd@apache.org>"
gpg: aka "Andr\xe9\x20Malo <nd@perlig.de>"
gpg: aka "Andre Malo <ndparker@gmx.net>"
.. vim: ft=rest tw=72

View File

@ -0,0 +1,57 @@
Download
~~~~~~~~
Change Log
----------
`CHANGES file <http://storage.perlig.de/rjsmin/CHANGES-@@VERSION@@>`_
Source Packages
---------------
.. begin stable
Current Stable Version
''''''''''''''''''''''
- `rjsmin-@@VERSION@@.tar.xz <http://storage.perlig.de/rjsmin/rjsmin-@@VERSION@@.tar.xz>`_
- `rjsmin-@@VERSION@@.tar.bz2 <http://storage.perlig.de/rjsmin/rjsmin-@@VERSION@@.tar.bz2>`_
- `rjsmin-@@VERSION@@.tar.gz <http://storage.perlig.de/rjsmin/rjsmin-@@VERSION@@.tar.gz>`_
- `rjsmin-@@VERSION@@.zip <http://storage.perlig.de/rjsmin/rjsmin-@@VERSION@@.zip>`_
- `rjsmin-@@VERSION@@.digests <http://storage.perlig.de/rjsmin/rjsmin-@@VERSION@@.digests>`_
.. end stable
Integrity Check
---------------
There are hashes (MD5, SHA1 and SHA256) of the download packages stored
in the `digests file
<http://storage.perlig.de/rjsmin/@@PATH@@rjsmin-@@VERSION@@.digests>`_\.
In order to check the integrity of the downloaded file, use a tool like
md5sum (or sha1sum, sha256sum accordingly), e.g.:
.. sourcecode:: console
$ md5sum -c rjsmin-@@VERSION@@.digests
rjsmin-@@VERSION@@.tar.bz2: OK
rjsmin-@@VERSION@@.tar.gz: OK
rjsmin-@@VERSION@@.tar.xz: OK
rjsmin-@@VERSION@@.zip: OK
In order to check the integrity of the digest file itself, you can check
the PGP signature of that file. The file is signed by André Malo, Key-ID
0x8103A37E:
.. sourcecode:: console
$ gpg --verify rjsmin-@@VERSION@@.digests
gpg: Signature made Sun Jun 30 16:10:42 2013 CEST using DSA key ID 8103A37E
gpg: Good signature from "Andre Malo <nd@apache.org>"
gpg: aka "Andr\xe9\x20Malo <nd@perlig.de>"
gpg: aka "Andre Malo <ndparker@gmx.net>"
.. vim: ft=rest tw=72

22
docs/epydoc.conf Normal file
View File

@ -0,0 +1,22 @@
[epydoc]
verbosity = 1
modules =
rjsmin
output = html
url = http://opensource.perlig.de/rjsmin/
link = <a href="http://opensource.perlig.de/rjsmin/" target="_top">Visit rjsmin Online</a>
top = rjsmin
frames = no
sourcecode = yes
#graphs are ugly
#graph = classtree
target = docs/apidoc/
docformat = plaintext
private = no
parse = yes
introspect = yes

78
gen_chartable.py Executable file
View File

@ -0,0 +1,78 @@
#!/usr/bin/env python
# -*- coding: ascii -*-
#
# Copyright 2011
# Andr\xe9 Malo or his licensors, as applicable
#
# Licensed 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.
import re as _re
TPL = r"""
static const unsigned short rjsmin_charmask[128] = {
@@mask@@
};
""".strip() + "\n"
def _make_charmask():
dull = r'[^\047"/\000-\040]'
pre_regex = r'[(,=:\[!&|?{};\r\n]'
regex_dull = r'[^/\\\[\r\n]'
regex_cc_dull = r'[^\\\]\r\n]'
newline = r'[\r\n]'
id_literal = r'[^\000-#%-,./:-@\[-^`{-~-]'
id_literal_open = r'[^\000-\040"#%-\047)*,./:-@\\-^`|-~]'
id_literal_close = r'[^\000-!#%&(*,./:-@\[\\^`{|~]'
string_dull = r'[^\047"\\\r\n]'
space = r'[\000-\011\013\014\016-\040]'
charmask = []
for x in range(8):
maskline = []
for y in range(16):
c, mask = chr(x*16 + y), 0
if _re.match(dull, c):
mask |= 1
if _re.match(pre_regex, c):
mask |= 2
if _re.match(regex_dull, c):
mask |= 4
if _re.match(regex_cc_dull, c):
mask |= 8
if _re.match(id_literal, c):
mask |= 16
if _re.match(id_literal_open, c):
mask |= 32
if _re.match(id_literal_close, c):
mask |= 64
if _re.match(string_dull, c):
mask |= 128
if _re.match(space, c):
mask |= 256
if mask < 10:
mask = ' ' + str(mask)
elif mask < 100:
mask = ' ' + str(mask)
maskline.append(str(mask))
if y == 7:
charmask.append(', '.join(maskline))
maskline = []
charmask.append(', '.join(maskline))
return TPL.replace('@@mask@@', ',\n '.join(charmask))
print _make_charmask()

618
make.py Executable file
View File

@ -0,0 +1,618 @@
#!/usr/bin/env python
# -*- coding: ascii -*-
#
# Copyright 2006 - 2013
# Andr\xe9 Malo or his licensors, as applicable
#
# Licensed 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.
"""
===============
Build targets
===============
Build targets.
"""
__author__ = "Andr\xe9 Malo"
__author__ = getattr(__author__, 'decode', lambda x: __author__)('latin-1')
__docformat__ = "restructuredtext en"
import errno as _errno
import os as _os
import re as _re
import sys as _sys
from _setup import dist
from _setup import shell
from _setup import make
from _setup import term
from _setup.make import targets, default_targets
class Target(make.Target):
def init(self):
self.dirs = {
'lib': '.',
'docs': 'docs',
'apidoc': 'docs/apidoc',
'userdoc': 'docs/userdoc',
'userdoc_source': 'docs/_userdoc',
'userdoc_build': 'docs/_userdoc/_build',
'website': 'dist/website',
'_website': '_website', # source dir
'dist': 'dist',
'build': 'build',
'bench': 'bench',
'ebuild': '_pkg/ebuilds',
}
libpath = shell.native(self.dirs['lib'])
if libpath != _sys.path[0]:
while libpath in _sys.path:
_sys.path.remove(libpath)
_sys.path.insert(0, libpath)
self.ebuild_files = {
'rjsmin.ebuild.in':
'rjsmin-%(VERSION)s.ebuild',
}
Manifest = targets.Manifest
class Distribution(targets.Distribution):
def init(self):
self._dist = 'dist'
self._ebuilds = '_pkg/ebuilds'
self._changes = 'docs/CHANGES'
class MakefileTarget(default_targets.MakefileTarget):
def extend(self, names):
names.append('jsmin')
return '\n\n'.join([
'jsmin: bench/jsmin',
'bench/jsmin: bench/jsmin.c\n\tgcc -o bench/jsmin bench/jsmin.c',
])
class Benchmark(Target):
""" Benchmark """
NAME = "bench"
DEPS = ["compile-quiet"]
python = None
def run(self):
files = list(shell.files(self.dirs['bench'], '*.js'))
if self.python is None:
python = _sys.executable
else:
python = shell.frompath(self.python)
return not shell.spawn(*[
python,
shell.native('bench.py'),
'-c10'
] + files)
def clean(self, scm, dist):
term.green("Removing bytecode files...")
for filename in shell.dirs('.', '__pycache__'):
shell.rm_rf(filename)
for filename in shell.files('.', '*.py[co]'):
shell.rm(filename)
for filename in shell.files('.', '*$py.class'):
shell.rm(filename)
shell.rm(shell.native('bench/jsmin'))
class Benchmark2(Benchmark):
""" Benchmark """
NAME = "bench2"
python = "python2"
def clean(self, scm, dist):
pass
class Benchmark3(Benchmark):
""" Benchmark """
NAME = "bench3"
python = "python3"
def clean(self, scm, dist):
pass
class Check(Target):
""" Check the python code """
NAME = "check"
DEPS = ["compile-quiet"]
def run(self):
from _setup.dev import analysis
term.green('Linting rjsmin sources...')
res = analysis.pylint('_pkg/pylint.conf', 'rjsmin')
if res == 2:
make.warn('pylint not found', self.NAME)
class Compile(Target):
""" Compile the python code """
NAME = "compile"
#DEPS = None
def run(self):
import setup
_old_argv = _sys.argv
try:
_sys.argv = ['setup.py', '-q', 'build']
if not self.HIDDEN:
_sys.argv.remove('-q')
setup.setup()
if 'java' not in _sys.platform.lower():
_sys.argv = [
'setup.py', '-q', 'install_lib', '--install-dir',
shell.native(self.dirs['lib']),
'--optimize', '2',
]
if not self.HIDDEN:
_sys.argv.remove('-q')
setup.setup()
finally:
_sys.argv = _old_argv
self.compile('rjsmin.py')
term.write("%(ERASE)s")
term.green("All files successfully compiled.")
def compile(self, name):
path = shell.native(name)
term.write("%(ERASE)s%(BOLD)s>>> Compiling %(name)s...%(NORMAL)s",
name=name)
from distutils import util
try:
from distutils import log
except ImportError:
util.byte_compile([path], verbose=0, force=True)
else:
log.set_verbosity(0)
util.byte_compile([path], force=True)
def clean(self, scm, dist):
term.green("Removing python byte code...")
for name in shell.dirs('.', '__pycache__'):
shell.rm_rf(name)
for name in shell.files('.', '*.py[co]'):
shell.rm(name)
term.green("Removing c extensions...")
for name in shell.files('.', '*.so'):
shell.rm(name)
for name in shell.files('.', '*.pyd'):
shell.rm(name)
shell.rm_rf(self.dirs['build'])
class CompileQuiet(Compile):
NAME = "compile-quiet"
HIDDEN = True
def clean(self, scm, dist):
pass
class Doc(Target):
""" Build the docs (api + user) """
NAME = "doc"
DEPS = ['apidoc', 'userdoc']
class ApiDoc(Target):
""" Build the API docs """
NAME = "apidoc"
def run(self):
from _setup.dev import apidoc
apidoc.epydoc(
prepend=[
shell.native(self.dirs['lib']),
],
)
def clean(self, scm, dist):
if scm:
term.green("Removing apidocs...")
shell.rm_rf(self.dirs['apidoc'])
class UserDoc(Target):
""" Build the user docs """
NAME = "userdoc"
#DEPS = None
def run(self):
from _setup.dev import userdoc
userdoc.sphinx(
build=shell.native(self.dirs['userdoc_build']),
source=shell.native(self.dirs['userdoc_source']),
target=shell.native(self.dirs['userdoc']),
)
def clean(self, scm, dist):
if scm:
term.green("Removing userdocs...")
shell.rm_rf(self.dirs['userdoc'])
shell.rm_rf(self.dirs['userdoc_build'])
class Website(Target):
""" Build the website """
NAME = "website"
DEPS = ["apidoc"]
def run(self):
from _setup.util import SafeConfigParser as parser
parser = parser()
parser.read('package.cfg')
strversion = parser.get('package', 'version.number')
shortversion = tuple(map(int, strversion.split('.')[:2]))
shell.rm_rf(self.dirs['_website'])
shell.cp_r(
self.dirs['userdoc_source'],
_os.path.join(self.dirs['_website'], 'src')
)
shell.rm_rf(_os.path.join(self.dirs['_website'], 'build'))
shell.rm_rf(self.dirs['website'])
_os.makedirs(self.dirs['website'])
filename = _os.path.join(
self.dirs['_website'], 'src', 'website_download.txt'
)
fp = open(filename)
try:
download = fp.read()
finally:
fp.close()
filename = _os.path.join(self.dirs['_website'], 'src', 'index.txt')
fp = open(filename)
try:
indexlines = fp.readlines()
finally:
fp.close()
fp = open(filename, 'w')
try:
for line in indexlines:
if line.startswith('.. placeholder: Download'):
line = download
fp.write(line)
finally:
fp.close()
shell.cp_r(
self.dirs['apidoc'],
_os.path.join(self.dirs['website'], 'doc-%d.%d' % shortversion)
)
shell.cp_r(
self.dirs['apidoc'],
_os.path.join(
self.dirs['_website'], 'src', 'doc-%d.%d' % shortversion
)
)
fp = open(_os.path.join(
self.dirs['_website'], 'src', 'conf.py'
), 'a')
try:
fp.write("\nepydoc = dict(rjsmin=%r)\n" % (
_os.path.join(
shell.native(self.dirs['_website']),
"src",
"doc-%d.%d" % shortversion,
),
))
fp.write("\nexclude_trees.append(%r)\n" %
"doc-%d.%d" % shortversion
)
finally:
fp.close()
from _setup.dev import userdoc
userdoc.sphinx(
build=shell.native(_os.path.join(self.dirs['_website'], 'build')),
source=shell.native(_os.path.join(self.dirs['_website'], 'src')),
target=shell.native(self.dirs['website']),
)
shell.rm(_os.path.join(self.dirs['website'], '.buildinfo'))
def clean(self, scm, dist):
if scm:
term.green("Removing website...")
shell.rm_rf(self.dirs['website'])
shell.rm_rf(self.dirs['_website'])
class PreCheck(Target):
""" Run clean, doc, check """
NAME = "precheck"
DEPS = ["clean", "doc", "check"]
class SVNRelease(Target):
""" Release current version """
#NAME = "release"
DEPS = None
def run(self):
self._check_committed()
self._update_versions()
self._tag_release()
self.runner('dist', seen={})
def _tag_release(self):
""" Tag release """
from _setup.util import SafeConfigParser as parser
parser = parser()
parser.read('package.cfg')
strversion = parser.get('package', 'version.number')
version = strversion
trunk_url = self._repo_url()
if not trunk_url.endswith('/trunk'):
rex = _re.compile(r'/branches/\d+(?:\.\d+)*\.[xX]$').search
match = rex(trunk_url)
if not match:
make.fail("Not in trunk or release branch!")
found = match.start(0)
else:
found = -len('/trunk')
release_url = trunk_url[:found] + '/releases/' + version
svn = shell.frompath('svn')
shell.spawn(
svn, 'copy', '-m', 'Release version ' + version, '--',
trunk_url, release_url,
echo=True,
)
def _update_versions(self):
""" Update versions """
self.runner('version', seen={})
svn = shell.frompath('svn')
shell.spawn(svn, 'commit', '-m', 'Pre-release: version update',
echo=True
)
def _repo_url(self):
""" Determine URL """
from xml.dom import minidom
svn = shell.frompath('svn')
info = minidom.parseString(
shell.spawn(svn, 'info', '--xml', stdout=True)
)
try:
url = info.getElementsByTagName('url')[0]
text = []
for node in url.childNodes:
if node.nodeType == node.TEXT_NODE:
text.append(node.data)
finally:
info.unlink()
return ''.join(text).encode('utf-8')
def _check_committed(self):
""" Check if everything is committed """
if not self._repo_url().endswith('/trunk'):
rex = _re.compile(r'/branches/\d+(?:\.\d+)*\.[xX]$').search
match = rex(self._repo_url())
if not match:
make.fail("Not in trunk or release branch!")
svn = shell.frompath('svn')
lines = shell.spawn(svn, 'stat', '--ignore-externals',
stdout=True, env=dict(_os.environ, LC_ALL='C'),
).splitlines()
for line in lines:
if line.startswith('X'):
continue
make.fail("Uncommitted changes!")
class GitRelease(Target):
""" Release current version """
#NAME = "release"
DEPS = None
def run(self):
self._check_committed()
self._update_versions()
self._tag_release()
self.runner('dist', seen={})
def _tag_release(self):
""" Tag release """
from _setup.util import SafeConfigParser as parser
parser = parser()
parser.read('package.cfg')
strversion = parser.get('package', 'version.number')
version = strversion
git = shell.frompath('git')
shell.spawn(
git, 'tag', '-a', '-m', 'Release version ' + version, '--',
version,
echo=True,
)
def _update_versions(self):
""" Update versions """
self.runner('version', seen={})
git = shell.frompath('git')
shell.spawn(git, 'commit', '-a', '-m', 'Pre-release: version update',
echo=True
)
def _check_committed(self):
""" Check if everything is committed """
git = shell.frompath('git')
lines = shell.spawn(git, 'branch', '--color=never',
stdout=True, env=dict(_os.environ, LC_ALL='C')
).splitlines()
for line in lines:
if line.startswith('*'):
branch = line.split(None, 1)[1]
break
else:
make.fail("Could not determine current branch.")
if branch != 'master':
rex = _re.compile(r'^\d+(?:\.\d+)*\.[xX]$').match
match = rex(branch)
if not match:
make.fail("Not in master or release branch.")
lines = shell.spawn(git, 'status', '--porcelain',
stdout=True, env=dict(_os.environ, LC_ALL='C'),
)
if lines:
make.fail("Uncommitted changes!")
class Release(GitRelease):
NAME = "release"
#DEPS = None
class Version(Target):
""" Insert the program version into all relevant files """
NAME = "version"
#DEPS = None
def run(self):
from _setup.util import SafeConfigParser as parser
parser = parser()
parser.read('package.cfg')
strversion = parser.get('package', 'version.number')
self._version_init(strversion)
self._version_userdoc(strversion)
self._version_download(strversion)
self._version_changes(strversion)
parm = {'VERSION': strversion}
for src, dest in self.ebuild_files.items():
src = "%s/%s" % (self.dirs['ebuild'], src)
dest = "%s/%s" % (self.dirs['ebuild'], dest % parm)
term.green("Creating %(name)s...", name=dest)
shell.cp(src, dest)
def _version_init(self, strversion):
""" Modify version in __init__ """
filename = _os.path.join(self.dirs['lib'], 'rjsmin.py')
fp = open(filename)
try:
initlines = fp.readlines()
finally:
fp.close()
fp = open(filename, 'w')
replaced = False
try:
for line in initlines:
if line.startswith('__version__'):
line = '__version__ = %r\n' % (strversion,)
replaced = True
fp.write(line)
finally:
fp.close()
assert replaced, "__version__ not found in rjsmin.py"
def _version_changes(self, strversion):
""" Modify version in changes """
filename = _os.path.join(shell.native(self.dirs['docs']), 'CHANGES')
fp = open(filename)
try:
initlines = fp.readlines()
finally:
fp.close()
fp = open(filename, 'w')
try:
for line in initlines:
if line.rstrip() == "Changes with version":
line = "%s %s\n" % (line.rstrip(), strversion)
fp.write(line)
finally:
fp.close()
def _version_userdoc(self, strversion):
""" Modify version in userdoc """
filename = _os.path.join(self.dirs['userdoc_source'], 'conf.py')
shortversion = '.'.join(strversion.split('.')[:2])
longversion = strversion
fp = open(filename)
try:
initlines = fp.readlines()
finally:
fp.close()
replaced = 0
fp = open(filename, 'w')
try:
for line in initlines:
if line.startswith('version'):
line = 'version = %r\n' % shortversion
replaced |= 1
elif line.startswith('release'):
line = 'release = %r\n' % longversion
replaced |= 2
fp.write(line)
finally:
fp.close()
assert replaced & 3 != 0, "version/release not found in conf.py"
def _version_download(self, strversion):
""" Modify version in website download docs """
filename = _os.path.join(
self.dirs['userdoc_source'], 'website_download.txt'
)
VERSION, PATH = strversion, ''
fp = open(filename + '.in')
try:
dllines = fp.readlines()
finally:
fp.close()
instable = []
fp = open(filename, 'w')
try:
for line in dllines:
if instable:
instable.append(line)
if line.startswith('.. end stable'):
res = (''.join(instable)
.replace('@@VERSION@@', strversion)
.replace('@@PATH@@', '')
)
fp.write(res)
instable = []
elif line.startswith('.. begin stable'):
instable.append(line)
else:
fp.write(line
.replace('@@VERSION@@', VERSION)
.replace('@@PATH@@', PATH)
)
finally:
fp.close()
def clean(self, scm, dist):
""" Clean versioned files """
if scm:
term.green("Removing generated ebuild files")
for name in shell.files(self.dirs['ebuild'], '*.ebuild'):
shell.rm(name)
make.main(name=__name__)

78
package.cfg Normal file
View File

@ -0,0 +1,78 @@
# -*- coding: utf-8 -*-
#
# Copyright 2009 - 2013
# André Malo or his licensors, as applicable
#
# Licensed 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.
[package]
name = rjsmin
python.min = 2.3
python.max = 3.3
pypy.min = 1.9
pypy.max = 2.0
jython.min = 2.5
jython.max = 2.7
version.number = 1.0.7
author.name = André Malo
author.email = nd@perlig.de
#maintainer.name =
#maintainer.email =
url.homepage = http://opensource.perlig.de/rjsmin/
url.download = http://storage.perlig.de/rjsmin/
[docs]
meta.classifiers = docs/CLASSIFIERS
meta.description = docs/DESCRIPTION
meta.summary = docs/SUMMARY
meta.provides = docs/PROVIDES
meta.license = LICENSE
meta.keywords =
Javascript
Minimization
apidoc.dir = docs/apidoc
apidoc.strip = 1
#apidoc.ignore =
#userdoc.dir = docs/userdoc
#userdoc.strip = 1
#userdoc.ignore =
# .buildinfo
#examples.dir = docs/examples
#examples.strip = 1
#examples.ignore =
#man =
extra =
README.rst
docs/CHANGES
docs/BENCHMARKS
[manifest]
#packages.lib = .
#packages.collect =
modules = rjsmin
#scripts =
dist =
bench.py
bench

420
rjsmin.c Normal file
View File

@ -0,0 +1,420 @@
/*
* Copyright 2011, 2012
* Andr\xe9 Malo or his licensors, as applicable
*
* Licensed 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.
*/
#include "cext.h"
EXT_INIT_FUNC;
#define RJSMIN_DULL_BIT (1 << 0)
#define RJSMIN_PRE_REGEX_BIT (1 << 1)
#define RJSMIN_REGEX_DULL_BIT (1 << 2)
#define RJSMIN_REGEX_CC_DULL_BIT (1 << 3)
#define RJSMIN_ID_LIT_BIT (1 << 4)
#define RJSMIN_ID_LIT_O_BIT (1 << 5)
#define RJSMIN_ID_LIT_C_BIT (1 << 6)
#define RJSMIN_STRING_DULL_BIT (1 << 7)
#define RJSMIN_SPACE_BIT (1 << 8)
#ifdef EXT3
typedef Py_UNICODE rchar;
#else
typedef unsigned char rchar;
#endif
#define U(c) ((rchar)(c))
#define RJSMIN_IS_DULL(c) ((U(c) > 127) || \
(rjsmin_charmask[U(c) & 0x7F] & RJSMIN_DULL_BIT))
#define RJSMIN_IS_REGEX_DULL(c) ((U(c) > 127) || \
(rjsmin_charmask[U(c) & 0x7F] & RJSMIN_REGEX_DULL_BIT))
#define RJSMIN_IS_REGEX_CC_DULL(c) ((U(c) > 127) || \
(rjsmin_charmask[U(c) & 0x7F] & RJSMIN_REGEX_CC_DULL_BIT))
#define RJSMIN_IS_STRING_DULL(c) ((U(c) > 127) || \
(rjsmin_charmask[U(c) & 0x7F] & RJSMIN_STRING_DULL_BIT))
#define RJSMIN_IS_ID_LITERAL(c) ((U(c) > 127) || \
(rjsmin_charmask[U(c) & 0x7F] & RJSMIN_ID_LIT_BIT))
#define RJSMIN_IS_ID_LITERAL_OPEN(c) ((U(c) > 127) || \
(rjsmin_charmask[U(c) & 0x7F] & RJSMIN_ID_LIT_O_BIT))
#define RJSMIN_IS_ID_LITERAL_CLOSE(c) ((U(c) > 127) || \
(rjsmin_charmask[U(c) & 0x7F] & RJSMIN_ID_LIT_C_BIT))
#define RJSMIN_IS_SPACE(c) ((U(c) <= 127) && \
(rjsmin_charmask[U(c) & 0x7F] & RJSMIN_SPACE_BIT))
#define RJSMIN_IS_PRE_REGEX_1(c) ((U(c) <= 127) && \
(rjsmin_charmask[U(c) & 0x7F] & RJSMIN_PRE_REGEX_BIT))
static const unsigned short rjsmin_charmask[128] = {
396, 396, 396, 396, 396, 396, 396, 396,
396, 396, 2, 396, 396, 2, 396, 396,
396, 396, 396, 396, 396, 396, 396, 396,
396, 396, 396, 396, 396, 396, 396, 396,
396, 175, 76, 141, 253, 141, 143, 76,
175, 205, 141, 237, 143, 237, 141, 136,
253, 253, 253, 253, 253, 253, 253, 253,
253, 253, 143, 143, 141, 143, 141, 143,
141, 253, 253, 253, 253, 253, 253, 253,
253, 253, 253, 253, 253, 253, 253, 253,
253, 253, 253, 253, 253, 253, 253, 253,
253, 253, 253, 171, 1, 197, 141, 253,
141, 253, 253, 253, 253, 253, 253, 253,
253, 253, 253, 253, 253, 253, 253, 253,
253, 253, 253, 253, 253, 253, 253, 253,
253, 253, 253, 175, 143, 207, 141, 253
};
static Py_ssize_t
rjsmin(const rchar *source, rchar *target, Py_ssize_t length)
{
const rchar *reset, *sentinel = source + length;
rchar *tstart = target;
rchar c, quote;
while (source < sentinel) {
c = *source++;
if (RJSMIN_IS_DULL(c)) {
*target++ = c;
continue;
}
switch (c) {
/* String */
case U('\''): case U('"'):
reset = source;
*target++ = quote = c;
while (source < sentinel) {
c = *source++;
*target++ = c;
if (RJSMIN_IS_STRING_DULL(c))
continue;
switch (c) {
case U('\''): case U('"'):
if (c == quote)
goto cont;
continue;
case U('\\'):
if (source < sentinel) {
c = *source++;
*target++ = c;
if (c == U('\r') && source < sentinel
&& *source == U('\n'))
*target++ = *source++;
}
continue;
}
break;
}
target -= source - reset;
source = reset;
continue;
/* Comment or Regex or something else entirely */
case U('/'):
if (!(source < sentinel)) {
*target++ = c;
}
else {
switch (*source) {
/* Comment */
case U('*'): case U('/'):
goto skip_or_copy_ws;
default:
if ( target == tstart
|| RJSMIN_IS_PRE_REGEX_1(*(target - 1))
|| (
(target - tstart >= 6)
&& *(target - 1) == U('n')
&& *(target - 2) == U('r')
&& *(target - 3) == U('u')
&& *(target - 4) == U('t')
&& *(target - 5) == U('e')
&& *(target - 6) == U('r')
&& (
target - tstart == 6
|| !RJSMIN_IS_ID_LITERAL(*(target - 7))
)
)) {
/* Regex */
reset = source;
*target++ = U('/');
while (source < sentinel) {
c = *source++;
*target++ = c;
if (RJSMIN_IS_REGEX_DULL(c))
continue;
switch (c) {
case U('/'):
goto cont;
case U('\\'):
if (source < sentinel) {
c = *source++;
*target++ = c;
if (c == U('\r') || c == U('\n'))
break;
}
continue;
case U('['):
while (source < sentinel) {
c = *source++;
*target++ = c;
if (RJSMIN_IS_REGEX_CC_DULL(c))
continue;
switch (c) {
case U('\\'):
if (source < sentinel) {
c = *source++;
*target++ = c;
if (c == U('\r') || c == U('\n'))
break;
}
continue;
case U(']'):
goto cont_regex;
}
}
break;
}
break;
cont_regex:
continue;
}
target -= source - reset;
source = reset;
}
else {
/* Just a slash */
*target++ = c;
}
continue;
}
}
continue;
/* Whitespace */
default:
skip_or_copy_ws:
quote = U(' ');
--source;
while (source < sentinel) {
c = *source++;
if (RJSMIN_IS_SPACE(c))
continue;
switch (c) {
case U('\r'): case U('\n'):
quote = U('\n');
continue;
case U('/'):
if (source < sentinel) {
switch (*source) {
case U('*'):
reset = source;
c = *source++;
while (source < sentinel) {
c = *source++;
if (c == U('*') && source < sentinel
&& *source == U('/')) {
++source;
reset = NULL;
break;
}
}
if (!reset)
continue;
source = reset;
*target++ = U('/');
goto cont;
case U('/'):
++source;
while (source < sentinel) {
c = *source++;
switch (c) {
case U('\n'):
break;
case U('\r'):
if (source < sentinel
&& *source == U('\n'))
++source;
break;
default:
continue;
}
break;
}
quote = U('\n');
continue;
}
}
}
--source;
break;
}
if ((tstart < target && source < sentinel)
&& ((quote == U('\n')
&& RJSMIN_IS_ID_LITERAL_CLOSE(*(target - 1))
&& RJSMIN_IS_ID_LITERAL_OPEN(*source))
||
(quote == U(' ')
&& ((RJSMIN_IS_ID_LITERAL(*(target - 1))
&& RJSMIN_IS_ID_LITERAL(*source))
|| (source < sentinel
&& ((*(target - 1) == U('+')
&& *source == U('+'))
|| (*(target - 1) == U('-')
&& *source == U('-'))))))))
*target++ = quote;
}
cont:
continue;
}
return (Py_ssize_t)(target - tstart);
}
PyDoc_STRVAR(rjsmin_jsmin__doc__,
"jsmin(script)\n\
\n\
Minify javascript based on `jsmin.c by Douglas Crockford`_\\.\n\
\n\
Instead of parsing the stream char by char, it uses a regular\n\
expression approach which minifies the whole script with one big\n\
substitution regex.\n\
\n\
.. _jsmin.c by Douglas Crockford:\n\
http://www.crockford.com/javascript/jsmin.c\n\
\n\
:Note: This is a hand crafted C implementation built on the regex\n\
semantics.\n\
\n\
:Parameters:\n\
`script` : ``str``\n\
Script to minify\n\
\n\
:Return: Minified script\n\
:Rtype: ``str``");
static PyObject *
rjsmin_jsmin(PyObject *self, PyObject *args, PyObject *kwds)
{
PyObject *script, *result;
static char *kwlist[] = {"script", NULL};
Py_ssize_t slength, length;
#ifdef EXT2
int uni;
#define UOBJ "O"
#endif
#ifdef EXT3
#define UOBJ "U"
#endif
if (!PyArg_ParseTupleAndKeywords(args, kwds, UOBJ, kwlist,
&script))
return NULL;
#ifdef EXT2
if (PyUnicode_Check(script)) {
if (!(script = PyUnicode_AsUTF8String(script)))
return NULL;
uni = 1;
}
else {
if (!(script = PyObject_Str(script)))
return NULL;
uni = 0;
}
#endif
#ifdef EXT3
Py_INCREF(script);
#define PyString_GET_SIZE PyUnicode_GET_SIZE
#define PyString_AS_STRING PyUnicode_AS_UNICODE
#define _PyString_Resize PyUnicode_Resize
#define PyString_FromStringAndSize PyUnicode_FromUnicode
#endif
slength = PyString_GET_SIZE(script);
if (!(result = PyString_FromStringAndSize(NULL, slength))) {
Py_DECREF(script);
return NULL;
}
Py_BEGIN_ALLOW_THREADS
length = rjsmin((rchar *)PyString_AS_STRING(script),
(rchar *)PyString_AS_STRING(result),
slength);
Py_END_ALLOW_THREADS
Py_DECREF(script);
if (length < 0) {
Py_DECREF(result);
return NULL;
}
if (length != slength && _PyString_Resize(&result, length) == -1)
return NULL;
#ifdef EXT2
if (uni) {
script = PyUnicode_DecodeUTF8(PyString_AS_STRING(result),
PyString_GET_SIZE(result), "strict");
Py_DECREF(result);
if (!script)
return NULL;
result = script;
}
#endif
return result;
}
/* ------------------------ BEGIN MODULE DEFINITION ------------------------ */
EXT_METHODS = {
{"jsmin",
(PyCFunction)rjsmin_jsmin, METH_VARARGS | METH_KEYWORDS,
rjsmin_jsmin__doc__},
{NULL} /* Sentinel */
};
PyDoc_STRVAR(EXT_DOCS_VAR,
"C implementation of rjsmin\n\
==========================\n\
\n\
C implementation of rjsmin.");
EXT_DEFINE(EXT_MODULE_NAME, EXT_METHODS_VAR, EXT_DOCS_VAR);
EXT_INIT_FUNC {
PyObject *m;
/* Create the module and populate stuff */
if (!(m = EXT_CREATE(&EXT_DEFINE_VAR)))
EXT_INIT_ERROR(NULL);
EXT_ADD_UNICODE(m, "__author__", "Andr\xe9 Malo", "latin-1");
EXT_ADD_STRING(m, "__docformat__", "restructuredtext en");
EXT_INIT_RETURN(m);
}
/* ------------------------- END MODULE DEFINITION ------------------------- */

300
rjsmin.py Executable file
View File

@ -0,0 +1,300 @@
#!/usr/bin/env python
# -*- coding: ascii -*-
#
# Copyright 2011 - 2013
# Andr\xe9 Malo or his licensors, as applicable
#
# Licensed 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.
r"""
=====================
Javascript Minifier
=====================
rJSmin is a javascript minifier written in python.
The minifier is based on the semantics of `jsmin.c by Douglas Crockford`_\.
The module is a re-implementation aiming for speed, so it can be used at
runtime (rather than during a preprocessing step). Usually it produces the
same results as the original ``jsmin.c``. It differs in the following ways:
- there is no error detection: unterminated string, regex and comment
literals are treated as regular javascript code and minified as such.
- Control characters inside string and regex literals are left untouched; they
are not converted to spaces (nor to \n)
- Newline characters are not allowed inside string and regex literals, except
for line continuations in string literals (ECMA-5).
- "return /regex/" is recognized correctly.
- "+ +" and "- -" sequences are not collapsed to '++' or '--'
- Newlines before ! operators are removed more sensibly
- rJSmin does not handle streams, but only complete strings. (However, the
module provides a "streamy" interface).
Since most parts of the logic are handled by the regex engine it's way
faster than the original python port of ``jsmin.c`` by Baruch Even. The speed
factor varies between about 6 and 55 depending on input and python version
(it gets faster the more compressed the input already is). Compared to the
speed-refactored python port by Dave St.Germain the performance gain is less
dramatic but still between 1.2 and 7. See the docs/BENCHMARKS file for
details.
rjsmin.c is a reimplementation of rjsmin.py in C and speeds it up even more.
Both python 2 and python 3 are supported.
.. _jsmin.c by Douglas Crockford:
http://www.crockford.com/javascript/jsmin.c
"""
__author__ = "Andr\xe9 Malo"
__author__ = getattr(__author__, 'decode', lambda x: __author__)('latin-1')
__docformat__ = "restructuredtext en"
__license__ = "Apache License, Version 2.0"
__version__ = '1.0.7'
__all__ = ['jsmin']
import re as _re
def _make_jsmin(python_only=False):
"""
Generate JS minifier based on `jsmin.c by Douglas Crockford`_
.. _jsmin.c by Douglas Crockford:
http://www.crockford.com/javascript/jsmin.c
:Parameters:
`python_only` : ``bool``
Use only the python variant. If true, the c extension is not even
tried to be loaded.
:Return: Minifier
:Rtype: ``callable``
"""
# pylint: disable = R0912, R0914, W0612
if not python_only:
try:
import _rjsmin
except ImportError:
pass
else:
return _rjsmin.jsmin
try:
xrange
except NameError:
xrange = range # pylint: disable = W0622
space_chars = r'[\000-\011\013\014\016-\040]'
line_comment = r'(?://[^\r\n]*)'
space_comment = r'(?:/\*[^*]*\*+(?:[^/*][^*]*\*+)*/)'
string1 = \
r'(?:\047[^\047\\\r\n]*(?:\\(?:[^\r\n]|\r?\n|\r)[^\047\\\r\n]*)*\047)'
string2 = r'(?:"[^"\\\r\n]*(?:\\(?:[^\r\n]|\r?\n|\r)[^"\\\r\n]*)*")'
strings = r'(?:%s|%s)' % (string1, string2)
charclass = r'(?:\[[^\\\]\r\n]*(?:\\[^\r\n][^\\\]\r\n]*)*\])'
nospecial = r'[^/\\\[\r\n]'
regex = r'(?:/(?![\r\n/*])%s*(?:(?:\\[^\r\n]|%s)%s*)*/)' % (
nospecial, charclass, nospecial
)
space = r'(?:%s|%s)' % (space_chars, space_comment)
newline = r'(?:%s?[\r\n])' % line_comment
def fix_charclass(result):
""" Fixup string of chars to fit into a regex char class """
pos = result.find('-')
if pos >= 0:
result = r'%s%s-' % (result[:pos], result[pos + 1:])
def sequentize(string):
"""
Notate consecutive characters as sequence
(1-4 instead of 1234)
"""
first, last, result = None, None, []
for char in map(ord, string):
if last is None:
first = last = char
elif last + 1 == char:
last = char
else:
result.append((first, last))
first = last = char
if last is not None:
result.append((first, last))
return ''.join(['%s%s%s' % (
chr(first),
last > first + 1 and '-' or '',
last != first and chr(last) or ''
) for first, last in result])
return _re.sub(r'([\000-\040\047])', # for better portability
lambda m: '\\%03o' % ord(m.group(1)), (sequentize(result)
.replace('\\', '\\\\')
.replace('[', '\\[')
.replace(']', '\\]')
)
)
def id_literal_(what):
""" Make id_literal like char class """
match = _re.compile(what).match
result = ''.join([
chr(c) for c in xrange(127) if not match(chr(c))
])
return '[^%s]' % fix_charclass(result)
def not_id_literal_(keep):
""" Make negated id_literal like char class """
match = _re.compile(id_literal_(keep)).match
result = ''.join([
chr(c) for c in xrange(127) if not match(chr(c))
])
return r'[%s]' % fix_charclass(result)
not_id_literal = not_id_literal_(r'[a-zA-Z0-9_$]')
preregex1 = r'[(,=:\[!&|?{};\r\n]'
preregex2 = r'%(not_id_literal)sreturn' % locals()
id_literal = id_literal_(r'[a-zA-Z0-9_$]')
id_literal_open = id_literal_(r'[a-zA-Z0-9_${\[(!+-]')
id_literal_close = id_literal_(r'[a-zA-Z0-9_$}\])"\047+-]')
dull = r'[^\047"/\000-\040]'
space_sub = _re.compile((
r'(%(dull)s+)'
r'|(%(strings)s%(dull)s*)'
r'|(?<=%(preregex1)s)'
r'%(space)s*(?:%(newline)s%(space)s*)*'
r'(%(regex)s%(dull)s*)'
r'|(?<=%(preregex2)s)'
r'%(space)s*(?:%(newline)s%(space)s)*'
r'(%(regex)s%(dull)s*)'
r'|(?<=%(id_literal_close)s)'
r'%(space)s*(?:(%(newline)s)%(space)s*)+'
r'(?=%(id_literal_open)s)'
r'|(?<=%(id_literal)s)(%(space)s)+(?=%(id_literal)s)'
r'|(?<=\+)(%(space)s)+(?=\+)'
r'|(?<=-)(%(space)s)+(?=-)'
r'|%(space)s+'
r'|(?:%(newline)s%(space)s*)+'
) % locals()).sub
#print space_sub.__self__.pattern
def space_subber(match):
""" Substitution callback """
# pylint: disable = C0321, R0911
groups = match.groups()
if groups[0]: return groups[0]
elif groups[1]: return groups[1]
elif groups[2]: return groups[2]
elif groups[3]: return groups[3]
elif groups[4]: return '\n'
elif groups[5] or groups[6] or groups[7]: return ' '
else: return ''
def jsmin(script): # pylint: disable = W0621
r"""
Minify javascript based on `jsmin.c by Douglas Crockford`_\.
Instead of parsing the stream char by char, it uses a regular
expression approach which minifies the whole script with one big
substitution regex.
.. _jsmin.c by Douglas Crockford:
http://www.crockford.com/javascript/jsmin.c
:Parameters:
`script` : ``str``
Script to minify
:Return: Minified script
:Rtype: ``str``
"""
return space_sub(space_subber, '\n%s\n' % script).strip()
return jsmin
jsmin = _make_jsmin()
def jsmin_for_posers(script):
r"""
Minify javascript based on `jsmin.c by Douglas Crockford`_\.
Instead of parsing the stream char by char, it uses a regular
expression approach which minifies the whole script with one big
substitution regex.
.. _jsmin.c by Douglas Crockford:
http://www.crockford.com/javascript/jsmin.c
:Warning: This function is the digest of a _make_jsmin() call. It just
utilizes the resulting regex. It's just for fun here and may
vanish any time. Use the `jsmin` function instead.
:Parameters:
`script` : ``str``
Script to minify
:Return: Minified script
:Rtype: ``str``
"""
def subber(match):
""" Substitution callback """
groups = match.groups()
return (
groups[0] or
groups[1] or
groups[2] or
groups[3] or
(groups[4] and '\n') or
(groups[5] and ' ') or
(groups[6] and ' ') or
(groups[7] and ' ') or
''
)
return _re.sub(
r'([^\047"/\000-\040]+)|((?:(?:\047[^\047\\\r\n]*(?:\\(?:[^\r\n]|\r?'
r'\n|\r)[^\047\\\r\n]*)*\047)|(?:"[^"\\\r\n]*(?:\\(?:[^\r\n]|\r?\n|'
r'\r)[^"\\\r\n]*)*"))[^\047"/\000-\040]*)|(?<=[(,=:\[!&|?{};\r\n])(?'
r':[\000-\011\013\014\016-\040]|(?:/\*[^*]*\*+(?:[^/*][^*]*\*+)*/))*'
r'(?:(?:(?://[^\r\n]*)?[\r\n])(?:[\000-\011\013\014\016-\040]|(?:/\*'
r'[^*]*\*+(?:[^/*][^*]*\*+)*/))*)*((?:/(?![\r\n/*])[^/\\\[\r\n]*(?:('
r'?:\\[^\r\n]|(?:\[[^\\\]\r\n]*(?:\\[^\r\n][^\\\]\r\n]*)*\]))[^/\\\['
r'\r\n]*)*/)[^\047"/\000-\040]*)|(?<=[\000-#%-,./:-@\[-^`{-~-]return'
r')(?:[\000-\011\013\014\016-\040]|(?:/\*[^*]*\*+(?:[^/*][^*]*\*+)*/'
r'))*(?:(?:(?://[^\r\n]*)?[\r\n])(?:[\000-\011\013\014\016-\040]|(?:'
r'/\*[^*]*\*+(?:[^/*][^*]*\*+)*/)))*((?:/(?![\r\n/*])[^/\\\[\r\n]*(?'
r':(?:\\[^\r\n]|(?:\[[^\\\]\r\n]*(?:\\[^\r\n][^\\\]\r\n]*)*\]))[^/'
r'\\\[\r\n]*)*/)[^\047"/\000-\040]*)|(?<=[^\000-!#%&(*,./:-@\[\\^`{|'
r'~])(?:[\000-\011\013\014\016-\040]|(?:/\*[^*]*\*+(?:[^/*][^*]*\*+)'
r'*/))*(?:((?:(?://[^\r\n]*)?[\r\n]))(?:[\000-\011\013\014\016-\040]'
r'|(?:/\*[^*]*\*+(?:[^/*][^*]*\*+)*/))*)+(?=[^\000-\040"#%-\047)*,./'
r':-@\\-^`|-~])|(?<=[^\000-#%-,./:-@\[-^`{-~-])((?:[\000-\011\013\01'
r'4\016-\040]|(?:/\*[^*]*\*+(?:[^/*][^*]*\*+)*/)))+(?=[^\000-#%-,./:'
r'-@\[-^`{-~-])|(?<=\+)((?:[\000-\011\013\014\016-\040]|(?:/\*[^*]*'
r'\*+(?:[^/*][^*]*\*+)*/)))+(?=\+)|(?<=-)((?:[\000-\011\013\014\016-'
r'\040]|(?:/\*[^*]*\*+(?:[^/*][^*]*\*+)*/)))+(?=-)|(?:[\000-\011\013'
r'\014\016-\040]|(?:/\*[^*]*\*+(?:[^/*][^*]*\*+)*/))+|(?:(?:(?://[^'
r'\r\n]*)?[\r\n])(?:[\000-\011\013\014\016-\040]|(?:/\*[^*]*\*+(?:[^'
r'/*][^*]*\*+)*/))*)+', subber, '\n%s\n' % script
).strip()
if __name__ == '__main__':
import sys as _sys
_sys.stdout.write(jsmin(_sys.stdin.read()))

42
setup.py Normal file
View File

@ -0,0 +1,42 @@
#!/usr/bin/env python
# -*- coding: ascii -*-
#
# Copyright 2006 - 2013
# Andr\xe9 Malo or his licensors, as applicable
#
# Licensed 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.
import sys as _sys
from _setup import run
def setup(args=None, _manifest=0):
""" Main setup function """
from _setup.ext import Extension
if 'java' in _sys.platform.lower():
# no c extension for jython
ext = None
else:
ext=[Extension('_rjsmin', sources=['rjsmin.c'])]
return run(script_args=args, ext=ext, manifest_only=_manifest)
def manifest():
""" Create List of packaged files """
return setup((), _manifest=1)
if __name__ == '__main__':
setup()