initial import.
This commit is contained in:
commit
f7d6457e2d
|
@ -0,0 +1,13 @@
|
|||
Makefile
|
||||
*.py[cod]
|
||||
*.so
|
||||
dist
|
||||
build
|
||||
__pycache__
|
||||
docs/_userdoc/_build/
|
||||
docs/apidoc/
|
||||
docs/userdoc/
|
||||
_website/
|
||||
*.ebuild
|
||||
.*.sw?
|
||||
MANIFEST
|
|
@ -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.
|
|
@ -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
|
|
@ -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
|
||||
}
|
|
@ -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__
|
|
@ -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
|
|
@ -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 */
|
|
@ -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
|
|
@ -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)
|
|
@ -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)
|
|
@ -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"
|
|
@ -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
|
|
@ -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)
|
|
@ -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
|
|
@ -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})
|
|
@ -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)
|
|
@ -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)
|
|
@ -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
|
|
@ -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()
|
|
@ -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
|
|
@ -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)
|
|
@ -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)
|
|
@ -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
|
|
@ -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
|
|
@ -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()
|
||||
|
||||
|
|
@ -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))
|
|
@ -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
|
|
@ -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)
|
|
@ -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)
|
|
@ -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"
|
|
@ -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
|
|
@ -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)
|
|
@ -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
|
|
@ -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})
|
|
@ -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)
|
|
@ -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)
|
|
@ -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
|
|
@ -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()
|
|
@ -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
|
|
@ -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)
|
|
@ -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)
|
|
@ -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
|
|
@ -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
|
|
@ -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()
|
||||
|
||||
|
|
@ -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))
|
|
@ -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:])
|
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -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;
|
||||
}
|
|
@ -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)
|
|
@ -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()))
|
|
@ -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()))
|
|
@ -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);
|
|
@ -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');
|
||||
}
|
||||
};
|
|
@ -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
|
|
@ -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
|
|
@ -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.
|
|
@ -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
|
|
@ -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
|
|
@ -0,0 +1 @@
|
|||
rjsmin (1.0)
|
|
@ -0,0 +1 @@
|
|||
Javascript Minifier
|
|
@ -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;
|
||||
}
|
|
@ -0,0 +1,2 @@
|
|||
{% extends "default/layout.html" %}
|
||||
{% set css_files = css_files + ['_static/ci.css'] %}
|
|
@ -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
|
|
@ -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
|
|
@ -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)
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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()
|
|
@ -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__)
|
|
@ -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
|
|
@ -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 ------------------------- */
|
|
@ -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()))
|
|
@ -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()
|
Loading…
Reference in New Issue