initial import.
This commit is contained in:
commit
f7d6457e2d
13
.gitignore
vendored
Normal file
13
.gitignore
vendored
Normal file
@ -0,0 +1,13 @@
|
||||
Makefile
|
||||
*.py[cod]
|
||||
*.so
|
||||
dist
|
||||
build
|
||||
__pycache__
|
||||
docs/_userdoc/_build/
|
||||
docs/apidoc/
|
||||
docs/userdoc/
|
||||
_website/
|
||||
*.ebuild
|
||||
.*.sw?
|
||||
MANIFEST
|
201
LICENSE
Normal file
201
LICENSE
Normal file
@ -0,0 +1,201 @@
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
127
README.rst
Normal file
127
README.rst
Normal file
@ -0,0 +1,127 @@
|
||||
.. -*- coding: utf-8 -*-
|
||||
|
||||
TABLE OF CONTENTS
|
||||
=================
|
||||
|
||||
1. Introduction
|
||||
2. Copyright and License
|
||||
3. System Requirements
|
||||
4. Installation
|
||||
5. Documentation
|
||||
6. Bugs
|
||||
7. Author Information
|
||||
|
||||
|
||||
INTRODUCTION
|
||||
============
|
||||
|
||||
rJSmin is a javascript minifier written in python.
|
||||
|
||||
The minifier is based on the semantics of `jsmin.c by Douglas Crockford`_\.
|
||||
|
||||
The module is a re-implementation aiming for speed, so it can be used at
|
||||
runtime (rather than during a preprocessing step). Usually it produces the
|
||||
same results as the original ``jsmin.c``. It differs in the following ways:
|
||||
|
||||
- there is no error detection: unterminated string, regex and comment
|
||||
literals are treated as regular javascript code and minified as such.
|
||||
- Control characters inside string and regex literals are left untouched; they
|
||||
are not converted to spaces (nor to \n)
|
||||
- Newline characters are not allowed inside string and regex literals, except
|
||||
for line continuations in string literals (ECMA-5).
|
||||
- "return /regex/" is recognized correctly.
|
||||
- "+ +" and "- -" sequences are not collapsed to '++' or '--'
|
||||
- Newlines before ! operators are removed more sensibly
|
||||
- rJSmin does not handle streams, but only complete strings. (However, the
|
||||
module provides a "streamy" interface).
|
||||
|
||||
Since most parts of the logic are handled by the regex engine it's way
|
||||
faster than the original python port of ``jsmin.c`` by Baruch Even. The speed
|
||||
factor varies between about 6 and 55 depending on input and python version
|
||||
(it gets faster the more compressed the input already is). Compared to the
|
||||
speed-refactored python port by Dave St.Germain the performance gain is less
|
||||
dramatic but still between 1.2 and 7. See the docs/BENCHMARKS file for
|
||||
details.
|
||||
|
||||
rjsmin.c is a reimplementation of rjsmin.py in C and speeds it up even more.
|
||||
|
||||
.. _jsmin.c by Douglas Crockford: http://www.crockford.com/javascript/jsmin.c
|
||||
|
||||
|
||||
COPYRIGHT AND LICENSE
|
||||
=====================
|
||||
|
||||
Copyright 2011 - 2013
|
||||
André Malo or his licensors, as applicable.
|
||||
|
||||
The whole package (except for the files in the bench/ directory)
|
||||
is distributed under the Apache License Version 2.0. You'll find a copy in the
|
||||
root directory of the distribution or online at:
|
||||
<http://www.apache.org/licenses/LICENSE-2.0>.
|
||||
|
||||
|
||||
SYSTEM REQUIREMENTS
|
||||
===================
|
||||
|
||||
Both python 2 (>=2.4) and python 3 are supported.
|
||||
|
||||
|
||||
INSTALLATION
|
||||
============
|
||||
|
||||
rJSmin is set up using the standard python distutils. So you can install
|
||||
it using the usual command:
|
||||
|
||||
$ python setup.py install
|
||||
|
||||
The command above will install rJSmin into python's library path.
|
||||
|
||||
Additionally it will install the documentation. On unices it will be
|
||||
installed by default into <prefix>/share/doc/rjsmin.
|
||||
|
||||
For customization options please study the output of
|
||||
|
||||
$ python setup.py --help
|
||||
|
||||
Especially the following options may be interesting for you:
|
||||
|
||||
--without-c-extensions Don't install C extensions
|
||||
--without-docs Do not install documentation files
|
||||
|
||||
Alternatively just copy rjsmin.py into your project and use it.
|
||||
|
||||
|
||||
DOCUMENTATION
|
||||
=============
|
||||
|
||||
A generated API documentation is available in the docs/apidoc/ directory.
|
||||
But you can just look into the module. It provides a simple function,
|
||||
called jsmin which takes the script as a string and returns the minified
|
||||
script as a string.
|
||||
|
||||
The module additionally provides a "streamy" interface similar to the one
|
||||
jsmin.c provides:
|
||||
|
||||
$ python -mrjsmin <script >minified
|
||||
|
||||
The latest documentation is also available online at
|
||||
<http://opensource.perlig.de/rjsmin/>.
|
||||
|
||||
|
||||
BUGS
|
||||
====
|
||||
|
||||
No bugs, of course. ;-)
|
||||
But if you've found one or have an idea how to improve rjsmin,
|
||||
please send a mail to <rjsmin-bugs@perlig.de>.
|
||||
|
||||
|
||||
AUTHOR INFORMATION
|
||||
==================
|
||||
|
||||
André "nd" Malo <nd@perlig.de>
|
||||
GPG: 0x8103A37E
|
||||
|
||||
|
||||
If God intended people to be naked, they would be born that way.
|
||||
-- Oscar Wilde
|
25
_pkg/ebuilds/rjsmin.ebuild.in
Normal file
25
_pkg/ebuilds/rjsmin.ebuild.in
Normal file
@ -0,0 +1,25 @@
|
||||
# Copyright 2011-2013 Andr\xe9 Malo
|
||||
# Distributed under the terms of the GNU General Public License v2
|
||||
# $Header$
|
||||
|
||||
EAPI="5"
|
||||
PYTHON_COMPAT=( python{2_5,2_6,2_7,3_1,3_2,3_3} pypy{1_9,2_0} jython{2_5,2_7} )
|
||||
|
||||
inherit distutils-r1
|
||||
|
||||
DESCRIPTION="Fast javascript minifier for python"
|
||||
HOMEPAGE="http://opensource.perlig.de/rjsmin/"
|
||||
SRC_URI="http://storage.perlig.de/rjsmin/${P}.tar.bz2"
|
||||
RESTRICT="mirror"
|
||||
|
||||
LICENSE="Apache-2"
|
||||
SLOT="0"
|
||||
KEYWORDS="~amd64 ~ppc ~x86 ~x86-fbsd ~amd64-linux ~x86-linux ~ppc-macos ~x64-macos ~x86-macos"
|
||||
IUSE="doc"
|
||||
|
||||
DOCS=( README.rst docs/CHANGES )
|
||||
HTML_DOCS=( docs/apidoc )
|
||||
|
||||
python_install() {
|
||||
distutils-r1_python_install --without-docs
|
||||
}
|
243
_pkg/pylint.conf
Normal file
243
_pkg/pylint.conf
Normal file
@ -0,0 +1,243 @@
|
||||
# pylint-version: 0.21.0
|
||||
[MASTER]
|
||||
|
||||
# Specify a configuration file.
|
||||
#rcfile=
|
||||
|
||||
# Python code to execute, usually for sys.path manipulation such as
|
||||
# pygtk.require().
|
||||
#init-hook=
|
||||
|
||||
# Profiled execution.
|
||||
profile=no
|
||||
|
||||
# Add <file or directory> to the black list. It should be a base name, not a
|
||||
# path. You may set this option multiple times.
|
||||
ignore=
|
||||
.svn, _tdi_impl.so
|
||||
|
||||
# Pickle collected data for later comparisons.
|
||||
persistent=no
|
||||
|
||||
# List of plugins (as comma separated values of python modules names) to load,
|
||||
# usually to register additional checkers.
|
||||
load-plugins=
|
||||
|
||||
|
||||
[MESSAGES CONTROL]
|
||||
|
||||
# Enable the message, report, category or checker with the given id(s). You can
|
||||
# either give multiple identifier separated by comma (,) or put this option
|
||||
# multiple time.
|
||||
#enable=
|
||||
|
||||
# Disable the message, report, category or checker with the given id(s). You
|
||||
# can either give multiple identifier separated by comma (,) or put this option
|
||||
# multiple time.
|
||||
disable=
|
||||
I0011,
|
||||
W0142,
|
||||
R0201, R0923,
|
||||
|
||||
|
||||
[REPORTS]
|
||||
|
||||
# Set the output format. Available formats are text, parseable, colorized, msvs
|
||||
# (visual studio) and html
|
||||
output-format=parseable
|
||||
|
||||
# Include message's id in output
|
||||
include-ids=yes
|
||||
|
||||
# Put messages in a separate file for each module / package specified on the
|
||||
# command line instead of printing them on stdout. Reports (if any) will be
|
||||
# written in a file name "pylint_global.[txt|html]".
|
||||
files-output=no
|
||||
|
||||
# Tells whether to display a full report or only the messages
|
||||
reports=no
|
||||
|
||||
# Python expression which should return a note less than 10 (10 is the highest
|
||||
# note). You have access to the variables errors warning, statement which
|
||||
# respectively contain the number of errors / warnings messages and the total
|
||||
# number of statements analyzed. This is used by the global evaluation report
|
||||
# (R0004).
|
||||
evaluation=10.0 - ((float(5 * error + warning + refactor + convention) / statement) * 10)
|
||||
|
||||
# Add a comment according to your evaluation note. This is used by the global
|
||||
# evaluation report (R0004).
|
||||
comment=no
|
||||
|
||||
|
||||
[FORMAT]
|
||||
|
||||
# Maximum number of characters on a single line.
|
||||
max-line-length=78
|
||||
|
||||
# Maximum number of lines in a module
|
||||
max-module-lines=1500
|
||||
|
||||
# String used as indentation unit. This is usually " " (4 spaces) or "\t" (1
|
||||
# tab).
|
||||
indent-string=' '
|
||||
|
||||
|
||||
[VARIABLES]
|
||||
|
||||
# Tells whether we should check for unused import in __init__ files.
|
||||
init-import=yes
|
||||
|
||||
# A regular expression matching names used for dummy variables (i.e. not used).
|
||||
dummy-variables-rgx=_|dummy|(?:kw)?args
|
||||
|
||||
# List of additional names supposed to be defined in builtins. Remember that
|
||||
# you should avoid to define new builtins when possible.
|
||||
additional-builtins=
|
||||
|
||||
|
||||
[TYPECHECK]
|
||||
|
||||
# Tells whether missing members accessed in mixin class should be ignored. A
|
||||
# mixin class is detected if its name ends with "mixin" (case insensitive).
|
||||
ignore-mixin-members=yes
|
||||
|
||||
# List of classes names for which member attributes should not be checked
|
||||
# (useful for classes with attributes dynamically set).
|
||||
ignored-classes=
|
||||
|
||||
# When zope mode is activated, add a predefined set of Zope acquired attributes
|
||||
# to generated-members.
|
||||
zope=no
|
||||
|
||||
# List of members which are set dynamically and missed by pylint inference
|
||||
# system, and so shouldn't trigger E0201 when accessed.
|
||||
generated-members=
|
||||
|
||||
|
||||
[SIMILARITIES]
|
||||
|
||||
# Minimum lines number of a similarity.
|
||||
min-similarity-lines=4
|
||||
|
||||
# Ignore comments when computing similarities.
|
||||
ignore-comments=yes
|
||||
|
||||
# Ignore docstrings when computing similarities.
|
||||
ignore-docstrings=yes
|
||||
|
||||
|
||||
[MISCELLANEOUS]
|
||||
|
||||
# List of note tags to take in consideration, separated by a comma.
|
||||
notes=FIXME,XXX,TODO
|
||||
|
||||
|
||||
[BASIC]
|
||||
|
||||
# Required attributes for module, separated by a comma
|
||||
required-attributes=
|
||||
__author__, __docformat__
|
||||
|
||||
# List of builtins function names that should not be used, separated by a comma
|
||||
bad-functions=
|
||||
apply,input,exec,hasattr
|
||||
|
||||
# Regular expression which should only match correct module names
|
||||
module-rgx=[a-z_][a-z0-9_]*$
|
||||
|
||||
# Regular expression which should only match correct module level names
|
||||
const-rgx=(?:_?[A-Z][A-Z0-9_]{1,30}|_?[A-Z][a-zA-Z0-9]{2,30}|_?[a-z_][a-z0-9_]{2,30}|__.*__)$
|
||||
|
||||
# Regular expression which should only match correct class names
|
||||
class-rgx=_?[A-Z][a-zA-Z0-9]+$
|
||||
|
||||
# Regular expression which should only match correct function names
|
||||
function-rgx=(?:__[a-z]+__|_?[a-z_][a-z0-9_]*)$
|
||||
|
||||
# Regular expression which should only match correct method names
|
||||
method-rgx=(?:__[a-z]+__|_?[a-z_][a-z0-9_]*)$
|
||||
|
||||
# Regular expression which should only match correct instance attribute names
|
||||
attr-rgx=(?:[A-Z][A-Z0-9_]{2,30}|[a-z_][a-z0-9_]{2,30})$
|
||||
|
||||
# Regular expression which should only match correct argument names
|
||||
argument-rgx=[a-z_][a-z0-9_]{2,30}$
|
||||
|
||||
# Regular expression which should only match correct variable names
|
||||
variable-rgx=(?:[A-Z_][A-Z0-9_]{1,30}|[a-z_][a-z0-9_]{2,30})$
|
||||
|
||||
# Regular expression which should only match correct list comprehension /
|
||||
# generator expression variable names
|
||||
inlinevar-rgx=[A-Za-z_][A-Za-z0-9_]{,10}$
|
||||
|
||||
# Good variable names which should always be accepted, separated by a comma
|
||||
good-names=_,j,e,c
|
||||
|
||||
# Bad variable names which should always be refused, separated by a comma
|
||||
bad-names=foo,bar,baz,toto,tutu,tata
|
||||
|
||||
# Regular expression which should only match functions or classes name which do
|
||||
# not require a docstring
|
||||
no-docstring-rgx=__.*__
|
||||
|
||||
|
||||
[DESIGN]
|
||||
|
||||
# Maximum number of arguments for function / method
|
||||
max-args=10
|
||||
|
||||
# Argument names that match this expression will be ignored. Default to name
|
||||
# with leading underscore
|
||||
ignored-argument-names=_.*
|
||||
|
||||
# Maximum number of locals for function / method body
|
||||
max-locals=20
|
||||
|
||||
# Maximum number of return / yield for function / method body
|
||||
max-returns=6
|
||||
|
||||
# Maximum number of branch for function / method body
|
||||
max-branchs=12
|
||||
|
||||
# Maximum number of statements in function / method body
|
||||
max-statements=50
|
||||
|
||||
# Maximum number of parents for a class (see R0901).
|
||||
max-parents=7
|
||||
|
||||
# Maximum number of attributes for a class (see R0902).
|
||||
max-attributes=20
|
||||
|
||||
# Minimum number of public methods for a class (see R0903).
|
||||
min-public-methods=0
|
||||
|
||||
# Maximum number of public methods for a class (see R0904).
|
||||
max-public-methods=50
|
||||
|
||||
|
||||
[IMPORTS]
|
||||
|
||||
# Deprecated modules which should not be used, separated by a comma
|
||||
deprecated-modules=regsub,TERMIOS,Bastion,rexec
|
||||
|
||||
# Create a graph of every (i.e. internal and external) dependencies in the
|
||||
# given file (report R0402 must not be disabled)
|
||||
import-graph=
|
||||
|
||||
# Create a graph of external dependencies in the given file (report R0402 must
|
||||
# not be disabled)
|
||||
ext-import-graph=
|
||||
|
||||
# Create a graph of internal dependencies in the given file (report R0402 must
|
||||
# not be disabled)
|
||||
int-import-graph=
|
||||
|
||||
|
||||
[CLASSES]
|
||||
|
||||
# List of interface methods to ignore, separated by a comma. This is used for
|
||||
# instance to not check methods defines in Zope's Interface base class.
|
||||
ignore-iface-methods=
|
||||
|
||||
# List of method names used to declare (i.e. assign) instance attributes.
|
||||
defining-attr-methods=__init__,__new__
|
39
_setup/__init__.py
Normal file
39
_setup/__init__.py
Normal file
@ -0,0 +1,39 @@
|
||||
# -*- coding: ascii -*-
|
||||
#
|
||||
# Copyright 2007, 2008, 2009, 2010, 2011
|
||||
# Andr\xe9 Malo or his licensors, as applicable
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
"""
|
||||
================
|
||||
Package _setup
|
||||
================
|
||||
|
||||
This package provides tools for main package setup.
|
||||
"""
|
||||
__author__ = "Andr\xe9 Malo"
|
||||
__docformat__ = "restructuredtext en"
|
||||
|
||||
import os as _os
|
||||
import sys as _sys
|
||||
|
||||
if _sys.version_info[0] == 2:
|
||||
__path__ = [_os.path.join(__path__[0], 'py2')]
|
||||
__author__ = __author__.decode('latin-1')
|
||||
elif _sys.version_info[0] == 3:
|
||||
__path__ = [_os.path.join(__path__[0], 'py3')]
|
||||
else:
|
||||
raise RuntimeError("Unsupported python version")
|
||||
del _os, _sys
|
||||
|
||||
from _setup.setup import run # pylint: disable = W0611
|
244
_setup/include/cext.h
Normal file
244
_setup/include/cext.h
Normal file
@ -0,0 +1,244 @@
|
||||
/*
|
||||
* Copyright 2006, 2007, 2008, 2009, 2010, 2011
|
||||
* Andr\xe9 Malo or his licensors, as applicable
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/*
|
||||
* central naming stuff
|
||||
*/
|
||||
|
||||
#ifndef SETUP_CEXT_H
|
||||
#define SETUP_CEXT_H
|
||||
|
||||
#ifndef EXT_MODULE
|
||||
#error EXT_MODULE must be defined outside of this file (-DEXT_MODULE=...)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* include core header files
|
||||
*/
|
||||
#define PY_SSIZE_T_CLEAN
|
||||
|
||||
#include "Python.h"
|
||||
#include "structmember.h"
|
||||
|
||||
/*
|
||||
* define our helper macros depending on the stuff above
|
||||
*/
|
||||
#define STRINGIFY(n) STRINGIFY_HELPER(n)
|
||||
#define STRINGIFY_HELPER(n) #n
|
||||
#define CONCATENATE(first, second) CONCATENATE_HELPER(first, second)
|
||||
#define CONCATENATE_HELPER(first, second) first##second
|
||||
|
||||
#define EXT_MODULE_NAME STRINGIFY(EXT_MODULE)
|
||||
#ifdef EXT_PACKAGE
|
||||
#define EXT_PACKAGE_NAME STRINGIFY(EXT_PACKAGE)
|
||||
#define EXT_MODULE_PATH EXT_PACKAGE_NAME "." EXT_MODULE_NAME
|
||||
#else
|
||||
#define EXT_PACKAGE_NAME ""
|
||||
#define EXT_MODULE_PATH EXT_MODULE_NAME
|
||||
#endif
|
||||
|
||||
#define EXT_DOCS_VAR CONCATENATE(var, CONCATENATE(EXT_MODULE, __doc__))
|
||||
#define EXT_METHODS_VAR CONCATENATE(var, CONCATENATE(EXT_MODULE, _methods))
|
||||
#define EXT_METHODS static PyMethodDef EXT_METHODS_VAR[]
|
||||
|
||||
#define EXT_DEFINE_VAR CONCATENATE(var, CONCATENATE(EXT_MODULE, _module))
|
||||
|
||||
/* Py3K Support */
|
||||
#if PY_MAJOR_VERSION >= 3
|
||||
|
||||
#define EXT3
|
||||
|
||||
#ifndef PyMODINIT_FUNC
|
||||
#define EXT_INIT_FUNC PyObject *CONCATENATE(PyInit_, EXT_MODULE)(void)
|
||||
#else
|
||||
#define EXT_INIT_FUNC PyMODINIT_FUNC CONCATENATE(PyInit_, EXT_MODULE)(void)
|
||||
#endif
|
||||
|
||||
#define EXT_DEFINE(name, methods, doc) \
|
||||
static struct PyModuleDef EXT_DEFINE_VAR = { \
|
||||
PyModuleDef_HEAD_INIT, \
|
||||
name, \
|
||||
doc, \
|
||||
-1, \
|
||||
methods, \
|
||||
NULL, \
|
||||
NULL, \
|
||||
NULL, \
|
||||
NULL \
|
||||
}
|
||||
|
||||
#define EXT_CREATE(def) (PyModule_Create(def))
|
||||
#define EXT_INIT_ERROR(module) do {Py_XDECREF(module); return NULL;} while(0)
|
||||
#define EXT_INIT_RETURN(module) return module
|
||||
|
||||
#else /* end py3k */
|
||||
|
||||
#define EXT2
|
||||
|
||||
#ifndef PyMODINIT_FUNC
|
||||
#define EXT_INIT_FUNC void CONCATENATE(init, EXT_MODULE)(void)
|
||||
#else
|
||||
#define EXT_INIT_FUNC PyMODINIT_FUNC CONCATENATE(init, EXT_MODULE)(void)
|
||||
#endif
|
||||
|
||||
#define EXT_DEFINE__STRUCT \
|
||||
CONCATENATE(struct, CONCATENATE(EXT_MODULE, _module))
|
||||
|
||||
struct EXT_DEFINE__STRUCT {
|
||||
char *m_name;
|
||||
char *m_doc;
|
||||
PyMethodDef *m_methods;
|
||||
};
|
||||
#define EXT_DEFINE(name, methods, doc) \
|
||||
static struct EXT_DEFINE__STRUCT EXT_DEFINE_VAR = { \
|
||||
name, \
|
||||
doc, \
|
||||
methods \
|
||||
}
|
||||
|
||||
#define EXT_CREATE(def) ((def)->m_doc \
|
||||
? Py_InitModule3((def)->m_name, (def)->m_methods, (def)->m_doc) \
|
||||
: Py_InitModule((def)->m_name, (def)->m_methods) \
|
||||
)
|
||||
#define EXT_INIT_ERROR(module) return
|
||||
#define EXT_INIT_RETURN(module) return
|
||||
|
||||
#endif /* end py2K */
|
||||
|
||||
#define EXT_INIT_TYPE(module, type) do { \
|
||||
if (PyType_Ready(type) < 0) \
|
||||
EXT_INIT_ERROR(module); \
|
||||
} while (0)
|
||||
|
||||
#define EXT_ADD_TYPE(module, name, type) do { \
|
||||
Py_INCREF(type); \
|
||||
if (PyModule_AddObject(module, name, (PyObject *)(type)) < 0) \
|
||||
EXT_INIT_ERROR(module); \
|
||||
} while (0)
|
||||
|
||||
#define EXT_ADD_UNICODE(module, name, string, encoding) do { \
|
||||
if (PyModule_AddObject( \
|
||||
module, \
|
||||
name, \
|
||||
PyUnicode_Decode( \
|
||||
string, \
|
||||
sizeof(string) - 1, \
|
||||
encoding, \
|
||||
"strict" \
|
||||
)) < 0) \
|
||||
EXT_INIT_ERROR(module); \
|
||||
} while (0)
|
||||
|
||||
#define EXT_ADD_STRING(module, name, string) do { \
|
||||
if (PyModule_AddStringConstant(module, name, string) < 0) \
|
||||
EXT_INIT_ERROR(module); \
|
||||
} while (0)
|
||||
|
||||
#define EXT_ADD_INT(module, name, number) do { \
|
||||
if (PyModule_AddIntConstant(module, name, number) < 0) \
|
||||
EXT_INIT_ERROR(module); \
|
||||
} while (0)
|
||||
|
||||
|
||||
/* PEP 353 support, implemented as of python 2.5 */
|
||||
#if PY_VERSION_HEX < 0x02050000
|
||||
typedef int Py_ssize_t;
|
||||
#define PyInt_FromSsize_t(arg) PyInt_FromLong((long)arg)
|
||||
#define PyInt_AsSsize_t(arg) (int)PyInt_AsLong(arg)
|
||||
#define PY_SSIZE_T_MAX ((Py_ssize_t)INT_MAX)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* some helper macros (Python 2.4)
|
||||
*/
|
||||
#ifndef Py_VISIT
|
||||
#define Py_VISIT(op) do { \
|
||||
if (op) { \
|
||||
int vret = visit((op), arg); \
|
||||
if (vret) return vret; \
|
||||
} \
|
||||
} while (0)
|
||||
#endif
|
||||
|
||||
#ifdef Py_CLEAR
|
||||
#undef Py_CLEAR
|
||||
#endif
|
||||
#define Py_CLEAR(op) do { \
|
||||
if (op) { \
|
||||
PyObject *tmp__ = (PyObject *)(op); \
|
||||
(op) = NULL; \
|
||||
Py_DECREF(tmp__); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#ifndef Py_RETURN_NONE
|
||||
#define Py_RETURN_NONE return Py_INCREF(Py_None), Py_None
|
||||
#endif
|
||||
|
||||
#ifndef Py_RETURN_FALSE
|
||||
#define Py_RETURN_FALSE return Py_INCREF(Py_False), Py_False
|
||||
#endif
|
||||
|
||||
#ifndef Py_RETURN_TRUE
|
||||
#define Py_RETURN_TRUE return Py_INCREF(Py_True), Py_True
|
||||
#endif
|
||||
|
||||
/* Macros for inline documentation. (Python 2.3) */
|
||||
#ifndef PyDoc_VAR
|
||||
#define PyDoc_VAR(name) static char name[]
|
||||
#endif
|
||||
|
||||
#ifndef PyDoc_STRVAR
|
||||
#define PyDoc_STRVAR(name,str) PyDoc_VAR(name) = PyDoc_STR(str)
|
||||
#endif
|
||||
|
||||
#ifndef PyDoc_STR
|
||||
#ifdef WITH_DOC_STRINGS
|
||||
#define PyDoc_STR(str) str
|
||||
#else
|
||||
#define PyDoc_STR(str) ""
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* Basestring check (basestring introduced in Python 2.3) */
|
||||
#if PY_VERSION_HEX < 0x02030000
|
||||
#define BaseString_Check(type) ( \
|
||||
PyObject_TypeCheck((type), &PyString_Type) \
|
||||
|| PyObject_TypeCheck((type), &PyUnicode_Type) \
|
||||
)
|
||||
#else
|
||||
#define BaseString_Check(type) PyObject_TypeCheck((type), &PyBaseString_Type)
|
||||
#endif
|
||||
|
||||
#define GENERIC_ALLOC(type) \
|
||||
((void *)((PyTypeObject *)type)->tp_alloc(type, (Py_ssize_t)0))
|
||||
|
||||
/* PyPy doesn't define it */
|
||||
#ifndef PyType_IS_GC
|
||||
#define PyType_IS_GC(t) PyType_HasFeature((t), Py_TPFLAGS_HAVE_GC)
|
||||
#endif
|
||||
|
||||
#define DEFINE_GENERIC_DEALLOC(prefix) \
|
||||
static void prefix##_dealloc(void *self) \
|
||||
{ \
|
||||
if (PyType_IS_GC(((PyObject *)self)->ob_type)) \
|
||||
PyObject_GC_UnTrack(self); \
|
||||
(void)prefix##_clear(self); \
|
||||
((PyObject *)self)->ob_type->tp_free((PyObject *)self); \
|
||||
}
|
||||
|
||||
#endif /* SETUP_CEXT_H */
|
27
_setup/py2/__init__.py
Normal file
27
_setup/py2/__init__.py
Normal file
@ -0,0 +1,27 @@
|
||||
# -*- coding: ascii -*-
|
||||
#
|
||||
# Copyright 2007, 2008, 2009, 2010, 2011
|
||||
# Andr\xe9 Malo or his licensors, as applicable
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
"""
|
||||
================
|
||||
Package _setup
|
||||
================
|
||||
|
||||
This package provides tools for main package setup.
|
||||
"""
|
||||
__author__ = u"Andr\xe9 Malo"
|
||||
__docformat__ = "restructuredtext en"
|
||||
|
||||
from _setup.setup import run # pylint: disable = W0611
|
267
_setup/py2/commands.py
Normal file
267
_setup/py2/commands.py
Normal file
@ -0,0 +1,267 @@
|
||||
# -*- coding: ascii -*-
|
||||
#
|
||||
# Copyright 2007, 2008, 2009, 2010, 2011
|
||||
# Andr\xe9 Malo or his licensors, as applicable
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
"""
|
||||
===================
|
||||
Command extenders
|
||||
===================
|
||||
|
||||
Command extenders.
|
||||
"""
|
||||
__author__ = u"Andr\xe9 Malo"
|
||||
__docformat__ = "restructuredtext en"
|
||||
__test__ = False
|
||||
|
||||
from distutils import fancy_getopt as _fancy_getopt
|
||||
from distutils.command import build as _build
|
||||
from distutils.command import build_ext as _build_ext
|
||||
from distutils.command import install as _install
|
||||
from distutils.command import install_data as _install_data
|
||||
from distutils.command import install_lib as _install_lib
|
||||
import os as _os
|
||||
|
||||
from _setup.util import log
|
||||
|
||||
_option_defaults = {}
|
||||
_option_inherits = {}
|
||||
_option_finalizers = {}
|
||||
_command_mapping = {
|
||||
'install': 'Install',
|
||||
'install_data': 'InstallData',
|
||||
'install_lib': 'InstallLib',
|
||||
'build': 'Build',
|
||||
'build_ext': 'BuildExt',
|
||||
}
|
||||
|
||||
|
||||
def add_option(command, long_name, help_text, short_name=None, default=None,
|
||||
inherit=None):
|
||||
""" Add an option """
|
||||
try:
|
||||
command_class = globals()[_command_mapping[command]]
|
||||
except KeyError:
|
||||
raise ValueError("Unknown command %r" % (command,))
|
||||
for opt in command_class.user_options:
|
||||
if opt[0] == long_name:
|
||||
break
|
||||
else:
|
||||
opt = (long_name, short_name, help_text)
|
||||
command_class.user_options.append(opt)
|
||||
if not long_name.endswith('='):
|
||||
command_class.boolean_options.append(long_name)
|
||||
attr_name = _fancy_getopt.translate_longopt(long_name)
|
||||
else:
|
||||
attr_name = _fancy_getopt.translate_longopt(long_name[:-1])
|
||||
if not _option_defaults.has_key(command):
|
||||
_option_defaults[command] = []
|
||||
if inherit is not None:
|
||||
if isinstance(inherit, (str, unicode)):
|
||||
inherit = [inherit]
|
||||
for i_inherit in inherit:
|
||||
add_option(
|
||||
i_inherit, long_name, help_text, short_name, default
|
||||
)
|
||||
default = None
|
||||
if not _option_inherits.has_key(command):
|
||||
_option_inherits[command] = []
|
||||
for i_inherit in inherit:
|
||||
for i_command, opt_name in _option_inherits[command]:
|
||||
if i_command == i_inherit and opt_name == attr_name:
|
||||
break
|
||||
else:
|
||||
_option_inherits[command].append((i_inherit, attr_name))
|
||||
_option_defaults[command].append((attr_name, default))
|
||||
|
||||
|
||||
def add_finalizer(command, key, func):
|
||||
""" Add finalizer """
|
||||
if not _option_finalizers.has_key(command):
|
||||
_option_finalizers[command] = {}
|
||||
if not _option_finalizers[command].has_key(key):
|
||||
_option_finalizers[command][key] = func
|
||||
|
||||
|
||||
class Install(_install.install):
|
||||
""" Extended installer to reflect the additional data options """
|
||||
user_options = _install.install.user_options + [
|
||||
('single-version-externally-managed', None,
|
||||
"Compat option. Does not a thing."),
|
||||
]
|
||||
boolean_options = _install.install.boolean_options + [
|
||||
'single-version-externally-managed'
|
||||
]
|
||||
|
||||
def initialize_options(self):
|
||||
""" Prepare for new options """
|
||||
_install.install.initialize_options(self)
|
||||
self.single_version_externally_managed = None
|
||||
if _option_defaults.has_key('install'):
|
||||
for opt_name, default in _option_defaults['install']:
|
||||
setattr(self, opt_name, default)
|
||||
|
||||
def finalize_options(self):
|
||||
""" Finalize options """
|
||||
_install.install.finalize_options(self)
|
||||
if _option_inherits.has_key('install'):
|
||||
for parent, opt_name in _option_inherits['install']:
|
||||
self.set_undefined_options(parent, (opt_name, opt_name))
|
||||
if _option_finalizers.has_key('install'):
|
||||
for func in _option_finalizers['install'].values():
|
||||
func(self)
|
||||
|
||||
|
||||
class InstallData(_install_data.install_data):
|
||||
""" Extended data installer """
|
||||
user_options = _install_data.install_data.user_options + []
|
||||
boolean_options = _install_data.install_data.boolean_options + []
|
||||
|
||||
def initialize_options(self):
|
||||
""" Prepare for new options """
|
||||
_install_data.install_data.initialize_options(self)
|
||||
if _option_defaults.has_key('install_data'):
|
||||
for opt_name, default in _option_defaults['install_data']:
|
||||
setattr(self, opt_name, default)
|
||||
|
||||
def finalize_options(self):
|
||||
""" Finalize options """
|
||||
_install_data.install_data.finalize_options(self)
|
||||
if _option_inherits.has_key('install_data'):
|
||||
for parent, opt_name in _option_inherits['install_data']:
|
||||
self.set_undefined_options(parent, (opt_name, opt_name))
|
||||
if _option_finalizers.has_key('install_data'):
|
||||
for func in _option_finalizers['install_data'].values():
|
||||
func(self)
|
||||
|
||||
|
||||
class InstallLib(_install_lib.install_lib):
|
||||
""" Extended lib installer """
|
||||
user_options = _install_lib.install_lib.user_options + []
|
||||
boolean_options = _install_lib.install_lib.boolean_options + []
|
||||
|
||||
def initialize_options(self):
|
||||
""" Prepare for new options """
|
||||
_install_lib.install_lib.initialize_options(self)
|
||||
if _option_defaults.has_key('install_lib'):
|
||||
for opt_name, default in _option_defaults['install_lib']:
|
||||
setattr(self, opt_name, default)
|
||||
|
||||
def finalize_options(self):
|
||||
""" Finalize options """
|
||||
_install_lib.install_lib.finalize_options(self)
|
||||
if _option_inherits.has_key('install_lib'):
|
||||
for parent, opt_name in _option_inherits['install_lib']:
|
||||
self.set_undefined_options(parent, (opt_name, opt_name))
|
||||
if _option_finalizers.has_key('install_lib'):
|
||||
for func in _option_finalizers['install_lib'].values():
|
||||
func(self)
|
||||
|
||||
|
||||
class BuildExt(_build_ext.build_ext):
|
||||
"""
|
||||
Extended extension builder class
|
||||
|
||||
This class allows extensions to provide a ``check_prerequisites`` method
|
||||
which is called before actually building it. The method takes the
|
||||
`BuildExt` instance and returns whether the extension should be skipped or
|
||||
not.
|
||||
"""
|
||||
|
||||
def initialize_options(self):
|
||||
""" Prepare for new options """
|
||||
_build_ext.build_ext.initialize_options(self)
|
||||
if _option_defaults.has_key('build_ext'):
|
||||
for opt_name, default in _option_defaults['build_ext']:
|
||||
setattr(self, opt_name, default)
|
||||
|
||||
def finalize_options(self):
|
||||
""" Finalize options """
|
||||
_build_ext.build_ext.finalize_options(self)
|
||||
if _option_inherits.has_key('build_ext'):
|
||||
for parent, opt_name in _option_inherits['build_ext']:
|
||||
self.set_undefined_options(parent, (opt_name, opt_name))
|
||||
if _option_finalizers.has_key('build_ext'):
|
||||
for func in _option_finalizers['build_ext'].values():
|
||||
func(self)
|
||||
|
||||
def build_extension(self, ext):
|
||||
"""
|
||||
Build C extension - with extended functionality
|
||||
|
||||
The following features are added here:
|
||||
|
||||
- ``ext.check_prerequisites`` is called before the extension is being
|
||||
built. See `Extension` for details. If the method does not exist,
|
||||
simply no check will be run.
|
||||
- The macros ``EXT_PACKAGE`` and ``EXT_MODULE`` will be filled (or
|
||||
unset) depending on the extensions name, but only if they are not
|
||||
already defined.
|
||||
|
||||
:Parameters:
|
||||
`ext` : `Extension`
|
||||
The extension to build. If it's a pure
|
||||
``distutils.core.Extension``, simply no prequisites check is
|
||||
applied.
|
||||
|
||||
:Return: whatever ``distutils.command.build_ext.build_ext`` returns
|
||||
:Rtype: any
|
||||
"""
|
||||
# handle name macros
|
||||
macros = dict(ext.define_macros or ())
|
||||
tup = ext.name.split('.')
|
||||
if len(tup) == 1:
|
||||
pkg, mod = None, tup[0]
|
||||
else:
|
||||
pkg, mod = '.'.join(tup[:-1]), tup[-1]
|
||||
if pkg is not None and 'EXT_PACKAGE' not in macros:
|
||||
ext.define_macros.append(('EXT_PACKAGE', pkg))
|
||||
if 'EXT_MODULE' not in macros:
|
||||
ext.define_macros.append(('EXT_MODULE', mod))
|
||||
if pkg is None:
|
||||
macros = dict(ext.undef_macros or ())
|
||||
if 'EXT_PACKAGE' not in macros:
|
||||
ext.undef_macros.append('EXT_PACKAGE')
|
||||
|
||||
# handle prereq checks
|
||||
try:
|
||||
checker = ext.check_prerequisites
|
||||
except AttributeError:
|
||||
pass
|
||||
else:
|
||||
if checker(self):
|
||||
log.info("Skipping %s extension" % ext.name)
|
||||
return
|
||||
|
||||
return _build_ext.build_ext.build_extension(self, ext)
|
||||
|
||||
|
||||
class Build(_build.build):
|
||||
|
||||
def initialize_options(self):
|
||||
""" Prepare for new options """
|
||||
_build.build.initialize_options(self)
|
||||
if _option_defaults.has_key('build'):
|
||||
for opt_name, default in _option_defaults['build']:
|
||||
setattr(self, opt_name, default)
|
||||
|
||||
def finalize_options(self):
|
||||
""" Finalize options """
|
||||
_build.build.finalize_options(self)
|
||||
if _option_inherits.has_key('build'):
|
||||
for parent, opt_name in _option_inherits['build']:
|
||||
self.set_undefined_options(parent, (opt_name, opt_name))
|
||||
if _option_finalizers.has_key('build'):
|
||||
for func in _option_finalizers['build'].values():
|
||||
func(self)
|
165
_setup/py2/data.py
Normal file
165
_setup/py2/data.py
Normal file
@ -0,0 +1,165 @@
|
||||
# -*- coding: ascii -*-
|
||||
#
|
||||
# Copyright 2007, 2008, 2009, 2010, 2011
|
||||
# Andr\xe9 Malo or his licensors, as applicable
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
"""
|
||||
===================
|
||||
Data distribution
|
||||
===================
|
||||
|
||||
This module provides tools to simplify data distribution.
|
||||
"""
|
||||
__author__ = u"Andr\xe9 Malo"
|
||||
__docformat__ = "restructuredtext en"
|
||||
|
||||
from distutils import filelist as _filelist
|
||||
import os as _os
|
||||
import posixpath as _posixpath
|
||||
import sys as _sys
|
||||
|
||||
from _setup import commands as _commands
|
||||
|
||||
|
||||
def splitpath(path):
|
||||
""" Split a path """
|
||||
drive, path = '', _os.path.normpath(path)
|
||||
try:
|
||||
splitunc = _os.path.splitunc
|
||||
except AttributeError:
|
||||
pass
|
||||
else:
|
||||
drive, path = splitunc(path)
|
||||
if not drive:
|
||||
drive, path = _os.path.splitdrive(path)
|
||||
elems = []
|
||||
try:
|
||||
sep = _os.path.sep
|
||||
except AttributeError:
|
||||
sep = _os.path.join('1', '2')[1:-1]
|
||||
while 1:
|
||||
prefix, path = _os.path.split(path)
|
||||
elems.append(path)
|
||||
if prefix in ('', sep):
|
||||
drive = _os.path.join(drive, prefix)
|
||||
break
|
||||
path = prefix
|
||||
elems.reverse()
|
||||
return drive, elems
|
||||
|
||||
|
||||
def finalizer(installer):
|
||||
""" Finalize install_data """
|
||||
data_files = []
|
||||
for item in installer.data_files:
|
||||
if not isinstance(item, Data):
|
||||
data_files.append(item)
|
||||
continue
|
||||
data_files.extend(item.flatten(installer))
|
||||
installer.data_files = data_files
|
||||
|
||||
|
||||
class Data(object):
|
||||
""" File list container """
|
||||
|
||||
def __init__(self, files, target=None, preserve=0, strip=0,
|
||||
prefix=None):
|
||||
""" Initialization """
|
||||
self._files = files
|
||||
self._target = target
|
||||
self._preserve = preserve
|
||||
self._strip = strip
|
||||
self._prefix = prefix
|
||||
self.fixup_commands()
|
||||
|
||||
def fixup_commands(self):
|
||||
pass
|
||||
|
||||
def from_templates(cls, *templates, **kwargs):
|
||||
""" Initialize from template """
|
||||
files = _filelist.FileList()
|
||||
for tpl in templates:
|
||||
for line in tpl.split(';'):
|
||||
files.process_template_line(line.strip())
|
||||
files.sort()
|
||||
files.remove_duplicates()
|
||||
result = []
|
||||
for filename in files.files:
|
||||
_, elems = splitpath(filename)
|
||||
if '.svn' in elems:
|
||||
continue
|
||||
result.append(filename)
|
||||
return cls(result, **kwargs)
|
||||
from_templates = classmethod(from_templates)
|
||||
|
||||
def flatten(self, installer):
|
||||
""" Flatten the file list to (target, file) tuples """
|
||||
# pylint: disable = W0613
|
||||
if self._prefix:
|
||||
_, prefix = splitpath(self._prefix)
|
||||
telems = prefix
|
||||
else:
|
||||
telems = []
|
||||
|
||||
tmap = {}
|
||||
for fname in self._files:
|
||||
(_, name), target = splitpath(fname), telems
|
||||
if self._preserve:
|
||||
if self._strip:
|
||||
name = name[max(0, min(self._strip, len(name) - 1)):]
|
||||
if len(name) > 1:
|
||||
target = telems + name[:-1]
|
||||
tmap.setdefault(_posixpath.join(*target), []).append(fname)
|
||||
return tmap.items()
|
||||
|
||||
|
||||
class Documentation(Data):
|
||||
""" Documentation container """
|
||||
|
||||
def fixup_commands(self):
|
||||
_commands.add_option('install_data', 'without-docs',
|
||||
help_text='Do not install documentation files',
|
||||
inherit='install',
|
||||
)
|
||||
_commands.add_finalizer('install_data', 'documentation', finalizer)
|
||||
|
||||
def flatten(self, installer):
|
||||
""" Check if docs should be installed at all """
|
||||
if installer.without_docs:
|
||||
return []
|
||||
return Data.flatten(self, installer)
|
||||
|
||||
|
||||
class Manpages(Documentation):
|
||||
""" Manpages container """
|
||||
|
||||
def dispatch(cls, files):
|
||||
""" Automatically dispatch manpages to their target directories """
|
||||
mpmap = {}
|
||||
for manpage in files:
|
||||
normalized = _os.path.normpath(manpage)
|
||||
_, ext = _os.path.splitext(normalized)
|
||||
if ext.startswith(_os.path.extsep):
|
||||
ext = ext[len(_os.path.extsep):]
|
||||
mpmap.setdefault(ext, []).append(manpage)
|
||||
return [cls(manpages, prefix=_posixpath.join(
|
||||
'share', 'man', 'man%s' % section,
|
||||
)) for section, manpages in mpmap.items()]
|
||||
dispatch = classmethod(dispatch)
|
||||
|
||||
def flatten(self, installer):
|
||||
""" Check if manpages are suitable """
|
||||
if _sys.platform == 'win32':
|
||||
return []
|
||||
return Documentation.flatten(self, installer)
|
25
_setup/py2/dev/__init__.py
Normal file
25
_setup/py2/dev/__init__.py
Normal file
@ -0,0 +1,25 @@
|
||||
# -*- coding: ascii -*-
|
||||
#
|
||||
# Copyright 2009, 2010, 2011
|
||||
# Andr\xe9 Malo or his licensors, as applicable
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
"""
|
||||
====================
|
||||
Package _setup.dev
|
||||
====================
|
||||
|
||||
Development tools, not distributed.
|
||||
"""
|
||||
__author__ = u"Andr\xe9 Malo"
|
||||
__docformat__ = "restructuredtext en"
|
258
_setup/py2/dev/_pylint.py
Normal file
258
_setup/py2/dev/_pylint.py
Normal file
@ -0,0 +1,258 @@
|
||||
# -*- coding: ascii -*-
|
||||
#
|
||||
# Copyright 2006, 2007, 2008, 2009, 2010, 2011
|
||||
# Andr\xe9 Malo or his licensors, as applicable
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
"""
|
||||
=================================
|
||||
Support for code analysis tools
|
||||
=================================
|
||||
|
||||
Support for code analysis tools.
|
||||
"""
|
||||
__author__ = u"Andr\xe9 Malo"
|
||||
__docformat__ = "restructuredtext en"
|
||||
|
||||
import re as _re
|
||||
import sys as _sys
|
||||
|
||||
from _setup import term as _term
|
||||
from _setup import shell as _shell
|
||||
|
||||
|
||||
class NotFinished(Exception):
|
||||
""" Exception used for message passing in the stream filter """
|
||||
|
||||
class NotParseable(Exception):
|
||||
""" Exception used for message passing in the stream filter """
|
||||
|
||||
class SpecialMessage(Exception):
|
||||
""" Exception used for message passing in the stream filter """
|
||||
|
||||
|
||||
class FilterStream(object):
|
||||
""" Stream filter """
|
||||
_LINERE = _re.compile(r'''
|
||||
(?P<name>[^:]+)
|
||||
:
|
||||
(?P<lineno>\d+)
|
||||
:\s+
|
||||
\[(?P<mid>[^\],]+)(?:,\s+(?P<func>[^\]]+))?\]
|
||||
\s+
|
||||
(?P<desc>.*)
|
||||
''', _re.X)
|
||||
_SIMRE = _re.compile(r'in (?P<number>\d+) files')
|
||||
_CYCRE = _re.compile(r'\((?P<cycle>[^)]+)\)')
|
||||
|
||||
def __init__(self, term, stream=_sys.stdout):
|
||||
self.written = False
|
||||
self._stream = stream
|
||||
self._lastname = None
|
||||
self._cycled = False
|
||||
self._term = dict(term)
|
||||
self._buffer = ''
|
||||
|
||||
def write(self, towrite):
|
||||
""" Stream write function """
|
||||
self._buffer += towrite
|
||||
term = self._term
|
||||
|
||||
while True:
|
||||
try:
|
||||
name, lineno, mid, func, desc = self._parse()
|
||||
except NotFinished:
|
||||
break
|
||||
except SpecialMessage, e:
|
||||
self._dospecial(e)
|
||||
continue
|
||||
except NotParseable, e:
|
||||
self._print_literal(str(e.args[0]))
|
||||
continue
|
||||
|
||||
if name != self._lastname:
|
||||
if self._lastname is not None:
|
||||
self._stream.write("\n")
|
||||
term['path'] = name
|
||||
self._stream.write(
|
||||
"%(BOLD)s>>> %(path)s%(NORMAL)s\n" % term
|
||||
)
|
||||
self._lastname = name
|
||||
self.written = True
|
||||
|
||||
term['mid'] = mid
|
||||
if mid.startswith('E') or mid.startswith('F'):
|
||||
self._stream.write("%(BOLD)s%(RED)s%(mid)s%(NORMAL)s" % term)
|
||||
elif mid == 'W0511':
|
||||
self._stream.write(
|
||||
"%(BOLD)s%(GREEN)s%(mid)s%(NORMAL)s" % term
|
||||
)
|
||||
else:
|
||||
self._stream.write(
|
||||
"%(BOLD)s%(YELLOW)s%(mid)s%(NORMAL)s" % term
|
||||
)
|
||||
|
||||
if int(lineno) != 0:
|
||||
term['lineno'] = lineno
|
||||
self._stream.write(" (%(lineno)s" % term)
|
||||
if func:
|
||||
term['func'] = func
|
||||
self._stream.write(
|
||||
", %(BOLD)s%(YELLOW)s%(func)s%(NORMAL)s" % term
|
||||
)
|
||||
self._stream.write(')')
|
||||
|
||||
self._stream.write(": %s\n" % desc)
|
||||
self._stream.flush()
|
||||
|
||||
return
|
||||
|
||||
def _print_literal(self, line):
|
||||
""" Print literal """
|
||||
suppress = (
|
||||
line.startswith('Unable to get imported names for ') or
|
||||
line.startswith("Exception exceptions.RuntimeError: 'generator "
|
||||
"ignored GeneratorExit' in <generator object at") or
|
||||
line.startswith("Exception RuntimeError: 'generator "
|
||||
"ignored GeneratorExit' in <generator object") or
|
||||
not line.strip()
|
||||
)
|
||||
if not suppress:
|
||||
self._stream.write("%s\n" % line)
|
||||
self._stream.flush()
|
||||
self.written = True
|
||||
|
||||
def _dospecial(self, e):
|
||||
""" Deal with special messages """
|
||||
if e.args[0] == 'R0401':
|
||||
pos = self._buffer.find('\n')
|
||||
line, self._buffer = (
|
||||
self._buffer[:pos + 1], self._buffer[pos + 1:]
|
||||
)
|
||||
term = self._term
|
||||
term['mid'] = e.args[0]
|
||||
if not self._cycled:
|
||||
self._cycled = True
|
||||
self._stream.write('\n')
|
||||
self._stream.write(
|
||||
"%(BOLD)s%(YELLOW)s%(mid)s%(NORMAL)s" % term
|
||||
)
|
||||
self._stream.write(": Cyclic imports\n")
|
||||
match = self._CYCRE.search(e.args[1])
|
||||
term['cycle'] = match.group('cycle')
|
||||
self._stream.write("%(BOLD)s@@@ %(NORMAL)s%(cycle)s\n" % term)
|
||||
self._stream.flush()
|
||||
self.written = True
|
||||
|
||||
elif e.args[0] == 'R0801':
|
||||
match = self._SIMRE.search(e.args[1])
|
||||
if not match:
|
||||
raise AssertionError(
|
||||
'Could not determine number of similar files'
|
||||
)
|
||||
|
||||
numfiles = int(match.group('number'))
|
||||
pos = -1
|
||||
for _ in range(numfiles + 1):
|
||||
pos = self._buffer.find('\n', pos + 1)
|
||||
if pos >= 0:
|
||||
lines = self._buffer[:pos + 1]
|
||||
self._buffer = self._buffer[pos + 1:]
|
||||
term = self._term
|
||||
|
||||
self._stream.write("\n")
|
||||
for name in lines.splitlines()[1:]:
|
||||
name = name.rstrip()[2:]
|
||||
term['path'] = name
|
||||
self._stream.write(
|
||||
"%(BOLD)s=== %(path)s%(NORMAL)s\n" % term
|
||||
)
|
||||
self._lastname = name
|
||||
|
||||
term['mid'] = e.args[0]
|
||||
self._stream.write(
|
||||
"%(BOLD)s%(YELLOW)s%(mid)s%(NORMAL)s" % term
|
||||
)
|
||||
self._stream.write(": %s\n" % e.args[1])
|
||||
self._stream.flush()
|
||||
self.written = True
|
||||
|
||||
def _parse(self):
|
||||
""" Parse output """
|
||||
if '\n' not in self._buffer:
|
||||
raise NotFinished()
|
||||
|
||||
line = self._buffer[:self._buffer.find('\n') + 1]
|
||||
self._buffer = self._buffer[len(line):]
|
||||
line = line.rstrip()
|
||||
match = self._LINERE.match(line)
|
||||
if not match:
|
||||
raise NotParseable(line)
|
||||
|
||||
mid = match.group('mid')
|
||||
if mid in ('R0801', 'R0401'):
|
||||
self._buffer = "%s\n%s" % (line, self._buffer)
|
||||
raise SpecialMessage(mid, match.group('desc'))
|
||||
|
||||
return match.group('name', 'lineno', 'mid', 'func', 'desc')
|
||||
|
||||
|
||||
def run(config, *args):
|
||||
""" Run pylint """
|
||||
try:
|
||||
from pylint import lint
|
||||
from pylint.reporters import text
|
||||
except ImportError:
|
||||
return 2
|
||||
|
||||
if config is None:
|
||||
config = _shell.native('pylint.conf')
|
||||
argv = ['--rcfile', config,
|
||||
'--reports', 'no',
|
||||
'--output-format', 'parseable',
|
||||
'--include-ids', 'yes'
|
||||
]
|
||||
|
||||
stream = FilterStream(_term.terminfo())
|
||||
|
||||
old_stderr = _sys.stderr
|
||||
try:
|
||||
# pylint: disable = E1101
|
||||
_sys.stderr = stream
|
||||
from pylint import __pkginfo__
|
||||
if __pkginfo__.numversion < (0, 13):
|
||||
# The lint tool is not very user friendly, so we need a hack here.
|
||||
lint.REPORTER_OPT_MAP['parseable'] = \
|
||||
lambda: text.TextReporter2(stream)
|
||||
reporter = text.TextReporter2(stream)
|
||||
else:
|
||||
reporter = text.ParseableTextReporter(stream)
|
||||
lint.REPORTER_OPT_MAP['parseable'] = lambda: reporter
|
||||
|
||||
for path in args:
|
||||
try:
|
||||
try:
|
||||
lint.Run(argv + [path], reporter=reporter)
|
||||
except SystemExit:
|
||||
pass # don't accept the exit. strange errors happen...
|
||||
|
||||
if stream.written:
|
||||
print
|
||||
stream.written = False
|
||||
except KeyboardInterrupt:
|
||||
print
|
||||
raise
|
||||
finally:
|
||||
_sys.stderr = old_stderr
|
||||
|
||||
return 0
|
31
_setup/py2/dev/analysis.py
Normal file
31
_setup/py2/dev/analysis.py
Normal file
@ -0,0 +1,31 @@
|
||||
# -*- coding: ascii -*-
|
||||
#
|
||||
# Copyright 2006, 2007, 2008, 2009, 2010, 2011
|
||||
# Andr\xe9 Malo or his licensors, as applicable
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
"""
|
||||
=================================
|
||||
Support for code analysis tools
|
||||
=================================
|
||||
|
||||
Support for code analysis tools.
|
||||
"""
|
||||
__author__ = u"Andr\xe9 Malo"
|
||||
__docformat__ = "restructuredtext en"
|
||||
|
||||
|
||||
def pylint(config, *args):
|
||||
""" Run pylint """
|
||||
from _setup.dev import _pylint
|
||||
return _pylint.run(config, *args)
|
131
_setup/py2/dev/apidoc.py
Normal file
131
_setup/py2/dev/apidoc.py
Normal file
@ -0,0 +1,131 @@
|
||||
# -*- coding: ascii -*-
|
||||
#
|
||||
# Copyright 2007, 2008, 2009, 2010, 2011
|
||||
# Andr\xe9 Malo or his licensors, as applicable
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
"""
|
||||
==================
|
||||
API doc builders
|
||||
==================
|
||||
|
||||
API doc builders.
|
||||
"""
|
||||
__author__ = u"Andr\xe9 Malo"
|
||||
__docformat__ = "restructuredtext en"
|
||||
|
||||
import os as _os
|
||||
import re as _re
|
||||
|
||||
from _setup import shell as _shell
|
||||
from _setup import term as _term
|
||||
from _setup import util as _util
|
||||
|
||||
|
||||
def _cleanup_epydoc(target):
|
||||
"""
|
||||
Cleanup epydoc generated files
|
||||
|
||||
This removes the epydoc-footer. It changes every release because of the
|
||||
timestamp. That creates bad diffs (accidently it's also invalid html).
|
||||
"""
|
||||
search = _re.compile(r'<table[^<>]+width="100%%"').search
|
||||
for filename in _shell.files(target, '*.html'):
|
||||
fp = open(filename, 'r')
|
||||
try:
|
||||
html = fp.read()
|
||||
finally:
|
||||
fp.close()
|
||||
match = search(html)
|
||||
if match:
|
||||
start = match.start()
|
||||
end = html.find('</table>', start)
|
||||
if end >= 0:
|
||||
end += len('</table>') + 1
|
||||
html = html[:start] + html[end:]
|
||||
fp = open(filename, 'w')
|
||||
try:
|
||||
fp.write(html)
|
||||
finally:
|
||||
fp.close()
|
||||
|
||||
|
||||
_VERSION_SEARCH = _re.compile(
|
||||
r'\bversion\s+(?P<major>\d+)\.(?P<minor>\d+)'
|
||||
).search
|
||||
def epydoc(**kwargs):
|
||||
""" Run epydoc """
|
||||
# pylint: disable = R0912
|
||||
prog = kwargs.get('epydoc') or 'epydoc'
|
||||
if not _os.path.dirname(_os.path.normpath(prog)):
|
||||
prog = _shell.frompath(prog)
|
||||
if not prog:
|
||||
_term.red("%(epydoc)s not found",
|
||||
epydoc=kwargs.get('epydoc') or 'epydoc',
|
||||
)
|
||||
return False
|
||||
|
||||
version = _VERSION_SEARCH(_shell.spawn(prog, "--version", stdout=True))
|
||||
if version is not None:
|
||||
try:
|
||||
version = tuple(map(int, version.group('major', 'minor')))
|
||||
except (TypeError, ValueError):
|
||||
version = None
|
||||
if version is None:
|
||||
_term.red("%(prog)s version not recognized" % locals())
|
||||
return False
|
||||
|
||||
if version < (3, 0):
|
||||
_term.red("%(prog)s is too old %(version)r < (3, 0)" % locals())
|
||||
return False
|
||||
|
||||
env = dict(_os.environ)
|
||||
|
||||
prepend = kwargs.get('prepend')
|
||||
if prepend:
|
||||
toprepend = _os.pathsep.join(map(str, prepend))
|
||||
if 'PYTHONPATH' in env:
|
||||
env['PYTHONPATH'] = _os.pathsep.join((
|
||||
toprepend, env['PYTHONPATH']
|
||||
))
|
||||
else:
|
||||
env['PYTHONPATH'] = toprepend
|
||||
|
||||
append = kwargs.get('append')
|
||||
if append:
|
||||
toappend = _os.pathsep.join(map(str, append))
|
||||
if 'PYTHONPATH' in env:
|
||||
env['PYTHONPATH'] = _os.pathsep.join((
|
||||
env['PYTHONPATH'], toappend
|
||||
))
|
||||
else:
|
||||
env['PYTHONPATH'] = toappend
|
||||
|
||||
moreenv = kwargs.get('env')
|
||||
if moreenv:
|
||||
env.update(moreenv)
|
||||
|
||||
config = kwargs.get('config') or _shell.native('docs/epydoc.conf')
|
||||
|
||||
argv = [prog, '--config', config]
|
||||
res = not _shell.spawn(*argv, **{'env': env})
|
||||
if res:
|
||||
cfg = _util.SafeConfigParser()
|
||||
cfg.read(config)
|
||||
try:
|
||||
target = dict(cfg.items('epydoc'))['target']
|
||||
except KeyError:
|
||||
pass
|
||||
else:
|
||||
_cleanup_epydoc(target)
|
||||
return res
|
50
_setup/py2/dev/userdoc.py
Normal file
50
_setup/py2/dev/userdoc.py
Normal file
@ -0,0 +1,50 @@
|
||||
# -*- coding: ascii -*-
|
||||
#
|
||||
# Copyright 2009, 2010, 2011
|
||||
# Andr\xe9 Malo or his licensors, as applicable
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
"""
|
||||
===================
|
||||
User doc builders
|
||||
===================
|
||||
|
||||
User doc builders.
|
||||
"""
|
||||
__author__ = u"Andr\xe9 Malo"
|
||||
__docformat__ = "restructuredtext en"
|
||||
|
||||
import os as _os
|
||||
|
||||
from _setup import shell as _shell
|
||||
from _setup import term as _term
|
||||
|
||||
|
||||
def sphinx(**kwargs):
|
||||
""" Run sphinx """
|
||||
prog = _shell.frompath('sphinx-build')
|
||||
if prog is None:
|
||||
_term.red("sphinx-build not found")
|
||||
return False
|
||||
|
||||
env = dict(_os.environ)
|
||||
|
||||
argv = [
|
||||
prog, '-a',
|
||||
'-d', _os.path.join(kwargs['build'], 'doctrees'),
|
||||
'-b', 'html',
|
||||
kwargs['source'],
|
||||
kwargs['target'],
|
||||
]
|
||||
|
||||
return not _shell.spawn(*argv, **{'env': env})
|
51
_setup/py2/dist.py
Normal file
51
_setup/py2/dist.py
Normal file
@ -0,0 +1,51 @@
|
||||
# -*- coding: ascii -*-
|
||||
#
|
||||
# Copyright 2007, 2008, 2009, 2010, 2011
|
||||
# Andr\xe9 Malo or his licensors, as applicable
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
"""
|
||||
================
|
||||
dist utilities
|
||||
================
|
||||
|
||||
dist utilities.
|
||||
"""
|
||||
__author__ = u"Andr\xe9 Malo"
|
||||
__docformat__ = "restructuredtext en"
|
||||
|
||||
import sys as _sys
|
||||
|
||||
from _setup import shell as _shell
|
||||
|
||||
|
||||
def run_setup(*args, **kwargs):
|
||||
""" Run setup """
|
||||
if 'setup' in kwargs:
|
||||
script = kwargs.get('setup') or 'setup.py'
|
||||
del kwargs['setup']
|
||||
else:
|
||||
script = 'setup.py'
|
||||
if 'fakeroot' in kwargs:
|
||||
fakeroot = kwargs['fakeroot']
|
||||
del kwargs['fakeroot']
|
||||
else:
|
||||
fakeroot = None
|
||||
if kwargs:
|
||||
raise TypeError("Unrecognized keyword parameters")
|
||||
|
||||
script = _shell.native(script)
|
||||
argv = [_sys.executable, script] + list(args)
|
||||
if fakeroot:
|
||||
argv.insert(0, fakeroot)
|
||||
return not _shell.spawn(*argv)
|
254
_setup/py2/ext.py
Normal file
254
_setup/py2/ext.py
Normal file
@ -0,0 +1,254 @@
|
||||
# -*- coding: ascii -*-
|
||||
#
|
||||
# Copyright 2007, 2008, 2009, 2010, 2011
|
||||
# Andr\xe9 Malo or his licensors, as applicable
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
"""
|
||||
===================
|
||||
C extension tools
|
||||
===================
|
||||
|
||||
C extension tools.
|
||||
"""
|
||||
__author__ = u"Andr\xe9 Malo"
|
||||
__docformat__ = "restructuredtext en"
|
||||
__test__ = False
|
||||
|
||||
from distutils import core as _core
|
||||
from distutils import errors as _distutils_errors
|
||||
import os as _os
|
||||
import posixpath as _posixpath
|
||||
import shutil as _shutil
|
||||
import tempfile as _tempfile
|
||||
|
||||
from _setup import commands as _commands
|
||||
from _setup.util import log
|
||||
|
||||
|
||||
def _install_finalizer(installer):
|
||||
if installer.without_c_extensions:
|
||||
installer.distribution.ext_modules = []
|
||||
|
||||
def _build_finalizer(builder):
|
||||
if builder.without_c_extensions:
|
||||
builder.extensions = []
|
||||
|
||||
|
||||
class Extension(_core.Extension):
|
||||
"""
|
||||
Extension with prerequisite check interface
|
||||
|
||||
If your check is cacheable (during the setup run), override
|
||||
`cached_check_prerequisites`, `check_prerequisites` otherwise.
|
||||
|
||||
:IVariables:
|
||||
`cached_check` : ``bool``
|
||||
The cached check result
|
||||
"""
|
||||
cached_check = None
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
""" Initialization """
|
||||
if kwargs.has_key('depends'):
|
||||
self.depends = kwargs['depends'] or []
|
||||
else:
|
||||
self.depends = []
|
||||
_core.Extension.__init__(self, *args, **kwargs)
|
||||
|
||||
# add include path
|
||||
included = _posixpath.join('_setup', 'include')
|
||||
if included not in self.include_dirs:
|
||||
self.include_dirs.append(included)
|
||||
|
||||
# add cext.h to the dependencies
|
||||
cext_h = _posixpath.join(included, 'cext.h')
|
||||
if cext_h not in self.depends:
|
||||
self.depends.append(cext_h)
|
||||
|
||||
_commands.add_option('install_lib', 'without-c-extensions',
|
||||
help_text='Don\'t install C extensions',
|
||||
inherit='install',
|
||||
)
|
||||
_commands.add_finalizer('install_lib', 'c-extensions',
|
||||
_install_finalizer
|
||||
)
|
||||
_commands.add_option('build_ext', 'without-c-extensions',
|
||||
help_text='Don\'t build C extensions',
|
||||
inherit=('build', 'install_lib'),
|
||||
)
|
||||
_commands.add_finalizer('build_ext', 'c-extensions', _build_finalizer)
|
||||
|
||||
def check_prerequisites(self, build):
|
||||
"""
|
||||
Check prerequisites
|
||||
|
||||
The check should cover all dependencies needed for the extension to
|
||||
be built and run. The method can do the following:
|
||||
|
||||
- return a false value: the extension will be built
|
||||
- return a true value: the extension will be skipped. This is useful
|
||||
for optional extensions
|
||||
- raise an exception. This is useful for mandatory extensions
|
||||
|
||||
If the check result is cacheable (during the setup run), override
|
||||
`cached_check_prerequisites` instead.
|
||||
|
||||
:Parameters:
|
||||
`build` : `BuildExt`
|
||||
The extension builder
|
||||
|
||||
:Return: Skip the extension?
|
||||
:Rtype: ``bool``
|
||||
"""
|
||||
if self.cached_check is None:
|
||||
log.debug("PREREQ check for %s" % self.name)
|
||||
self.cached_check = self.cached_check_prerequisites(build)
|
||||
else:
|
||||
log.debug("PREREQ check for %s (cached)" % self.name)
|
||||
return self.cached_check
|
||||
|
||||
def cached_check_prerequisites(self, build):
|
||||
"""
|
||||
Check prerequisites
|
||||
|
||||
The check should cover all dependencies needed for the extension to
|
||||
be built and run. The method can do the following:
|
||||
|
||||
- return a false value: the extension will be built
|
||||
- return a true value: the extension will be skipped. This is useful
|
||||
for optional extensions
|
||||
- raise an exception. This is useful for mandatory extensions
|
||||
|
||||
If the check result is *not* cacheable (during the setup run),
|
||||
override `check_prerequisites` instead.
|
||||
|
||||
:Parameters:
|
||||
`build` : `BuildExt`
|
||||
The extension builder
|
||||
|
||||
:Return: Skip the extension?
|
||||
:Rtype: ``bool``
|
||||
"""
|
||||
# pylint: disable = W0613
|
||||
log.debug("Nothing to check for %s!" % self.name)
|
||||
return False
|
||||
|
||||
|
||||
class ConfTest(object):
|
||||
"""
|
||||
Single conftest abstraction
|
||||
|
||||
:IVariables:
|
||||
`_tempdir` : ``str``
|
||||
The tempdir created for this test
|
||||
|
||||
`src` : ``str``
|
||||
Name of the source file
|
||||
|
||||
`target` : ``str``
|
||||
Target filename
|
||||
|
||||
`compiler` : ``CCompiler``
|
||||
compiler instance
|
||||
|
||||
`obj` : ``list``
|
||||
List of object filenames (``[str, ...]``)
|
||||
"""
|
||||
_tempdir = None
|
||||
|
||||
def __init__(self, build, source):
|
||||
"""
|
||||
Initialization
|
||||
|
||||
:Parameters:
|
||||
`build` : ``distuils.command.build_ext.build_ext``
|
||||
builder instance
|
||||
|
||||
`source` : ``str``
|
||||
Source of the file to compile
|
||||
"""
|
||||
self._tempdir = tempdir = _tempfile.mkdtemp()
|
||||
src = _os.path.join(tempdir, 'conftest.c')
|
||||
fp = open(src, 'w')
|
||||
try:
|
||||
fp.write(source)
|
||||
finally:
|
||||
fp.close()
|
||||
self.src = src
|
||||
self.compiler = compiler = build.compiler
|
||||
self.target = _os.path.join(tempdir, 'conftest')
|
||||
self.obj = compiler.object_filenames([src], output_dir=tempdir)
|
||||
|
||||
def __del__(self):
|
||||
""" Destruction """
|
||||
self.destroy()
|
||||
|
||||
def destroy(self):
|
||||
""" Destroy the conftest leftovers on disk """
|
||||
tempdir, self._tempdir = self._tempdir, None
|
||||
if tempdir is not None:
|
||||
_shutil.rmtree(tempdir)
|
||||
|
||||
def compile(self, **kwargs):
|
||||
"""
|
||||
Compile the conftest
|
||||
|
||||
:Parameters:
|
||||
`kwargs` : ``dict``
|
||||
Optional keyword parameters for the compiler call
|
||||
|
||||
:Return: Was the compilation successful?
|
||||
:Rtype: ``bool``
|
||||
"""
|
||||
kwargs['output_dir'] = self._tempdir
|
||||
try:
|
||||
self.compiler.compile([self.src], **kwargs)
|
||||
except _distutils_errors.CompileError:
|
||||
return False
|
||||
return True
|
||||
|
||||
def link(self, **kwargs):
|
||||
r"""
|
||||
Link the conftest
|
||||
|
||||
Before you can link the conftest objects they need to be `compile`\d.
|
||||
|
||||
:Parameters:
|
||||
`kwargs` : ``dict``
|
||||
Optional keyword parameters for the linker call
|
||||
|
||||
:Return: Was the linking successful?
|
||||
:Rtype: ``bool``
|
||||
"""
|
||||
try:
|
||||
self.compiler.link_executable(self.obj, self.target, **kwargs)
|
||||
except _distutils_errors.LinkError:
|
||||
return False
|
||||
return True
|
||||
|
||||
def pipe(self, mode="r"):
|
||||
r"""
|
||||
Execute the conftest binary and connect to it using a pipe
|
||||
|
||||
Before you can pipe to or from the conftest binary it needs to
|
||||
be `link`\ed.
|
||||
|
||||
:Parameters:
|
||||
`mode` : ``str``
|
||||
Pipe mode - r/w
|
||||
|
||||
:Return: The open pipe
|
||||
:Rtype: ``file``
|
||||
"""
|
||||
return _os.popen(self.compiler.executable_filename(self.target), mode)
|
28
_setup/py2/make/__init__.py
Normal file
28
_setup/py2/make/__init__.py
Normal file
@ -0,0 +1,28 @@
|
||||
# -*- coding: ascii -*-
|
||||
#
|
||||
# Copyright 2010, 2011
|
||||
# Andr\xe9 Malo or his licensors, as applicable
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
"""
|
||||
=====================
|
||||
Package _setup.make
|
||||
=====================
|
||||
|
||||
Make tools, not distributed.
|
||||
"""
|
||||
__author__ = u"Andr\xe9 Malo"
|
||||
__docformat__ = "restructuredtext en"
|
||||
|
||||
# pylint: disable = W0611
|
||||
from _setup.make._make import main, fail, warn, fatal, Target
|
338
_setup/py2/make/_make.py
Normal file
338
_setup/py2/make/_make.py
Normal file
@ -0,0 +1,338 @@
|
||||
# -*- coding: ascii -*-
|
||||
#
|
||||
# Copyright 2007, 2008, 2009, 2010, 2011
|
||||
# Andr\xe9 Malo or his licensors, as applicable
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
"""
|
||||
==================
|
||||
Simple make base
|
||||
==================
|
||||
|
||||
Simple make base.
|
||||
"""
|
||||
__author__ = u"Andr\xe9 Malo"
|
||||
__docformat__ = "restructuredtext en"
|
||||
|
||||
import sys as _sys
|
||||
|
||||
from _setup import term as _term
|
||||
|
||||
|
||||
class Failure(SystemExit):
|
||||
""" Failure exception """
|
||||
|
||||
|
||||
def fail(reason):
|
||||
""" Fail for a reason """
|
||||
raise Failure(reason)
|
||||
|
||||
|
||||
def warn(message, name=None):
|
||||
""" Warn """
|
||||
_term.red("%(NAME)sWarning: %(msg)s",
|
||||
NAME=name and "%s:" % name or '', msg=message
|
||||
)
|
||||
|
||||
|
||||
def fatal(reason):
|
||||
""" Fatal error, immediate stop """
|
||||
print >> _sys.stderr, reason
|
||||
_sys.exit(1)
|
||||
|
||||
|
||||
class Target(object):
|
||||
""" Target base class """
|
||||
NAME = None
|
||||
DEPS = None
|
||||
HIDDEN = False
|
||||
|
||||
ERROR = None
|
||||
|
||||
def __init__(self, runner):
|
||||
""" Base __init__ """
|
||||
self.runner = runner
|
||||
self.init()
|
||||
|
||||
def init(self):
|
||||
""" Default init hook """
|
||||
pass
|
||||
|
||||
def run(self):
|
||||
""" Default run hook """
|
||||
pass
|
||||
|
||||
def clean(self, scm=True, dist=False):
|
||||
""" Default clean hook """
|
||||
pass
|
||||
|
||||
|
||||
class _Runner(object):
|
||||
""" Runner """
|
||||
|
||||
def __init__(self, *targetscollection):
|
||||
""" Initialization """
|
||||
tdict = {}
|
||||
if not targetscollection:
|
||||
import __main__
|
||||
targetscollection = [__main__]
|
||||
|
||||
from _setup.make import default_targets
|
||||
if default_targets not in targetscollection:
|
||||
targetscollection.append(default_targets)
|
||||
|
||||
for targets in targetscollection:
|
||||
for value in vars(targets).values():
|
||||
if isinstance(value, type) and issubclass(value, Target) and \
|
||||
value.NAME is not None:
|
||||
if value.NAME in tdict:
|
||||
if issubclass(value, tdict[value.NAME]):
|
||||
pass # override base target
|
||||
elif issubclass(tdict[value.NAME], value):
|
||||
continue # found base later. ignore
|
||||
else:
|
||||
warn('Ambiguous target name', value.NAME)
|
||||
continue
|
||||
tdict[value.NAME] = value
|
||||
self._tdict = tdict
|
||||
self._itdict = {}
|
||||
|
||||
def print_help(self):
|
||||
""" Print make help """
|
||||
import textwrap as _textwrap
|
||||
|
||||
targets = self.targetinfo()
|
||||
keys = []
|
||||
for key, info in targets.items():
|
||||
if not info['hide']:
|
||||
keys.append(key)
|
||||
keys.sort()
|
||||
length = max(map(len, keys))
|
||||
info = []
|
||||
for key in keys:
|
||||
info.append("%s%s" % (
|
||||
(key + " " * length)[:length + 2],
|
||||
_textwrap.fill(
|
||||
targets[key]['desc'].strip(),
|
||||
subsequent_indent=" " * (length + 2)
|
||||
),
|
||||
))
|
||||
print "Available targets:\n\n" + "\n".join(info)
|
||||
|
||||
def targetinfo(self):
|
||||
""" Extract target information """
|
||||
result = {}
|
||||
for name, cls in self._tdict.items():
|
||||
result[name] = {
|
||||
'desc': cls.__doc__ or "no description",
|
||||
'hide': cls.HIDDEN,
|
||||
'deps': cls.DEPS or (),
|
||||
}
|
||||
return result
|
||||
|
||||
def _topleveltargets(self):
|
||||
""" Find all top level targets """
|
||||
rev = {} # key is a dep of [values]
|
||||
all_ = self.targetinfo()
|
||||
for target, info in all_.items():
|
||||
for dep in info['deps']:
|
||||
if dep not in all_:
|
||||
fatal("Unknown target '%s' (dep of %s) -> exit" % (
|
||||
dep, target
|
||||
))
|
||||
rev.setdefault(dep, []).append(target)
|
||||
return [target for target, info in rev.items() if not info]
|
||||
|
||||
def _run(self, target, seen=None):
|
||||
""" Run a target """
|
||||
if target.DEPS:
|
||||
self(*target.DEPS, **{'seen': seen})
|
||||
|
||||
if not target.HIDDEN:
|
||||
_term.yellow(">>> %(name)s", name=target.NAME)
|
||||
|
||||
try:
|
||||
result = target.run()
|
||||
except KeyboardInterrupt:
|
||||
result, target.ERROR = False, "^C -> exit"
|
||||
except Failure, e:
|
||||
result, target.ERROR = False, "%s: %s" % (target.NAME, e)
|
||||
except (SystemExit, MemoryError):
|
||||
raise
|
||||
except:
|
||||
import traceback
|
||||
target.ERROR = "%s errored:\n%s" % (target.NAME, ''.join(
|
||||
traceback.format_exception(*_sys.exc_info())
|
||||
))
|
||||
result = False
|
||||
else:
|
||||
if result is None:
|
||||
result = True
|
||||
return result
|
||||
|
||||
def _clean(self, target, scm, dist, seen=None):
|
||||
""" Run a target """
|
||||
if target.DEPS:
|
||||
self.run_clean(
|
||||
*target.DEPS, **{'scm': scm, 'dist': dist, 'seen': seen}
|
||||
)
|
||||
|
||||
try:
|
||||
result = target.clean(scm, dist)
|
||||
except KeyboardInterrupt:
|
||||
result, target.ERROR = False, "^C -> exit"
|
||||
except Failure, e:
|
||||
result, target.ERROR = False, "%s: %s" % (target.NAME, e)
|
||||
except (SystemExit, MemoryError):
|
||||
raise
|
||||
except:
|
||||
import traceback
|
||||
target.ERROR = "%s errored:\n%s" % (target.NAME, ''.join(
|
||||
traceback.format_exception(*_sys.exc_info())
|
||||
))
|
||||
result = False
|
||||
else:
|
||||
if result is None:
|
||||
result = True
|
||||
return result
|
||||
|
||||
def _make_init(self, seen):
|
||||
""" Make init mapper """
|
||||
def init(target):
|
||||
""" Return initialized target """
|
||||
if target not in seen:
|
||||
try:
|
||||
seen[target] = self._tdict[target](self)
|
||||
except KeyError:
|
||||
fatal("Unknown target '%s' -> exit" % target)
|
||||
else:
|
||||
seen[target] = None
|
||||
return seen[target]
|
||||
return init
|
||||
|
||||
def run_clean(self, *targets, **kwargs):
|
||||
""" Run targets """
|
||||
def pop(name, default=None):
|
||||
""" Pop """
|
||||
if name in kwargs:
|
||||
value = kwargs[name]
|
||||
del kwargs[name]
|
||||
if value is None:
|
||||
return default
|
||||
return value
|
||||
else:
|
||||
return default
|
||||
seen = pop('seen', {})
|
||||
scm = pop('scm', True)
|
||||
dist = pop('dist', False)
|
||||
if kwargs:
|
||||
raise TypeError('Unknown keyword parameters')
|
||||
|
||||
if not targets:
|
||||
top_targets = self._topleveltargets()
|
||||
targets = self.targetinfo()
|
||||
for item in top_targets:
|
||||
del targets[item]
|
||||
targets = targets.keys()
|
||||
targets.sort()
|
||||
top_targets.sort()
|
||||
targets = top_targets + targets
|
||||
|
||||
init = self._make_init(seen)
|
||||
for name in targets:
|
||||
target = init(name)
|
||||
if target is not None:
|
||||
if not self._clean(target, scm=scm, dist=dist, seen=seen):
|
||||
msg = target.ERROR
|
||||
if msg is None:
|
||||
msg = "Clean target %s returned error -> exit" % name
|
||||
fatal(msg)
|
||||
|
||||
def __call__(self, *targets, **kwargs):
|
||||
""" Run targets """
|
||||
if 'seen' in kwargs:
|
||||
seen = kwargs['seen']
|
||||
del kwargs['seen']
|
||||
else:
|
||||
seen = None
|
||||
if seen is None:
|
||||
seen = self._itdict
|
||||
if kwargs:
|
||||
raise TypeError('Unknown keyword parameters')
|
||||
|
||||
init = self._make_init(seen)
|
||||
for name in targets:
|
||||
target = init(name)
|
||||
if target is not None:
|
||||
if not self._run(target, seen):
|
||||
msg = target.ERROR
|
||||
if msg is None:
|
||||
msg = "Target %s returned error -> exit" % name
|
||||
fatal(msg)
|
||||
|
||||
|
||||
def main(*args, **kwargs):
|
||||
"""
|
||||
main(argv=None, *args, name=None)
|
||||
|
||||
Main start point. This function parses the command line and executes the
|
||||
targets given through `argv`. If there are no targets given, a help output
|
||||
is generated.
|
||||
|
||||
:Parameters:
|
||||
`argv` : sequence
|
||||
Command line arguments. If omitted or ``None``, they are picked from
|
||||
``sys.argv``.
|
||||
|
||||
`args` : ``tuple``
|
||||
The list of modules with targets. If omitted, ``__main__``
|
||||
is imported and treated as target module. Additionally the mechanism
|
||||
always adds the `_setup.make` module (this one) to the list in order
|
||||
to grab some default targets.
|
||||
|
||||
`name` : ``str``
|
||||
Name of the executing module. If omitted or ``None``, ``'__main__'``
|
||||
is assumed. If the final name is not ``'__main__'``, the function
|
||||
returns immediately.
|
||||
"""
|
||||
try:
|
||||
name = kwargs['name']
|
||||
except KeyError:
|
||||
name = '__main__'
|
||||
else:
|
||||
del kwargs['name']
|
||||
if name is None:
|
||||
name = '__main__'
|
||||
|
||||
try:
|
||||
argv = kwargs['argv']
|
||||
except KeyError:
|
||||
if not args:
|
||||
args = (None,)
|
||||
else:
|
||||
del kwargs['argv']
|
||||
args = (argv,) + args
|
||||
|
||||
if kwargs:
|
||||
raise TypeError("Unrecognized keyword arguments for main()")
|
||||
|
||||
if name == '__main__':
|
||||
argv, args = args[0], args[1:]
|
||||
if argv is None:
|
||||
argv = _sys.argv[1:]
|
||||
|
||||
runner = _Runner(*args)
|
||||
if argv:
|
||||
runner(*argv)
|
||||
else:
|
||||
runner.print_help()
|
110
_setup/py2/make/default_targets.py
Normal file
110
_setup/py2/make/default_targets.py
Normal file
@ -0,0 +1,110 @@
|
||||
# -*- coding: ascii -*-
|
||||
#
|
||||
# Copyright 2007, 2008, 2009, 2010, 2011
|
||||
# Andr\xe9 Malo or his licensors, as applicable
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
"""
|
||||
==================
|
||||
Simple make base
|
||||
==================
|
||||
|
||||
Simple make base.
|
||||
"""
|
||||
__author__ = u"Andr\xe9 Malo"
|
||||
__docformat__ = "restructuredtext en"
|
||||
|
||||
import os as _os
|
||||
import sys as _sys
|
||||
|
||||
from _setup import make as _make
|
||||
from _setup import shell as _shell
|
||||
|
||||
|
||||
class MakefileTarget(_make.Target):
|
||||
""" Create a make file """
|
||||
NAME = 'makefile'
|
||||
|
||||
def run(self):
|
||||
def escape(value):
|
||||
""" Escape for make and shell """
|
||||
return '"%s"' % value.replace(
|
||||
'\\', '\\\\').replace(
|
||||
'"', '\\"').replace(
|
||||
'$', '\\$$')
|
||||
def decorate(line, prefix='# ', width=78, char='~', padding=' '):
|
||||
""" Decorate a line """
|
||||
line = line.center(width - len(prefix))
|
||||
return '%s%s%s%s%s%s' % (
|
||||
prefix,
|
||||
char * (len(line) - len(line.lstrip()) - len(padding)),
|
||||
padding,
|
||||
line.strip(),
|
||||
padding,
|
||||
char * (len(line) - len(line.rstrip()) - len(padding)),
|
||||
)
|
||||
|
||||
python = escape(_sys.executable)
|
||||
script = escape(_sys.argv[0])
|
||||
targets = self.runner.targetinfo()
|
||||
names = []
|
||||
for name, info in targets.items():
|
||||
if not info['hide']:
|
||||
names.append(name)
|
||||
names.sort()
|
||||
|
||||
fp = open(_shell.native('Makefile'), 'w')
|
||||
print >> fp, decorate("Generated Makefile, DO NOT EDIT")
|
||||
print >> fp, decorate("python %s %s" % (
|
||||
_os.path.basename(script), self.NAME
|
||||
))
|
||||
print >> fp
|
||||
print >> fp, "_default_:"
|
||||
print >> fp, "\t@%s %s" % (python, script)
|
||||
for name in names:
|
||||
print >> fp, "\n"
|
||||
print >> fp, "# %s" % \
|
||||
targets[name]['desc'].splitlines()[0].strip()
|
||||
print >> fp, "%s:" % name
|
||||
print >> fp, "\t@%s %s %s" % (python, script, escape(name))
|
||||
print >> fp
|
||||
extension = self.extend(names)
|
||||
if extension is not None:
|
||||
print >> fp, extension
|
||||
print >> fp
|
||||
print >> fp, ".PHONY: _default_ %s\n\n" % ' '.join(names)
|
||||
fp.close()
|
||||
|
||||
def extend(self, names):
|
||||
pass
|
||||
|
||||
|
||||
class CleanTarget(_make.Target):
|
||||
""" Clean the mess """
|
||||
NAME = 'clean'
|
||||
_scm, _dist = True, False
|
||||
|
||||
def run(self):
|
||||
self.runner.run_clean(scm=self._scm, dist=self._dist)
|
||||
|
||||
|
||||
class DistCleanTarget(CleanTarget):
|
||||
""" Clean as freshly unpacked dist package """
|
||||
NAME = 'distclean'
|
||||
_scm, _dist = False, True
|
||||
|
||||
|
||||
class ExtraCleanTarget(CleanTarget):
|
||||
""" Clean everything """
|
||||
NAME = 'extraclean'
|
||||
_scm, _dist = True, True
|
324
_setup/py2/make/targets.py
Normal file
324
_setup/py2/make/targets.py
Normal file
@ -0,0 +1,324 @@
|
||||
# -*- coding: ascii -*-
|
||||
#
|
||||
# Copyright 2007 - 2013
|
||||
# Andr\xe9 Malo or his licensors, as applicable
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
"""
|
||||
==================
|
||||
Standard targets
|
||||
==================
|
||||
|
||||
Standard targets.
|
||||
"""
|
||||
__author__ = u"Andr\xe9 Malo"
|
||||
__docformat__ = "restructuredtext en"
|
||||
|
||||
import os as _os
|
||||
import sys as _sys
|
||||
|
||||
from _setup import dist as _dist
|
||||
from _setup import make as _make
|
||||
from _setup import shell as _shell
|
||||
from _setup import term as _term
|
||||
|
||||
|
||||
class Distribution(_make.Target):
|
||||
""" Build a distribution """
|
||||
NAME = "dist"
|
||||
DEPS = ["MANIFEST"]
|
||||
|
||||
_dist, _ebuilds, _changes = None, None, None
|
||||
|
||||
def init(self):
|
||||
raise NotImplementedError()
|
||||
|
||||
def run(self):
|
||||
exts = self.dist_pkg()
|
||||
digests = self.digest_files(exts)
|
||||
self.sign_digests(digests)
|
||||
self.copy_ebuilds()
|
||||
self.copy_changes()
|
||||
|
||||
def dist_pkg(self):
|
||||
_term.green("Building package...")
|
||||
_dist.run_setup("sdist", "--formats", "tar,zip",
|
||||
fakeroot=_shell.frompath('fakeroot')
|
||||
)
|
||||
exts = ['.zip']
|
||||
for name in _shell.files(self._dist, '*.tar', False):
|
||||
exts.extend(self.compress(name))
|
||||
_shell.rm(name)
|
||||
return exts
|
||||
|
||||
def compress(self, filename):
|
||||
""" Compress file """
|
||||
ext = _os.path.splitext(filename)[1]
|
||||
exts = []
|
||||
exts.append('.'.join((ext, self.compress_gzip(filename))))
|
||||
exts.append('.'.join((ext, self.compress_bzip2(filename))))
|
||||
exts.append('.'.join((ext, self.compress_xz(filename))))
|
||||
return exts
|
||||
|
||||
def compress_xz(self, filename):
|
||||
outfilename = filename + '.xz'
|
||||
self.compress_external(filename, outfilename, 'xz', '-c9')
|
||||
return 'xz'
|
||||
|
||||
def compress_bzip2(self, filename):
|
||||
outfilename = filename + '.bz2'
|
||||
try:
|
||||
import bz2 as _bz2
|
||||
except ImportError:
|
||||
self.compress_external(filename, outfilename, 'bzip2', '-c9')
|
||||
else:
|
||||
outfile = _bz2.BZ2File(outfilename, 'w')
|
||||
self.compress_internal(filename, outfile, outfilename)
|
||||
return 'bz2'
|
||||
|
||||
def compress_gzip(self, filename):
|
||||
outfilename = filename + '.gz'
|
||||
try:
|
||||
import gzip as _gzip
|
||||
except ImportError:
|
||||
self.compress_external(filename, outfilename, 'gzip', '-c9')
|
||||
else:
|
||||
outfile = _gzip.GzipFile(filename, 'wb',
|
||||
fileobj=open(outfilename, 'wb')
|
||||
)
|
||||
self.compress_internal(filename, outfile, outfilename)
|
||||
return 'gz'
|
||||
|
||||
def compress_external(self, infile, outfile, *argv):
|
||||
argv = list(argv)
|
||||
argv[0] = _shell.frompath(argv[0])
|
||||
if argv[0] is not None:
|
||||
return not _shell.spawn(*argv, **{
|
||||
'filepipe': True, 'stdin': infile, 'stdout': outfile,
|
||||
})
|
||||
return None
|
||||
|
||||
def compress_internal(self, filename, outfile, outfilename):
|
||||
infile = open(filename, 'rb')
|
||||
try:
|
||||
try:
|
||||
while 1:
|
||||
chunk = infile.read(8192)
|
||||
if not chunk:
|
||||
break
|
||||
outfile.write(chunk)
|
||||
outfile.close()
|
||||
except:
|
||||
e = _sys.exc_info()
|
||||
try:
|
||||
_shell.rm(outfilename)
|
||||
finally:
|
||||
try:
|
||||
raise e[0], e[1], e[2]
|
||||
finally:
|
||||
del e
|
||||
finally:
|
||||
infile.close()
|
||||
|
||||
def digest_files(self, exts):
|
||||
""" digest files """
|
||||
digests = {}
|
||||
digestnames = {}
|
||||
for ext in exts:
|
||||
for name in _shell.files(self._dist, '*' + ext, False):
|
||||
basename = _os.path.basename(name)
|
||||
if basename not in digests:
|
||||
digests[basename] = []
|
||||
digests[basename].extend(self.digest(name))
|
||||
digestname = basename[:-len(ext)]
|
||||
if digestname not in digestnames:
|
||||
digestnames[digestname] = []
|
||||
digestnames[digestname].append(basename)
|
||||
|
||||
result = []
|
||||
for name, basenames in digestnames.items():
|
||||
result.append(_os.path.join(self._dist, name + '.digests'))
|
||||
fp = open(result[-1], 'wb')
|
||||
try:
|
||||
fp.write(
|
||||
'\n# The file may contain MD5, SHA1 and SHA256 digests\n'
|
||||
)
|
||||
fp.write('# Check archive integrity with, e.g. md5sum -c\n')
|
||||
fp.write('# Check digest file integrity with PGP\n\n')
|
||||
basenames.sort()
|
||||
for basename in basenames:
|
||||
for digest in digests[basename]:
|
||||
fp.write("%s *%s\n" % (digest, basename))
|
||||
finally:
|
||||
fp.close()
|
||||
return result
|
||||
|
||||
def digest(self, filename):
|
||||
result = []
|
||||
for method in (self.md5, self.sha1, self.sha256):
|
||||
digest = method(filename)
|
||||
if digest is not None:
|
||||
result.append(digest)
|
||||
return result
|
||||
|
||||
def do_digest(self, hashfunc, name, filename):
|
||||
filename = _shell.native(filename)
|
||||
_term.green("%(digest)s-digesting %(name)s...",
|
||||
digest=name, name=_os.path.basename(filename))
|
||||
fp = open(filename, 'rb')
|
||||
sig = hashfunc()
|
||||
block = fp.read(8192)
|
||||
while block:
|
||||
sig.update(block)
|
||||
block = fp.read(8192)
|
||||
fp.close()
|
||||
return sig.hexdigest()
|
||||
|
||||
param = {'sig': sig.hexdigest(), 'file': _os.path.basename(filename)}
|
||||
fp = open("%s.%s" % (filename, name), "w")
|
||||
fp.write("%(sig)s *%(file)s\n" % param)
|
||||
fp.close()
|
||||
|
||||
return True
|
||||
|
||||
def md5(self, filename):
|
||||
try:
|
||||
from hashlib import md5
|
||||
except ImportError:
|
||||
try:
|
||||
from md5 import new as md5
|
||||
except ImportError:
|
||||
_make.warn("md5 not found -> skip md5 digests", self.NAME)
|
||||
return None
|
||||
return self.do_digest(md5, "md5", filename)
|
||||
|
||||
def sha1(self, filename):
|
||||
try:
|
||||
from hashlib import sha1
|
||||
except ImportError:
|
||||
try:
|
||||
from sha import new as sha1
|
||||
except ImportError:
|
||||
_make.warn("sha1 not found -> skip sha1 digests", self.NAME)
|
||||
return None
|
||||
return self.do_digest(sha1, "sha1", filename)
|
||||
|
||||
def sha256(self, filename):
|
||||
try:
|
||||
from hashlib import sha256
|
||||
except ImportError:
|
||||
try:
|
||||
from Crypto.Hash.SHA256 import new as sha256
|
||||
except ImportError:
|
||||
_make.warn(
|
||||
"sha256 not found -> skip sha256 digests", self.NAME
|
||||
)
|
||||
return None
|
||||
return self.do_digest(sha256, "sha256", filename)
|
||||
|
||||
def copy_ebuilds(self):
|
||||
if self._ebuilds is not None:
|
||||
for src in _shell.files(self._ebuilds, '*.ebuild'):
|
||||
_shell.cp(src, self._dist)
|
||||
|
||||
def copy_changes(self):
|
||||
if self._changes is not None:
|
||||
_shell.cp(self._changes, self._dist)
|
||||
|
||||
def sign_digests(self, digests):
|
||||
for digest in digests:
|
||||
self.sign(digest, detach=False)
|
||||
|
||||
def sign(self, filename, detach=True):
|
||||
filename = _shell.native(filename)
|
||||
try:
|
||||
from pyme import core, errors
|
||||
from pyme.constants.sig import mode
|
||||
except ImportError:
|
||||
return self.sign_external(filename, detach=detach)
|
||||
|
||||
_term.green("signing %(name)s...", name=_os.path.basename(filename))
|
||||
sigmode = [mode.CLEAR, mode.DETACH][bool(detach)]
|
||||
fp = core.Data(file=filename)
|
||||
sig = core.Data()
|
||||
try:
|
||||
c = core.Context()
|
||||
except errors.GPGMEError:
|
||||
return self.sign_external(filename, detach=detach)
|
||||
c.set_armor(1)
|
||||
try:
|
||||
c.op_sign(fp, sig, sigmode)
|
||||
except errors.GPGMEError, e:
|
||||
_make.fail(str(e))
|
||||
|
||||
sig.seek(0, 0)
|
||||
if detach:
|
||||
open("%s.asc" % filename, "w").write(sig.read())
|
||||
else:
|
||||
open(filename, "w").write(sig.read())
|
||||
|
||||
return True
|
||||
|
||||
def sign_external(self, filename, detach=True):
|
||||
""" Sign calling gpg """
|
||||
gpg = _shell.frompath('gpg')
|
||||
if gpg is None:
|
||||
_make.warn('GPG not found -> cannot sign')
|
||||
return False
|
||||
if detach:
|
||||
_shell.spawn(gpg,
|
||||
'--armor',
|
||||
'--output', filename + '.asc',
|
||||
'--detach-sign',
|
||||
'--',
|
||||
filename,
|
||||
)
|
||||
else:
|
||||
_shell.spawn(gpg,
|
||||
'--output', filename + '.signed',
|
||||
'--clearsign',
|
||||
'--',
|
||||
filename,
|
||||
)
|
||||
_os.rename(filename + '.signed', filename)
|
||||
return True
|
||||
|
||||
def clean(self, scm, dist):
|
||||
_term.green("Removing dist files...")
|
||||
_shell.rm_rf(self._dist)
|
||||
|
||||
|
||||
class Manifest(_make.Target):
|
||||
""" Create manifest """
|
||||
NAME = "MANIFEST"
|
||||
HIDDEN = True
|
||||
DEPS = ["doc"]
|
||||
|
||||
def run(self):
|
||||
_term.green("Creating %(name)s...", name=self.NAME)
|
||||
dest = _shell.native(self.NAME)
|
||||
dest = open(dest, 'w')
|
||||
for name in self.manifest_names():
|
||||
dest.write("%s\n" % name)
|
||||
dest.close()
|
||||
|
||||
def manifest_names(self):
|
||||
import setup
|
||||
for item in setup.manifest():
|
||||
yield item
|
||||
|
||||
def clean(self, scm, dist):
|
||||
""" Clean manifest """
|
||||
if scm:
|
||||
_term.green("Removing MANIFEST")
|
||||
_shell.rm(self.NAME)
|
419
_setup/py2/setup.py
Normal file
419
_setup/py2/setup.py
Normal file
@ -0,0 +1,419 @@
|
||||
# -*- coding: ascii -*-
|
||||
#
|
||||
# Copyright 2007 - 2013
|
||||
# Andr\xe9 Malo or his licensors, as applicable
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
"""
|
||||
===================
|
||||
Main setup runner
|
||||
===================
|
||||
|
||||
This module provides a wrapper around the distutils core setup.
|
||||
"""
|
||||
__author__ = u"Andr\xe9 Malo"
|
||||
__docformat__ = "restructuredtext en"
|
||||
|
||||
import ConfigParser as _config_parser
|
||||
from distutils import core as _core
|
||||
import os as _os
|
||||
import posixpath as _posixpath
|
||||
import sys as _sys
|
||||
|
||||
from _setup import commands as _commands
|
||||
from _setup import data as _data
|
||||
from _setup import ext as _ext
|
||||
from _setup import util as _util
|
||||
from _setup import shell as _shell
|
||||
|
||||
|
||||
def check_python_version(impl, version_min, version_max):
|
||||
""" Check python version """
|
||||
if impl == 'python':
|
||||
version_info = _sys.version_info
|
||||
elif impl == 'pypy':
|
||||
version_info = getattr(_sys, 'pypy_version_info', None)
|
||||
if not version_info:
|
||||
return
|
||||
elif impl == 'jython':
|
||||
if not 'java' in _sys.platform.lower():
|
||||
return
|
||||
version_info = _sys.version_info
|
||||
else:
|
||||
raise AssertionError("impl not in ('python', 'pypy', 'jython')")
|
||||
|
||||
pyversion = map(int, version_info[:3])
|
||||
if version_min:
|
||||
min_required = \
|
||||
map(int, '.'.join((version_min, '0.0.0')).split('.')[:3])
|
||||
if pyversion < min_required:
|
||||
raise EnvironmentError("Need at least %s %s (vs. %s)" % (
|
||||
impl, version_min, '.'.join(map(str, pyversion))
|
||||
))
|
||||
if version_max:
|
||||
max_required = map(int, version_max.split('.'))
|
||||
max_required[-1] += 1
|
||||
if pyversion >= max_required:
|
||||
raise EnvironmentError("Need at max %s %s (vs. %s)" % (
|
||||
impl,
|
||||
version_max,
|
||||
'.'.join(map(str, pyversion))
|
||||
))
|
||||
|
||||
|
||||
def find_description(docs):
|
||||
"""
|
||||
Determine the package description from DESCRIPTION
|
||||
|
||||
:Parameters:
|
||||
`docs` : ``dict``
|
||||
Docs config section
|
||||
|
||||
:Return: Tuple of summary, description and license
|
||||
(``('summary', 'description', 'license')``)
|
||||
(all may be ``None``)
|
||||
:Rtype: ``tuple``
|
||||
"""
|
||||
summary = None
|
||||
filename = docs.get('meta.summary', 'SUMMARY').strip()
|
||||
if filename and _os.path.isfile(filename):
|
||||
fp = open(filename)
|
||||
try:
|
||||
try:
|
||||
summary = fp.read().strip().splitlines()[0].rstrip()
|
||||
except IndexError:
|
||||
summary = ''
|
||||
finally:
|
||||
fp.close()
|
||||
|
||||
description = None
|
||||
filename = docs.get('meta.description', 'DESCRIPTION').strip()
|
||||
if filename and _os.path.isfile(filename):
|
||||
fp = open(filename)
|
||||
try:
|
||||
description = fp.read().rstrip()
|
||||
finally:
|
||||
fp.close()
|
||||
|
||||
if summary is None and description:
|
||||
from docutils import core
|
||||
summary = core.publish_parts(
|
||||
source=description,
|
||||
source_path=filename,
|
||||
writer_name='html',
|
||||
)['title'].encode('utf-8')
|
||||
|
||||
return summary, description
|
||||
|
||||
|
||||
def find_classifiers(docs):
|
||||
"""
|
||||
Determine classifiers from CLASSIFIERS
|
||||
|
||||
:return: List of classifiers (``['classifier', ...]``)
|
||||
:rtype: ``list``
|
||||
"""
|
||||
filename = docs.get('meta.classifiers', 'CLASSIFIERS').strip()
|
||||
if filename and _os.path.isfile(filename):
|
||||
fp = open(filename)
|
||||
try:
|
||||
content = fp.read()
|
||||
finally:
|
||||
fp.close()
|
||||
content = [item.strip() for item in content.splitlines()]
|
||||
return [item for item in content if item and not item.startswith('#')]
|
||||
return []
|
||||
|
||||
|
||||
def find_provides(docs):
|
||||
"""
|
||||
Determine provides from PROVIDES
|
||||
|
||||
:return: List of provides (``['provides', ...]``)
|
||||
:rtype: ``list``
|
||||
"""
|
||||
filename = docs.get('meta.provides', 'PROVIDES').strip()
|
||||
if filename and _os.path.isfile(filename):
|
||||
fp = open(filename)
|
||||
try:
|
||||
content = fp.read()
|
||||
finally:
|
||||
fp.close()
|
||||
content = [item.strip() for item in content.splitlines()]
|
||||
return [item for item in content if item and not item.startswith('#')]
|
||||
return []
|
||||
|
||||
|
||||
def find_license(docs):
|
||||
"""
|
||||
Determine license from LICENSE
|
||||
|
||||
:return: License text
|
||||
:rtype: ``str``
|
||||
"""
|
||||
filename = docs.get('meta.license', 'LICENSE').strip()
|
||||
if filename and _os.path.isfile(filename):
|
||||
fp = open(filename)
|
||||
try:
|
||||
return fp.read().rstrip()
|
||||
finally:
|
||||
fp.close()
|
||||
return None
|
||||
|
||||
|
||||
def find_packages(manifest):
|
||||
""" Determine packages and subpackages """
|
||||
packages = {}
|
||||
collect = manifest.get('packages.collect', '').split()
|
||||
lib = manifest.get('packages.lib', '.')
|
||||
try:
|
||||
sep = _os.path.sep
|
||||
except AttributeError:
|
||||
sep = _os.path.join('1', '2')[1:-1]
|
||||
for root in collect:
|
||||
for dirpath, _, filenames in _shell.walk(_os.path.join(lib, root)):
|
||||
if dirpath.find('.svn') >= 0:
|
||||
continue
|
||||
if '__init__.py' in filenames:
|
||||
packages[
|
||||
_os.path.normpath(dirpath).replace(sep, '.')
|
||||
] = None
|
||||
packages = packages.keys()
|
||||
packages.sort()
|
||||
return packages
|
||||
|
||||
|
||||
def find_data(name, docs):
|
||||
""" Determine data files """
|
||||
result = []
|
||||
if docs.get('extra', '').strip():
|
||||
result.append(_data.Documentation(docs['extra'].split(),
|
||||
prefix='share/doc/%s' % name,
|
||||
))
|
||||
if docs.get('examples.dir', '').strip():
|
||||
tpl = ['recursive-include %s *' % docs['examples.dir']]
|
||||
if docs.get('examples.ignore', '').strip():
|
||||
tpl.extend(["global-exclude %s" % item
|
||||
for item in docs['examples.ignore'].split()
|
||||
])
|
||||
strip = int(docs.get('examples.strip', '') or 0)
|
||||
result.append(_data.Documentation.from_templates(*tpl, **{
|
||||
'strip': strip,
|
||||
'prefix': 'share/doc/%s' % name,
|
||||
'preserve': 1,
|
||||
}))
|
||||
if docs.get('userdoc.dir', '').strip():
|
||||
tpl = ['recursive-include %s *' % docs['userdoc.dir']]
|
||||
if docs.get('userdoc.ignore', '').strip():
|
||||
tpl.extend(["global-exclude %s" % item
|
||||
for item in docs['userdoc.ignore'].split()
|
||||
])
|
||||
strip = int(docs.get('userdoc.strip', '') or 0)
|
||||
result.append(_data.Documentation.from_templates(*tpl, **{
|
||||
'strip': strip,
|
||||
'prefix': 'share/doc/%s' % name,
|
||||
'preserve': 1,
|
||||
}))
|
||||
if docs.get('apidoc.dir', '').strip():
|
||||
tpl = ['recursive-include %s *' % docs['apidoc.dir']]
|
||||
if docs.get('apidoc.ignore', '').strip():
|
||||
tpl.extend(["global-exclude %s" % item
|
||||
for item in docs['apidoc.ignore'].split()
|
||||
])
|
||||
strip = int(docs.get('apidoc.strip', '') or 0)
|
||||
result.append(_data.Documentation.from_templates(*tpl, **{
|
||||
'strip': strip,
|
||||
'prefix': 'share/doc/%s' % name,
|
||||
'preserve': 1,
|
||||
}))
|
||||
if docs.get('man', '').strip():
|
||||
result.extend(_data.Manpages.dispatch(docs['man'].split()))
|
||||
return result
|
||||
|
||||
|
||||
def make_manifest(manifest, config, docs, kwargs):
|
||||
""" Create file list to pack up """
|
||||
# pylint: disable = R0912
|
||||
kwargs = kwargs.copy()
|
||||
kwargs['script_args'] = ['install']
|
||||
kwargs['packages'] = list(kwargs.get('packages') or ()) + [
|
||||
'_setup', '_setup.py2', '_setup.py3',
|
||||
] + list(manifest.get('packages.extra', '').split() or ())
|
||||
_core._setup_stop_after = "commandline"
|
||||
try:
|
||||
dist = _core.setup(**kwargs)
|
||||
finally:
|
||||
_core._setup_stop_after = None
|
||||
|
||||
result = ['MANIFEST', 'PKG-INFO', 'setup.py'] + list(config)
|
||||
# TODO: work with default values:
|
||||
for key in ('classifiers', 'description', 'summary', 'provides',
|
||||
'license'):
|
||||
filename = docs.get('meta.' + key, '').strip()
|
||||
if filename and _os.path.isfile(filename):
|
||||
result.append(filename)
|
||||
|
||||
cmd = dist.get_command_obj("build_py")
|
||||
cmd.ensure_finalized()
|
||||
#from pprint import pprint; pprint(("build_py", cmd.get_source_files()))
|
||||
for item in cmd.get_source_files():
|
||||
result.append(_posixpath.sep.join(
|
||||
_os.path.normpath(item).split(_os.path.sep)
|
||||
))
|
||||
|
||||
cmd = dist.get_command_obj("build_ext")
|
||||
cmd.ensure_finalized()
|
||||
#from pprint import pprint; pprint(("build_ext", cmd.get_source_files()))
|
||||
for item in cmd.get_source_files():
|
||||
result.append(_posixpath.sep.join(
|
||||
_os.path.normpath(item).split(_os.path.sep)
|
||||
))
|
||||
for ext in cmd.extensions:
|
||||
if ext.depends:
|
||||
result.extend([_posixpath.sep.join(
|
||||
_os.path.normpath(item).split(_os.path.sep)
|
||||
) for item in ext.depends])
|
||||
|
||||
cmd = dist.get_command_obj("build_clib")
|
||||
cmd.ensure_finalized()
|
||||
if cmd.libraries:
|
||||
#import pprint; pprint.pprint(("build_clib", cmd.get_source_files()))
|
||||
for item in cmd.get_source_files():
|
||||
result.append(_posixpath.sep.join(
|
||||
_os.path.normpath(item).split(_os.path.sep)
|
||||
))
|
||||
for lib in cmd.libraries:
|
||||
if lib[1].get('depends'):
|
||||
result.extend([_posixpath.sep.join(
|
||||
_os.path.normpath(item).split(_os.path.sep)
|
||||
) for item in lib[1]['depends']])
|
||||
|
||||
cmd = dist.get_command_obj("build_scripts")
|
||||
cmd.ensure_finalized()
|
||||
#import pprint; pprint.pprint(("build_scripts", cmd.get_source_files()))
|
||||
if cmd.get_source_files():
|
||||
for item in cmd.get_source_files():
|
||||
result.append(_posixpath.sep.join(
|
||||
_os.path.normpath(item).split(_os.path.sep)
|
||||
))
|
||||
|
||||
cmd = dist.get_command_obj("install_data")
|
||||
cmd.ensure_finalized()
|
||||
#from pprint import pprint; pprint(("install_data", cmd.get_inputs()))
|
||||
try:
|
||||
strings = basestring
|
||||
except NameError:
|
||||
strings = (str, unicode)
|
||||
|
||||
for item in cmd.get_inputs():
|
||||
if isinstance(item, strings):
|
||||
result.append(item)
|
||||
else:
|
||||
result.extend(item[1])
|
||||
|
||||
for item in manifest.get('dist', '').split():
|
||||
result.append(item)
|
||||
if _os.path.isdir(item):
|
||||
for filename in _shell.files(item):
|
||||
result.append(filename)
|
||||
|
||||
result = dict([(item, None) for item in result]).keys()
|
||||
result.sort()
|
||||
return result
|
||||
|
||||
|
||||
def run(config=('package.cfg',), ext=None, script_args=None, manifest_only=0):
|
||||
""" Main runner """
|
||||
if ext is None:
|
||||
ext = []
|
||||
|
||||
cfg = _util.SafeConfigParser()
|
||||
cfg.read(config)
|
||||
pkg = dict(cfg.items('package'))
|
||||
python_min = pkg.get('python.min') or None
|
||||
python_max = pkg.get('python.max') or None
|
||||
check_python_version('python', python_min, python_max)
|
||||
pypy_min = pkg.get('pypy.min') or None
|
||||
pypy_max = pkg.get('pypy.max') or None
|
||||
check_python_version('pypy', pypy_min, pypy_max)
|
||||
jython_min = pkg.get('jython.min') or None
|
||||
jython_max = pkg.get('jython.max') or None
|
||||
check_python_version('jython', jython_min, jython_max)
|
||||
|
||||
manifest = dict(cfg.items('manifest'))
|
||||
try:
|
||||
docs = dict(cfg.items('docs'))
|
||||
except _config_parser.NoSectionError:
|
||||
docs = {}
|
||||
|
||||
summary, description = find_description(docs)
|
||||
scripts = manifest.get('scripts', '').strip() or None
|
||||
if scripts:
|
||||
scripts = scripts.split()
|
||||
modules = manifest.get('modules', '').strip() or None
|
||||
if modules:
|
||||
modules = modules.split()
|
||||
keywords = docs.get('meta.keywords', '').strip() or None
|
||||
if keywords:
|
||||
keywords = keywords.split()
|
||||
revision = pkg.get('version.revision', '').strip()
|
||||
if revision:
|
||||
revision = "-r%s" % (revision,)
|
||||
|
||||
kwargs = {
|
||||
'name': pkg['name'],
|
||||
'version': "%s%s" % (
|
||||
pkg['version.number'],
|
||||
["", "-dev%s" % (revision,)][_util.humanbool(
|
||||
'version.dev', pkg.get('version.dev', 'false')
|
||||
)],
|
||||
),
|
||||
'provides': find_provides(docs),
|
||||
'description': summary,
|
||||
'long_description': description,
|
||||
'classifiers': find_classifiers(docs),
|
||||
'keywords': keywords,
|
||||
'author': pkg['author.name'],
|
||||
'author_email': pkg['author.email'],
|
||||
'maintainer': pkg.get('maintainer.name'),
|
||||
'maintainer_email': pkg.get('maintainer.email'),
|
||||
'url': pkg.get('url.homepage'),
|
||||
'download_url': pkg.get('url.download'),
|
||||
'license': find_license(docs),
|
||||
'package_dir': {'': manifest.get('packages.lib', '.')},
|
||||
'packages': find_packages(manifest),
|
||||
'py_modules': modules,
|
||||
'ext_modules': ext,
|
||||
'scripts': scripts,
|
||||
'script_args': script_args,
|
||||
'data_files': find_data(pkg['name'], docs),
|
||||
'cmdclass': {
|
||||
'build' : _commands.Build,
|
||||
'build_ext' : _commands.BuildExt,
|
||||
'install' : _commands.Install,
|
||||
'install_data': _commands.InstallData,
|
||||
'install_lib' : _commands.InstallLib,
|
||||
}
|
||||
}
|
||||
for key in ('provides',):
|
||||
if key not in _core.setup_keywords:
|
||||
del kwargs[key]
|
||||
|
||||
if manifest_only:
|
||||
return make_manifest(manifest, config, docs, kwargs)
|
||||
|
||||
# monkey-patch crappy manifest writer away.
|
||||
from distutils.command import sdist
|
||||
sdist.sdist.get_file_list = sdist.sdist.read_manifest
|
||||
|
||||
return _core.setup(**kwargs)
|
478
_setup/py2/shell.py
Normal file
478
_setup/py2/shell.py
Normal file
@ -0,0 +1,478 @@
|
||||
# -*- coding: ascii -*-
|
||||
#
|
||||
# Copyright 2007 - 2013
|
||||
# Andr\xe9 Malo or his licensors, as applicable
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
"""
|
||||
=================
|
||||
Shell utilities
|
||||
=================
|
||||
|
||||
Shell utilities.
|
||||
"""
|
||||
from __future__ import generators
|
||||
|
||||
__author__ = u"Andr\xe9 Malo"
|
||||
__docformat__ = "restructuredtext en"
|
||||
|
||||
import errno as _errno
|
||||
import fnmatch as _fnmatch
|
||||
import os as _os
|
||||
import shutil as _shutil
|
||||
import sys as _sys
|
||||
import tempfile as _tempfile
|
||||
|
||||
cwd = _os.path.dirname(_os.path.abspath(_sys.argv[0]))
|
||||
|
||||
class ExitError(RuntimeError):
|
||||
""" Exit error """
|
||||
def __init__(self, code):
|
||||
RuntimeError.__init__(self, code)
|
||||
self.code = code
|
||||
self.signal = None
|
||||
|
||||
|
||||
class SignalError(ExitError):
|
||||
""" Signal error """
|
||||
def __init__(self, code, signal):
|
||||
ExitError.__init__(self, code)
|
||||
import signal as _signal
|
||||
self.signal = signal
|
||||
for key, val in vars(_signal).iteritems():
|
||||
if key.startswith('SIG') and not key.startswith('SIG_'):
|
||||
if val == signal:
|
||||
self.signalstr = key[3:]
|
||||
break
|
||||
else:
|
||||
self.signalstr = '%04d' % signal
|
||||
|
||||
|
||||
def native(path):
|
||||
""" Convert slash path to native """
|
||||
path = _os.path.sep.join(path.split('/'))
|
||||
return _os.path.normpath(_os.path.join(cwd, path))
|
||||
|
||||
|
||||
def cp(src, dest):
|
||||
""" Copy src to dest """
|
||||
_shutil.copy2(native(src), native(dest))
|
||||
|
||||
|
||||
def cp_r(src, dest):
|
||||
""" Copy -r src to dest """
|
||||
_shutil.copytree(native(src), native(dest))
|
||||
|
||||
|
||||
def rm(dest):
|
||||
""" Remove a file """
|
||||
try:
|
||||
_os.unlink(native(dest))
|
||||
except OSError, e:
|
||||
if _errno.ENOENT != e.errno:
|
||||
raise
|
||||
|
||||
def rm_rf(dest):
|
||||
""" Remove a tree """
|
||||
dest = native(dest)
|
||||
if _os.path.exists(dest):
|
||||
for path in files(dest, '*'):
|
||||
_os.chmod(native(path), 0644)
|
||||
_shutil.rmtree(dest)
|
||||
|
||||
|
||||
try:
|
||||
mkstemp = _tempfile.mkstemp
|
||||
except AttributeError:
|
||||
# helpers stolen from 2.4 tempfile module
|
||||
try:
|
||||
import fcntl as _fcntl
|
||||
except ImportError:
|
||||
def _set_cloexec(fd):
|
||||
""" Set close-on-exec (not implemented, but not an error) """
|
||||
# pylint: disable = W0613
|
||||
pass
|
||||
else:
|
||||
def _set_cloexec(fd):
|
||||
""" Set close-on-exec """
|
||||
try:
|
||||
flags = _fcntl.fcntl(fd, _fcntl.F_GETFD, 0)
|
||||
except IOError:
|
||||
pass
|
||||
else:
|
||||
# flags read successfully, modify
|
||||
flags |= _fcntl.FD_CLOEXEC
|
||||
_fcntl.fcntl(fd, _fcntl.F_SETFD, flags)
|
||||
|
||||
_text_openflags = _os.O_RDWR | _os.O_CREAT | _os.O_EXCL
|
||||
_text_openflags |= getattr(_os, 'O_NOINHERIT', 0)
|
||||
_text_openflags |= getattr(_os, 'O_NOFOLLOW', 0)
|
||||
|
||||
_bin_openflags = _text_openflags
|
||||
_bin_openflags |= getattr(_os, 'O_BINARY', 0)
|
||||
|
||||
def mkstemp(suffix="", prefix=_tempfile.gettempprefix(), dir=None,
|
||||
text=False):
|
||||
""" Create secure temp file """
|
||||
# pylint: disable = W0622
|
||||
if dir is None:
|
||||
dir = _tempfile.gettempdir()
|
||||
if text:
|
||||
flags = _text_openflags
|
||||
else:
|
||||
flags = _bin_openflags
|
||||
count = 100
|
||||
while count > 0:
|
||||
j = _tempfile._counter.get_next() # pylint: disable = E1101, W0212
|
||||
fname = _os.path.join(dir, prefix + str(j) + suffix)
|
||||
try:
|
||||
fd = _os.open(fname, flags, 0600)
|
||||
except OSError, e:
|
||||
if e.errno == _errno.EEXIST:
|
||||
count -= 1
|
||||
continue
|
||||
raise
|
||||
_set_cloexec(fd)
|
||||
return fd, _os.path.abspath(fname)
|
||||
raise IOError, (_errno.EEXIST, "No usable temporary file name found")
|
||||
|
||||
|
||||
def _pipespawn(argv, env):
|
||||
""" Pipe spawn """
|
||||
# pylint: disable = R0912
|
||||
import pickle as _pickle
|
||||
fd, name = mkstemp('.py')
|
||||
try:
|
||||
_os.write(fd, (r"""
|
||||
import os
|
||||
import pickle
|
||||
try:
|
||||
import subprocess
|
||||
except ImportError:
|
||||
subprocess = None
|
||||
import sys
|
||||
|
||||
argv = pickle.loads(%(argv)s)
|
||||
env = pickle.loads(%(env)s)
|
||||
if 'X_JYTHON_WA_PATH' in env:
|
||||
env['PATH'] = env['X_JYTHON_WA_PATH']
|
||||
|
||||
if subprocess is None:
|
||||
pid = os.spawnve(os.P_NOWAIT, argv[0], argv, env)
|
||||
result = os.waitpid(pid, 0)[1]
|
||||
else:
|
||||
p = subprocess.Popen(argv, env=env)
|
||||
result = p.wait()
|
||||
if result < 0:
|
||||
print "\n%%d 1" %% (-result)
|
||||
sys.exit(2)
|
||||
|
||||
if result == 0:
|
||||
sys.exit(0)
|
||||
signalled = getattr(os, 'WIFSIGNALED', None)
|
||||
if signalled is not None:
|
||||
if signalled(result):
|
||||
print "\n%%d %%d" %% (os.WTERMSIG(result), result & 7)
|
||||
sys.exit(2)
|
||||
print "\n%%d" %% (result & 7,)
|
||||
sys.exit(3)
|
||||
""".strip() + "\n") % {
|
||||
'argv': repr(_pickle.dumps(argv)),
|
||||
'env': repr(_pickle.dumps(env)),
|
||||
})
|
||||
fd, _ = None, _os.close(fd)
|
||||
if _sys.platform == 'win32':
|
||||
argv = []
|
||||
for arg in [_sys.executable, name]:
|
||||
if ' ' in arg or arg.startswith('"'):
|
||||
arg = '"%s"' % arg.replace('"', '\\"')
|
||||
argv.append(arg)
|
||||
argv = ' '.join(argv)
|
||||
shell = True
|
||||
close_fds = False
|
||||
else:
|
||||
argv = [_sys.executable, name]
|
||||
shell = False
|
||||
close_fds = True
|
||||
|
||||
res = 0
|
||||
try:
|
||||
import subprocess
|
||||
except ImportError:
|
||||
import popen2 as _popen2
|
||||
proc = _popen2.Popen3(argv, False)
|
||||
try:
|
||||
proc.tochild.close()
|
||||
result = proc.fromchild.read()
|
||||
finally:
|
||||
res = proc.wait()
|
||||
else:
|
||||
if 'X_JYTHON_WA_PATH' in env:
|
||||
env['PATH'] = env['X_JYTHON_WA_PATH']
|
||||
|
||||
proc = subprocess.Popen(argv,
|
||||
shell=shell,
|
||||
stdin=subprocess.PIPE,
|
||||
stdout=subprocess.PIPE,
|
||||
close_fds=close_fds,
|
||||
env=env,
|
||||
)
|
||||
try:
|
||||
proc.stdin.close()
|
||||
result = proc.stdout.read()
|
||||
finally:
|
||||
res = proc.wait()
|
||||
if res != 0:
|
||||
if res == 2:
|
||||
signal, code = map(int, result.splitlines()[-1].split())
|
||||
raise SignalError(code, signal)
|
||||
elif res == 3:
|
||||
code = int(result.splitlines()[-1].strip())
|
||||
raise ExitError(code)
|
||||
raise ExitError(res)
|
||||
|
||||
return result
|
||||
finally:
|
||||
try:
|
||||
if fd is not None:
|
||||
_os.close(fd)
|
||||
finally:
|
||||
_os.unlink(name)
|
||||
|
||||
|
||||
def _filepipespawn(infile, outfile, argv, env):
|
||||
""" File Pipe spawn """
|
||||
try:
|
||||
import subprocess
|
||||
except ImportError:
|
||||
subprocess = None
|
||||
import pickle as _pickle
|
||||
fd, name = mkstemp('.py')
|
||||
try:
|
||||
_os.write(fd, ("""
|
||||
import os
|
||||
import pickle
|
||||
import sys
|
||||
|
||||
infile = pickle.loads(%(infile)s)
|
||||
outfile = pickle.loads(%(outfile)s)
|
||||
argv = pickle.loads(%(argv)s)
|
||||
env = pickle.loads(%(env)s)
|
||||
|
||||
if infile is not None:
|
||||
infile = open(infile, 'rb')
|
||||
os.dup2(infile.fileno(), 0)
|
||||
infile.close()
|
||||
if outfile is not None:
|
||||
outfile = open(outfile, 'wb')
|
||||
os.dup2(outfile.fileno(), 1)
|
||||
outfile.close()
|
||||
|
||||
pid = os.spawnve(os.P_NOWAIT, argv[0], argv, env)
|
||||
result = os.waitpid(pid, 0)[1]
|
||||
sys.exit(result & 7)
|
||||
""".strip() + "\n") % {
|
||||
'infile': repr(_pickle.dumps(_os.path.abspath(infile))),
|
||||
'outfile': repr(_pickle.dumps(_os.path.abspath(outfile))),
|
||||
'argv': repr(_pickle.dumps(argv)),
|
||||
'env': repr(_pickle.dumps(env)),
|
||||
})
|
||||
fd, _ = None, _os.close(fd)
|
||||
if _sys.platform == 'win32':
|
||||
argv = []
|
||||
for arg in [_sys.executable, name]:
|
||||
if ' ' in arg or arg.startswith('"'):
|
||||
arg = '"%s"' % arg.replace('"', '\\"')
|
||||
argv.append(arg)
|
||||
argv = ' '.join(argv)
|
||||
close_fds = False
|
||||
shell = True
|
||||
else:
|
||||
argv = [_sys.executable, name]
|
||||
close_fds = True
|
||||
shell = False
|
||||
|
||||
if subprocess is None:
|
||||
pid = _os.spawnve(_os.P_NOWAIT, argv[0], argv, env)
|
||||
return _os.waitpid(pid, 0)[1]
|
||||
else:
|
||||
p = subprocess.Popen(
|
||||
argv, env=env, shell=shell, close_fds=close_fds
|
||||
)
|
||||
return p.wait()
|
||||
finally:
|
||||
try:
|
||||
if fd is not None:
|
||||
_os.close(fd)
|
||||
finally:
|
||||
_os.unlink(name)
|
||||
|
||||
|
||||
def spawn(*argv, **kwargs):
|
||||
""" Spawn a process """
|
||||
try:
|
||||
import subprocess
|
||||
except ImportError:
|
||||
subprocess = None
|
||||
|
||||
if _sys.platform == 'win32':
|
||||
newargv = []
|
||||
for arg in argv:
|
||||
if not arg or ' ' in arg or arg.startswith('"'):
|
||||
arg = '"%s"' % arg.replace('"', '\\"')
|
||||
newargv.append(arg)
|
||||
argv = newargv
|
||||
close_fds = False
|
||||
shell = True
|
||||
else:
|
||||
close_fds = True
|
||||
shell = False
|
||||
|
||||
env = kwargs.get('env')
|
||||
if env is None:
|
||||
env = dict(_os.environ)
|
||||
if 'X_JYTHON_WA_PATH' in env:
|
||||
env['PATH'] = env['X_JYTHON_WA_PATH']
|
||||
|
||||
echo = kwargs.get('echo')
|
||||
if echo:
|
||||
print ' '.join(argv)
|
||||
filepipe = kwargs.get('filepipe')
|
||||
if filepipe:
|
||||
return _filepipespawn(
|
||||
kwargs.get('stdin'), kwargs.get('stdout'), argv, env
|
||||
)
|
||||
pipe = kwargs.get('stdout')
|
||||
if pipe:
|
||||
return _pipespawn(argv, env)
|
||||
|
||||
if subprocess is None:
|
||||
pid = _os.spawnve(_os.P_NOWAIT, argv[0], argv, env)
|
||||
return _os.waitpid(pid, 0)[1]
|
||||
else:
|
||||
p = subprocess.Popen(argv, env=env, shell=shell, close_fds=close_fds)
|
||||
return p.wait()
|
||||
|
||||
|
||||
try:
|
||||
walk = _os.walk
|
||||
except AttributeError:
|
||||
# copy from python 2.4 sources (modulo docs and comments)
|
||||
def walk(top, topdown=True, onerror=None):
|
||||
""" directory tree walker """
|
||||
# pylint: disable = C0103
|
||||
join, isdir, islink = _os.path.join, _os.path.isdir, _os.path.islink
|
||||
listdir, error = _os.listdir, _os.error
|
||||
|
||||
try:
|
||||
names = listdir(top)
|
||||
except error, err:
|
||||
if onerror is not None:
|
||||
onerror(err)
|
||||
return
|
||||
|
||||
dirs, nondirs = [], []
|
||||
for name in names:
|
||||
if isdir(join(top, name)):
|
||||
dirs.append(name)
|
||||
else:
|
||||
nondirs.append(name)
|
||||
|
||||
if topdown:
|
||||
yield top, dirs, nondirs
|
||||
for name in dirs:
|
||||
path = join(top, name)
|
||||
if not islink(path):
|
||||
for x in walk(path, topdown, onerror):
|
||||
yield x
|
||||
if not topdown:
|
||||
yield top, dirs, nondirs
|
||||
|
||||
|
||||
def files(base, wildcard='[!.]*', recursive=1, prune=('.svn', 'CVS')):
|
||||
""" Determine a filelist """
|
||||
for dirpath, dirnames, filenames in walk(native(base)):
|
||||
for item in prune:
|
||||
if item in dirnames:
|
||||
dirnames.remove(item)
|
||||
|
||||
filenames.sort()
|
||||
for name in _fnmatch.filter(filenames, wildcard):
|
||||
dest = _os.path.join(dirpath, name)
|
||||
if dest.startswith(cwd):
|
||||
dest = dest.replace(cwd, '', 1)
|
||||
aslist = []
|
||||
head, tail = _os.path.split(dest)
|
||||
while tail:
|
||||
aslist.append(tail)
|
||||
head, tail = _os.path.split(head)
|
||||
aslist.reverse()
|
||||
dest = '/'.join(aslist)
|
||||
yield dest
|
||||
|
||||
if not recursive:
|
||||
break
|
||||
dirnames.sort()
|
||||
|
||||
|
||||
def dirs(base, wildcard='[!.]*', recursive=1, prune=('.svn', 'CVS')):
|
||||
""" Determine a filelist """
|
||||
for dirpath, dirnames, filenames in walk(native(base)):
|
||||
for item in prune:
|
||||
if item in dirnames:
|
||||
dirnames.remove(item)
|
||||
|
||||
dirnames.sort()
|
||||
for name in _fnmatch.filter(dirnames, wildcard):
|
||||
dest = _os.path.join(dirpath, name)
|
||||
if dest.startswith(cwd):
|
||||
dest = dest.replace(cwd, '', 1)
|
||||
aslist = []
|
||||
head, tail = _os.path.split(dest)
|
||||
while tail:
|
||||
aslist.append(tail)
|
||||
head, tail = _os.path.split(head)
|
||||
aslist.reverse()
|
||||
dest = '/'.join(aslist)
|
||||
yield dest
|
||||
|
||||
if not recursive:
|
||||
break
|
||||
|
||||
|
||||
def frompath(executable):
|
||||
""" Find executable in PATH """
|
||||
# Based on distutils.spawn.find_executable.
|
||||
path = _os.environ.get('PATH', '')
|
||||
paths = [
|
||||
_os.path.expanduser(item)
|
||||
for item in path.split(_os.pathsep)
|
||||
]
|
||||
ext = _os.path.splitext(executable)[1]
|
||||
exts = ['']
|
||||
if _sys.platform == 'win32' or _os.name == 'os2':
|
||||
eext = ['.exe', '.bat', '.py']
|
||||
if ext not in eext:
|
||||
exts.extend(eext)
|
||||
|
||||
for ext in exts:
|
||||
if not _os.path.isfile(executable + ext):
|
||||
for path in paths:
|
||||
fname = _os.path.join(path, executable + ext)
|
||||
if _os.path.isfile(fname):
|
||||
# the file exists, we have a shot at spawn working
|
||||
return fname
|
||||
else:
|
||||
return executable + ext
|
||||
|
||||
return None
|
28
_setup/py2/term/__init__.py
Normal file
28
_setup/py2/term/__init__.py
Normal file
@ -0,0 +1,28 @@
|
||||
# -*- coding: ascii -*-
|
||||
#
|
||||
# Copyright 2010, 2011
|
||||
# Andr\xe9 Malo or his licensors, as applicable
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
"""
|
||||
=====================
|
||||
Package _setup.term
|
||||
=====================
|
||||
|
||||
Terminal tools, not distributed.
|
||||
"""
|
||||
__author__ = u"Andr\xe9 Malo"
|
||||
__docformat__ = "restructuredtext en"
|
||||
|
||||
# pylint: disable = W0611
|
||||
from _setup.term._term import terminfo, write, green, red, yellow, announce
|
115
_setup/py2/term/_term.py
Normal file
115
_setup/py2/term/_term.py
Normal file
@ -0,0 +1,115 @@
|
||||
# -*- coding: ascii -*-
|
||||
#
|
||||
# Copyright 2007, 2008, 2009, 2010, 2011
|
||||
# Andr\xe9 Malo or his licensors, as applicable
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
"""
|
||||
=================
|
||||
Terminal writer
|
||||
=================
|
||||
"""
|
||||
__author__ = u"Andr\xe9 Malo"
|
||||
__docformat__ = "restructuredtext en"
|
||||
|
||||
import sys as _sys
|
||||
|
||||
|
||||
class _INFO(dict):
|
||||
""" Terminal info dict """
|
||||
|
||||
def __init__(self):
|
||||
""" Initialization """
|
||||
dict.__init__(self, {
|
||||
'NORMAL': '',
|
||||
'BOLD': '',
|
||||
'ERASE': '\n',
|
||||
'RED': '',
|
||||
'YELLOW': '',
|
||||
'GREEN': '',
|
||||
})
|
||||
try:
|
||||
import curses as _curses
|
||||
except ImportError:
|
||||
# fixup if a submodule of curses failed.
|
||||
if 'curses' in _sys.modules:
|
||||
del _sys.modules['curses']
|
||||
else:
|
||||
try:
|
||||
_curses.setupterm()
|
||||
except (TypeError, _curses.error):
|
||||
pass
|
||||
else:
|
||||
def make_color(color):
|
||||
""" Make color control string """
|
||||
seq = _curses.tigetstr('setaf')
|
||||
if seq is not None:
|
||||
# XXX may fail - need better logic
|
||||
seq = seq.replace("%p1", "") % color
|
||||
return seq
|
||||
|
||||
self['NORMAL'] = _curses.tigetstr('sgr0')
|
||||
self['BOLD'] = _curses.tigetstr('bold')
|
||||
|
||||
erase = _curses.tigetstr('el1')
|
||||
if erase is not None:
|
||||
self['ERASE'] = erase + _curses.tigetstr('cr')
|
||||
|
||||
self['RED'] = make_color(_curses.COLOR_RED)
|
||||
self['YELLOW'] = make_color(_curses.COLOR_YELLOW)
|
||||
self['GREEN'] = make_color(_curses.COLOR_GREEN)
|
||||
|
||||
def __getitem__(self, key):
|
||||
""" Deliver always """
|
||||
dict.get(self, key) or ""
|
||||
|
||||
|
||||
def terminfo():
|
||||
""" Get info singleton """
|
||||
# pylint: disable = E1101, W0612
|
||||
if terminfo.info is None:
|
||||
terminfo.info = _INFO()
|
||||
return terminfo.info
|
||||
terminfo.info = None
|
||||
|
||||
|
||||
def write(fmt, **kwargs):
|
||||
""" Write stuff on the terminal """
|
||||
parm = dict(terminfo())
|
||||
parm.update(kwargs)
|
||||
_sys.stdout.write(fmt % parm)
|
||||
_sys.stdout.flush()
|
||||
|
||||
|
||||
def green(bmt, **kwargs):
|
||||
""" Write something in green on screen """
|
||||
announce("%%(GREEN)s%s%%(NORMAL)s" % bmt, **kwargs)
|
||||
|
||||
|
||||
def red(bmt, **kwargs):
|
||||
""" Write something in red on the screen """
|
||||
announce("%%(BOLD)s%%(RED)s%s%%(NORMAL)s" % bmt, **kwargs)
|
||||
|
||||
|
||||
def yellow(fmt, **kwargs):
|
||||
""" Write something in yellow on the screen """
|
||||
announce("%%(BOLD)s%%(YELLOW)s%s%%(NORMAL)s" % fmt, **kwargs)
|
||||
|
||||
|
||||
def announce(fmt, **kwargs):
|
||||
""" Announce something """
|
||||
write(fmt, **kwargs)
|
||||
_sys.stdout.write("\n")
|
||||
_sys.stdout.flush()
|
||||
|
||||
|
73
_setup/py2/util.py
Normal file
73
_setup/py2/util.py
Normal file
@ -0,0 +1,73 @@
|
||||
# -*- coding: ascii -*-
|
||||
#
|
||||
# Copyright 2007, 2008, 2009, 2010, 2011
|
||||
# Andr\xe9 Malo or his licensors, as applicable
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
"""
|
||||
=================
|
||||
Setup utilities
|
||||
=================
|
||||
|
||||
Setup utilities.
|
||||
"""
|
||||
__author__ = u"Andr\xe9 Malo"
|
||||
__docformat__ = "restructuredtext en"
|
||||
|
||||
try:
|
||||
from distutils import log
|
||||
except ImportError:
|
||||
class log(object):
|
||||
def info(self, value):
|
||||
print value
|
||||
def debug(self, value):
|
||||
pass
|
||||
log = log()
|
||||
|
||||
from distutils import util as _util
|
||||
try:
|
||||
from ConfigParser import SafeConfigParser
|
||||
except ImportError:
|
||||
import ConfigParser as _config_parser
|
||||
class SafeConfigParser(_config_parser.ConfigParser):
|
||||
""" Safe config parser """
|
||||
def _interpolate(self, section, option, rawval, vars):
|
||||
return rawval
|
||||
|
||||
def items(self, section):
|
||||
return [(key, self.get(section, key))
|
||||
for key in self.options(section)
|
||||
]
|
||||
|
||||
|
||||
def humanbool(name, value):
|
||||
"""
|
||||
Determine human boolean value
|
||||
|
||||
:Parameters:
|
||||
`name` : ``str``
|
||||
The config key (used for error message)
|
||||
|
||||
`value` : ``str``
|
||||
The config value
|
||||
|
||||
:Return: The boolean value
|
||||
:Rtype: ``bool``
|
||||
|
||||
:Exceptions:
|
||||
- `ValueError` : The value could not be recognized
|
||||
"""
|
||||
try:
|
||||
return _util.strtobool(str(value).strip().lower() or 'no')
|
||||
except ValueError:
|
||||
raise ValueError("Unrecognized config value: %s = %s" % (name, value))
|
27
_setup/py3/__init__.py
Normal file
27
_setup/py3/__init__.py
Normal file
@ -0,0 +1,27 @@
|
||||
# -*- coding: ascii -*-
|
||||
#
|
||||
# Copyright 2007, 2008, 2009, 2010, 2011
|
||||
# Andr\xe9 Malo or his licensors, as applicable
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
"""
|
||||
================
|
||||
Package _setup
|
||||
================
|
||||
|
||||
This package provides tools for main package setup.
|
||||
"""
|
||||
__author__ = "Andr\xe9 Malo"
|
||||
__docformat__ = "restructuredtext en"
|
||||
|
||||
from _setup.setup import run # pylint: disable = W0611
|
266
_setup/py3/commands.py
Normal file
266
_setup/py3/commands.py
Normal file
@ -0,0 +1,266 @@
|
||||
# -*- coding: ascii -*-
|
||||
#
|
||||
# Copyright 2007, 2008, 2009, 2010, 2011
|
||||
# Andr\xe9 Malo or his licensors, as applicable
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
"""
|
||||
===================
|
||||
Command extenders
|
||||
===================
|
||||
|
||||
Command extenders.
|
||||
"""
|
||||
__author__ = "Andr\xe9 Malo"
|
||||
__docformat__ = "restructuredtext en"
|
||||
__test__ = False
|
||||
|
||||
from distutils import fancy_getopt as _fancy_getopt
|
||||
from distutils import log
|
||||
from distutils.command import build as _build
|
||||
from distutils.command import build_ext as _build_ext
|
||||
from distutils.command import install as _install
|
||||
from distutils.command import install_data as _install_data
|
||||
from distutils.command import install_lib as _install_lib
|
||||
import os as _os
|
||||
|
||||
_option_defaults = {}
|
||||
_option_inherits = {}
|
||||
_option_finalizers = {}
|
||||
_command_mapping = {
|
||||
'install': 'Install',
|
||||
'install_data': 'InstallData',
|
||||
'install_lib': 'InstallLib',
|
||||
'build': 'Build',
|
||||
'build_ext': 'BuildExt',
|
||||
}
|
||||
|
||||
|
||||
def add_option(command, long_name, help_text, short_name=None, default=None,
|
||||
inherit=None):
|
||||
""" Add an option """
|
||||
try:
|
||||
command_class = globals()[_command_mapping[command]]
|
||||
except KeyError:
|
||||
raise ValueError("Unknown command %r" % (command,))
|
||||
for opt in command_class.user_options:
|
||||
if opt[0] == long_name:
|
||||
break
|
||||
else:
|
||||
opt = (long_name, short_name, help_text)
|
||||
command_class.user_options.append(opt)
|
||||
if not long_name.endswith('='):
|
||||
command_class.boolean_options.append(long_name)
|
||||
attr_name = _fancy_getopt.translate_longopt(long_name)
|
||||
else:
|
||||
attr_name = _fancy_getopt.translate_longopt(long_name[:-1])
|
||||
if command not in _option_defaults:
|
||||
_option_defaults[command] = []
|
||||
if inherit is not None:
|
||||
if isinstance(inherit, str):
|
||||
inherit = [inherit]
|
||||
for i_inherit in inherit:
|
||||
add_option(
|
||||
i_inherit, long_name, help_text, short_name, default
|
||||
)
|
||||
default = None
|
||||
if command not in _option_inherits:
|
||||
_option_inherits[command] = []
|
||||
for i_inherit in inherit:
|
||||
for i_command, opt_name in _option_inherits[command]:
|
||||
if i_command == i_inherit and opt_name == attr_name:
|
||||
break
|
||||
else:
|
||||
_option_inherits[command].append((i_inherit, attr_name))
|
||||
_option_defaults[command].append((attr_name, default))
|
||||
|
||||
|
||||
def add_finalizer(command, key, func):
|
||||
""" Add finalizer """
|
||||
if command not in _option_finalizers:
|
||||
_option_finalizers[command] = {}
|
||||
if key not in _option_finalizers[command]:
|
||||
_option_finalizers[command][key] = func
|
||||
|
||||
|
||||
class Install(_install.install):
|
||||
""" Extended installer to reflect the additional data options """
|
||||
user_options = _install.install.user_options + [
|
||||
('single-version-externally-managed', None,
|
||||
"Compat option. Does not a thing."),
|
||||
]
|
||||
boolean_options = _install.install.boolean_options + [
|
||||
'single-version-externally-managed'
|
||||
]
|
||||
|
||||
def initialize_options(self):
|
||||
""" Prepare for new options """
|
||||
_install.install.initialize_options(self)
|
||||
self.single_version_externally_managed = None
|
||||
if 'install' in _option_defaults:
|
||||
for opt_name, default in _option_defaults['install']:
|
||||
setattr(self, opt_name, default)
|
||||
|
||||
def finalize_options(self):
|
||||
""" Finalize options """
|
||||
_install.install.finalize_options(self)
|
||||
if 'install' in _option_inherits:
|
||||
for parent, opt_name in _option_inherits['install']:
|
||||
self.set_undefined_options(parent, (opt_name, opt_name))
|
||||
if 'install' in _option_finalizers:
|
||||
for func in list(_option_finalizers['install'].values()):
|
||||
func(self)
|
||||
|
||||
|
||||
class InstallData(_install_data.install_data):
|
||||
""" Extended data installer """
|
||||
user_options = _install_data.install_data.user_options + []
|
||||
boolean_options = _install_data.install_data.boolean_options + []
|
||||
|
||||
def initialize_options(self):
|
||||
""" Prepare for new options """
|
||||
_install_data.install_data.initialize_options(self)
|
||||
if 'install_data' in _option_defaults:
|
||||
for opt_name, default in _option_defaults['install_data']:
|
||||
setattr(self, opt_name, default)
|
||||
|
||||
def finalize_options(self):
|
||||
""" Finalize options """
|
||||
_install_data.install_data.finalize_options(self)
|
||||
if 'install_data' in _option_inherits:
|
||||
for parent, opt_name in _option_inherits['install_data']:
|
||||
self.set_undefined_options(parent, (opt_name, opt_name))
|
||||
if 'install_data' in _option_finalizers:
|
||||
for func in list(_option_finalizers['install_data'].values()):
|
||||
func(self)
|
||||
|
||||
|
||||
class InstallLib(_install_lib.install_lib):
|
||||
""" Extended lib installer """
|
||||
user_options = _install_lib.install_lib.user_options + []
|
||||
boolean_options = _install_lib.install_lib.boolean_options + []
|
||||
|
||||
def initialize_options(self):
|
||||
""" Prepare for new options """
|
||||
_install_lib.install_lib.initialize_options(self)
|
||||
if 'install_lib' in _option_defaults:
|
||||
for opt_name, default in _option_defaults['install_lib']:
|
||||
setattr(self, opt_name, default)
|
||||
|
||||
def finalize_options(self):
|
||||
""" Finalize options """
|
||||
_install_lib.install_lib.finalize_options(self)
|
||||
if 'install_lib' in _option_inherits:
|
||||
for parent, opt_name in _option_inherits['install_lib']:
|
||||
self.set_undefined_options(parent, (opt_name, opt_name))
|
||||
if 'install_lib' in _option_finalizers:
|
||||
for func in list(_option_finalizers['install_lib'].values()):
|
||||
func(self)
|
||||
|
||||
|
||||
class BuildExt(_build_ext.build_ext):
|
||||
"""
|
||||
Extended extension builder class
|
||||
|
||||
This class allows extensions to provide a ``check_prerequisites`` method
|
||||
which is called before actually building it. The method takes the
|
||||
`BuildExt` instance and returns whether the extension should be skipped or
|
||||
not.
|
||||
"""
|
||||
|
||||
def initialize_options(self):
|
||||
""" Prepare for new options """
|
||||
_build_ext.build_ext.initialize_options(self)
|
||||
if 'build_ext' in _option_defaults:
|
||||
for opt_name, default in _option_defaults['build_ext']:
|
||||
setattr(self, opt_name, default)
|
||||
|
||||
def finalize_options(self):
|
||||
""" Finalize options """
|
||||
_build_ext.build_ext.finalize_options(self)
|
||||
if 'build_ext' in _option_inherits:
|
||||
for parent, opt_name in _option_inherits['build_ext']:
|
||||
self.set_undefined_options(parent, (opt_name, opt_name))
|
||||
if 'build_ext' in _option_finalizers:
|
||||
for func in list(_option_finalizers['build_ext'].values()):
|
||||
func(self)
|
||||
|
||||
def build_extension(self, ext):
|
||||
"""
|
||||
Build C extension - with extended functionality
|
||||
|
||||
The following features are added here:
|
||||
|
||||
- ``ext.check_prerequisites`` is called before the extension is being
|
||||
built. See `Extension` for details. If the method does not exist,
|
||||
simply no check will be run.
|
||||
- The macros ``EXT_PACKAGE`` and ``EXT_MODULE`` will be filled (or
|
||||
unset) depending on the extensions name, but only if they are not
|
||||
already defined.
|
||||
|
||||
:Parameters:
|
||||
`ext` : `Extension`
|
||||
The extension to build. If it's a pure
|
||||
``distutils.core.Extension``, simply no prequisites check is
|
||||
applied.
|
||||
|
||||
:Return: whatever ``distutils.command.build_ext.build_ext`` returns
|
||||
:Rtype: any
|
||||
"""
|
||||
# handle name macros
|
||||
macros = dict(ext.define_macros or ())
|
||||
tup = ext.name.split('.')
|
||||
if len(tup) == 1:
|
||||
pkg, mod = None, tup[0]
|
||||
else:
|
||||
pkg, mod = '.'.join(tup[:-1]), tup[-1]
|
||||
if pkg is not None and 'EXT_PACKAGE' not in macros:
|
||||
ext.define_macros.append(('EXT_PACKAGE', pkg))
|
||||
if 'EXT_MODULE' not in macros:
|
||||
ext.define_macros.append(('EXT_MODULE', mod))
|
||||
if pkg is None:
|
||||
macros = dict(ext.undef_macros or ())
|
||||
if 'EXT_PACKAGE' not in macros:
|
||||
ext.undef_macros.append('EXT_PACKAGE')
|
||||
|
||||
# handle prereq checks
|
||||
try:
|
||||
checker = ext.check_prerequisites
|
||||
except AttributeError:
|
||||
pass
|
||||
else:
|
||||
if checker(self):
|
||||
log.info("Skipping %s extension" % ext.name)
|
||||
return
|
||||
|
||||
return _build_ext.build_ext.build_extension(self, ext)
|
||||
|
||||
|
||||
class Build(_build.build):
|
||||
|
||||
def initialize_options(self):
|
||||
""" Prepare for new options """
|
||||
_build.build.initialize_options(self)
|
||||
if 'build' in _option_defaults:
|
||||
for opt_name, default in _option_defaults['build']:
|
||||
setattr(self, opt_name, default)
|
||||
|
||||
def finalize_options(self):
|
||||
""" Finalize options """
|
||||
_build.build.finalize_options(self)
|
||||
if 'build' in _option_inherits:
|
||||
for parent, opt_name in _option_inherits['build']:
|
||||
self.set_undefined_options(parent, (opt_name, opt_name))
|
||||
if 'build' in _option_finalizers:
|
||||
for func in list(_option_finalizers['build'].values()):
|
||||
func(self)
|
165
_setup/py3/data.py
Normal file
165
_setup/py3/data.py
Normal file
@ -0,0 +1,165 @@
|
||||
# -*- coding: ascii -*-
|
||||
#
|
||||
# Copyright 2007, 2008, 2009, 2010, 2011
|
||||
# Andr\xe9 Malo or his licensors, as applicable
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
"""
|
||||
===================
|
||||
Data distribution
|
||||
===================
|
||||
|
||||
This module provides tools to simplify data distribution.
|
||||
"""
|
||||
__author__ = "Andr\xe9 Malo"
|
||||
__docformat__ = "restructuredtext en"
|
||||
|
||||
from distutils import filelist as _filelist
|
||||
import os as _os
|
||||
import posixpath as _posixpath
|
||||
import sys as _sys
|
||||
|
||||
from _setup import commands as _commands
|
||||
|
||||
|
||||
def splitpath(path):
|
||||
""" Split a path """
|
||||
drive, path = '', _os.path.normpath(path)
|
||||
try:
|
||||
splitunc = _os.path.splitunc
|
||||
except AttributeError:
|
||||
pass
|
||||
else:
|
||||
drive, path = splitunc(path)
|
||||
if not drive:
|
||||
drive, path = _os.path.splitdrive(path)
|
||||
elems = []
|
||||
try:
|
||||
sep = _os.path.sep
|
||||
except AttributeError:
|
||||
sep = _os.path.join('1', '2')[1:-1]
|
||||
while 1:
|
||||
prefix, path = _os.path.split(path)
|
||||
elems.append(path)
|
||||
if prefix in ('', sep):
|
||||
drive = _os.path.join(drive, prefix)
|
||||
break
|
||||
path = prefix
|
||||
elems.reverse()
|
||||
return drive, elems
|
||||
|
||||
|
||||
def finalizer(installer):
|
||||
""" Finalize install_data """
|
||||
data_files = []
|
||||
for item in installer.data_files:
|
||||
if not isinstance(item, Data):
|
||||
data_files.append(item)
|
||||
continue
|
||||
data_files.extend(item.flatten(installer))
|
||||
installer.data_files = data_files
|
||||
|
||||
|
||||
class Data(object):
|
||||
""" File list container """
|
||||
|
||||
def __init__(self, files, target=None, preserve=0, strip=0,
|
||||
prefix=None):
|
||||
""" Initialization """
|
||||
self._files = files
|
||||
self._target = target
|
||||
self._preserve = preserve
|
||||
self._strip = strip
|
||||
self._prefix = prefix
|
||||
self.fixup_commands()
|
||||
|
||||
def fixup_commands(self):
|
||||
pass
|
||||
|
||||
def from_templates(cls, *templates, **kwargs):
|
||||
""" Initialize from template """
|
||||
files = _filelist.FileList()
|
||||
for tpl in templates:
|
||||
for line in tpl.split(';'):
|
||||
files.process_template_line(line.strip())
|
||||
files.sort()
|
||||
files.remove_duplicates()
|
||||
result = []
|
||||
for filename in files.files:
|
||||
_, elems = splitpath(filename)
|
||||
if '.svn' in elems:
|
||||
continue
|
||||
result.append(filename)
|
||||
return cls(result, **kwargs)
|
||||
from_templates = classmethod(from_templates)
|
||||
|
||||
def flatten(self, installer):
|
||||
""" Flatten the file list to (target, file) tuples """
|
||||
# pylint: disable = W0613
|
||||
if self._prefix:
|
||||
_, prefix = splitpath(self._prefix)
|
||||
telems = prefix
|
||||
else:
|
||||
telems = []
|
||||
|
||||
tmap = {}
|
||||
for fname in self._files:
|
||||
(_, name), target = splitpath(fname), telems
|
||||
if self._preserve:
|
||||
if self._strip:
|
||||
name = name[max(0, min(self._strip, len(name) - 1)):]
|
||||
if len(name) > 1:
|
||||
target = telems + name[:-1]
|
||||
tmap.setdefault(_posixpath.join(*target), []).append(fname)
|
||||
return list(tmap.items())
|
||||
|
||||
|
||||
class Documentation(Data):
|
||||
""" Documentation container """
|
||||
|
||||
def fixup_commands(self):
|
||||
_commands.add_option('install_data', 'without-docs',
|
||||
help_text='Do not install documentation files',
|
||||
inherit='install',
|
||||
)
|
||||
_commands.add_finalizer('install_data', 'documentation', finalizer)
|
||||
|
||||
def flatten(self, installer):
|
||||
""" Check if docs should be installed at all """
|
||||
if installer.without_docs:
|
||||
return []
|
||||
return Data.flatten(self, installer)
|
||||
|
||||
|
||||
class Manpages(Documentation):
|
||||
""" Manpages container """
|
||||
|
||||
def dispatch(cls, files):
|
||||
""" Automatically dispatch manpages to their target directories """
|
||||
mpmap = {}
|
||||
for manpage in files:
|
||||
normalized = _os.path.normpath(manpage)
|
||||
_, ext = _os.path.splitext(normalized)
|
||||
if ext.startswith(_os.path.extsep):
|
||||
ext = ext[len(_os.path.extsep):]
|
||||
mpmap.setdefault(ext, []).append(manpage)
|
||||
return [cls(manpages, prefix=_posixpath.join(
|
||||
'share', 'man', 'man%s' % section,
|
||||
)) for section, manpages in list(mpmap.items())]
|
||||
dispatch = classmethod(dispatch)
|
||||
|
||||
def flatten(self, installer):
|
||||
""" Check if manpages are suitable """
|
||||
if _sys.platform == 'win32':
|
||||
return []
|
||||
return Documentation.flatten(self, installer)
|
25
_setup/py3/dev/__init__.py
Normal file
25
_setup/py3/dev/__init__.py
Normal file
@ -0,0 +1,25 @@
|
||||
# -*- coding: ascii -*-
|
||||
#
|
||||
# Copyright 2009, 2010, 2011
|
||||
# Andr\xe9 Malo or his licensors, as applicable
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
"""
|
||||
====================
|
||||
Package _setup.dev
|
||||
====================
|
||||
|
||||
Development tools, not distributed.
|
||||
"""
|
||||
__author__ = "Andr\xe9 Malo"
|
||||
__docformat__ = "restructuredtext en"
|
258
_setup/py3/dev/_pylint.py
Normal file
258
_setup/py3/dev/_pylint.py
Normal file
@ -0,0 +1,258 @@
|
||||
# -*- coding: ascii -*-
|
||||
#
|
||||
# Copyright 2006, 2007, 2008, 2009, 2010, 2011
|
||||
# Andr\xe9 Malo or his licensors, as applicable
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
"""
|
||||
=================================
|
||||
Support for code analysis tools
|
||||
=================================
|
||||
|
||||
Support for code analysis tools.
|
||||
"""
|
||||
__author__ = "Andr\xe9 Malo"
|
||||
__docformat__ = "restructuredtext en"
|
||||
|
||||
import re as _re
|
||||
import sys as _sys
|
||||
|
||||
from _setup import term as _term
|
||||
from _setup import shell as _shell
|
||||
|
||||
|
||||
class NotFinished(Exception):
|
||||
""" Exception used for message passing in the stream filter """
|
||||
|
||||
class NotParseable(Exception):
|
||||
""" Exception used for message passing in the stream filter """
|
||||
|
||||
class SpecialMessage(Exception):
|
||||
""" Exception used for message passing in the stream filter """
|
||||
|
||||
|
||||
class FilterStream(object):
|
||||
""" Stream filter """
|
||||
_LINERE = _re.compile(r'''
|
||||
(?P<name>[^:]+)
|
||||
:
|
||||
(?P<lineno>\d+)
|
||||
:\s+
|
||||
\[(?P<mid>[^\],]+)(?:,\s+(?P<func>[^\]]+))?\]
|
||||
\s+
|
||||
(?P<desc>.*)
|
||||
''', _re.X)
|
||||
_SIMRE = _re.compile(r'in (?P<number>\d+) files')
|
||||
_CYCRE = _re.compile(r'\((?P<cycle>[^)]+)\)')
|
||||
|
||||
def __init__(self, term, stream=_sys.stdout):
|
||||
self.written = False
|
||||
self._stream = stream
|
||||
self._lastname = None
|
||||
self._cycled = False
|
||||
self._term = dict(term)
|
||||
self._buffer = ''
|
||||
|
||||
def write(self, towrite):
|
||||
""" Stream write function """
|
||||
self._buffer += towrite
|
||||
term = self._term
|
||||
|
||||
while True:
|
||||
try:
|
||||
name, lineno, mid, func, desc = self._parse()
|
||||
except NotFinished:
|
||||
break
|
||||
except SpecialMessage as e:
|
||||
self._dospecial(e)
|
||||
continue
|
||||
except NotParseable as e:
|
||||
self._print_literal(str(e.args[0]))
|
||||
continue
|
||||
|
||||
if name != self._lastname:
|
||||
if self._lastname is not None:
|
||||
self._stream.write("\n")
|
||||
term['path'] = name
|
||||
self._stream.write(
|
||||
"%(BOLD)s>>> %(path)s%(NORMAL)s\n" % term
|
||||
)
|
||||
self._lastname = name
|
||||
self.written = True
|
||||
|
||||
term['mid'] = mid
|
||||
if mid.startswith('E') or mid.startswith('F'):
|
||||
self._stream.write("%(BOLD)s%(RED)s%(mid)s%(NORMAL)s" % term)
|
||||
elif mid == 'W0511':
|
||||
self._stream.write(
|
||||
"%(BOLD)s%(GREEN)s%(mid)s%(NORMAL)s" % term
|
||||
)
|
||||
else:
|
||||
self._stream.write(
|
||||
"%(BOLD)s%(YELLOW)s%(mid)s%(NORMAL)s" % term
|
||||
)
|
||||
|
||||
if int(lineno) != 0:
|
||||
term['lineno'] = lineno
|
||||
self._stream.write(" (%(lineno)s" % term)
|
||||
if func:
|
||||
term['func'] = func
|
||||
self._stream.write(
|
||||
", %(BOLD)s%(YELLOW)s%(func)s%(NORMAL)s" % term
|
||||
)
|
||||
self._stream.write(')')
|
||||
|
||||
self._stream.write(": %s\n" % desc)
|
||||
self._stream.flush()
|
||||
|
||||
return
|
||||
|
||||
def _print_literal(self, line):
|
||||
""" Print literal """
|
||||
suppress = (
|
||||
line.startswith('Unable to get imported names for ') or
|
||||
line.startswith("Exception exceptions.RuntimeError: 'generator "
|
||||
"ignored GeneratorExit' in <generator object at") or
|
||||
line.startswith("Exception RuntimeError: 'generator "
|
||||
"ignored GeneratorExit' in <generator object") or
|
||||
not line.strip()
|
||||
)
|
||||
if not suppress:
|
||||
self._stream.write("%s\n" % line)
|
||||
self._stream.flush()
|
||||
self.written = True
|
||||
|
||||
def _dospecial(self, e):
|
||||
""" Deal with special messages """
|
||||
if e.args[0] == 'R0401':
|
||||
pos = self._buffer.find('\n')
|
||||
line, self._buffer = (
|
||||
self._buffer[:pos + 1], self._buffer[pos + 1:]
|
||||
)
|
||||
term = self._term
|
||||
term['mid'] = e.args[0]
|
||||
if not self._cycled:
|
||||
self._cycled = True
|
||||
self._stream.write('\n')
|
||||
self._stream.write(
|
||||
"%(BOLD)s%(YELLOW)s%(mid)s%(NORMAL)s" % term
|
||||
)
|
||||
self._stream.write(": Cyclic imports\n")
|
||||
match = self._CYCRE.search(e.args[1])
|
||||
term['cycle'] = match.group('cycle')
|
||||
self._stream.write("%(BOLD)s@@@ %(NORMAL)s%(cycle)s\n" % term)
|
||||
self._stream.flush()
|
||||
self.written = True
|
||||
|
||||
elif e.args[0] == 'R0801':
|
||||
match = self._SIMRE.search(e.args[1])
|
||||
if not match:
|
||||
raise AssertionError(
|
||||
'Could not determine number of similar files'
|
||||
)
|
||||
|
||||
numfiles = int(match.group('number'))
|
||||
pos = -1
|
||||
for _ in range(numfiles + 1):
|
||||
pos = self._buffer.find('\n', pos + 1)
|
||||
if pos >= 0:
|
||||
lines = self._buffer[:pos + 1]
|
||||
self._buffer = self._buffer[pos + 1:]
|
||||
term = self._term
|
||||
|
||||
self._stream.write("\n")
|
||||
for name in lines.splitlines()[1:]:
|
||||
name = name.rstrip()[2:]
|
||||
term['path'] = name
|
||||
self._stream.write(
|
||||
"%(BOLD)s=== %(path)s%(NORMAL)s\n" % term
|
||||
)
|
||||
self._lastname = name
|
||||
|
||||
term['mid'] = e.args[0]
|
||||
self._stream.write(
|
||||
"%(BOLD)s%(YELLOW)s%(mid)s%(NORMAL)s" % term
|
||||
)
|
||||
self._stream.write(": %s\n" % e.args[1])
|
||||
self._stream.flush()
|
||||
self.written = True
|
||||
|
||||
def _parse(self):
|
||||
""" Parse output """
|
||||
if '\n' not in self._buffer:
|
||||
raise NotFinished()
|
||||
|
||||
line = self._buffer[:self._buffer.find('\n') + 1]
|
||||
self._buffer = self._buffer[len(line):]
|
||||
line = line.rstrip()
|
||||
match = self._LINERE.match(line)
|
||||
if not match:
|
||||
raise NotParseable(line)
|
||||
|
||||
mid = match.group('mid')
|
||||
if mid in ('R0801', 'R0401'):
|
||||
self._buffer = "%s\n%s" % (line, self._buffer)
|
||||
raise SpecialMessage(mid, match.group('desc'))
|
||||
|
||||
return match.group('name', 'lineno', 'mid', 'func', 'desc')
|
||||
|
||||
|
||||
def run(config, *args):
|
||||
""" Run pylint """
|
||||
try:
|
||||
from pylint import lint
|
||||
from pylint.reporters import text
|
||||
except ImportError:
|
||||
return 2
|
||||
|
||||
if config is None:
|
||||
config = _shell.native('pylint.conf')
|
||||
argv = ['--rcfile', config,
|
||||
'--reports', 'no',
|
||||
'--output-format', 'parseable',
|
||||
'--include-ids', 'yes'
|
||||
]
|
||||
|
||||
stream = FilterStream(_term.terminfo())
|
||||
|
||||
old_stderr = _sys.stderr
|
||||
try:
|
||||
# pylint: disable = E1101
|
||||
_sys.stderr = stream
|
||||
from pylint import __pkginfo__
|
||||
if __pkginfo__.numversion < (0, 13):
|
||||
# The lint tool is not very user friendly, so we need a hack here.
|
||||
lint.REPORTER_OPT_MAP['parseable'] = \
|
||||
lambda: text.TextReporter2(stream)
|
||||
reporter = text.TextReporter2(stream)
|
||||
else:
|
||||
reporter = text.ParseableTextReporter(stream)
|
||||
lint.REPORTER_OPT_MAP['parseable'] = lambda: reporter
|
||||
|
||||
for path in args:
|
||||
try:
|
||||
try:
|
||||
lint.Run(argv + [path], reporter=reporter)
|
||||
except SystemExit:
|
||||
pass # don't accept the exit. strange errors happen...
|
||||
|
||||
if stream.written:
|
||||
print()
|
||||
stream.written = False
|
||||
except KeyboardInterrupt:
|
||||
print()
|
||||
raise
|
||||
finally:
|
||||
_sys.stderr = old_stderr
|
||||
|
||||
return 0
|
31
_setup/py3/dev/analysis.py
Normal file
31
_setup/py3/dev/analysis.py
Normal file
@ -0,0 +1,31 @@
|
||||
# -*- coding: ascii -*-
|
||||
#
|
||||
# Copyright 2006, 2007, 2008, 2009, 2010, 2011
|
||||
# Andr\xe9 Malo or his licensors, as applicable
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
"""
|
||||
=================================
|
||||
Support for code analysis tools
|
||||
=================================
|
||||
|
||||
Support for code analysis tools.
|
||||
"""
|
||||
__author__ = "Andr\xe9 Malo"
|
||||
__docformat__ = "restructuredtext en"
|
||||
|
||||
|
||||
def pylint(config, *args):
|
||||
""" Run pylint """
|
||||
from _setup.dev import _pylint
|
||||
return _pylint.run(config, *args)
|
131
_setup/py3/dev/apidoc.py
Normal file
131
_setup/py3/dev/apidoc.py
Normal file
@ -0,0 +1,131 @@
|
||||
# -*- coding: ascii -*-
|
||||
#
|
||||
# Copyright 2007, 2008, 2009, 2010, 2011
|
||||
# Andr\xe9 Malo or his licensors, as applicable
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
"""
|
||||
==================
|
||||
API doc builders
|
||||
==================
|
||||
|
||||
API doc builders.
|
||||
"""
|
||||
__author__ = "Andr\xe9 Malo"
|
||||
__docformat__ = "restructuredtext en"
|
||||
|
||||
import os as _os
|
||||
import re as _re
|
||||
|
||||
from _setup import shell as _shell
|
||||
from _setup import term as _term
|
||||
from _setup import util as _util
|
||||
|
||||
|
||||
def _cleanup_epydoc(target):
|
||||
"""
|
||||
Cleanup epydoc generated files
|
||||
|
||||
This removes the epydoc-footer. It changes every release because of the
|
||||
timestamp. That creates bad diffs (accidently it's also invalid html).
|
||||
"""
|
||||
search = _re.compile(r'<table[^<>]+width="100%%"').search
|
||||
for filename in _shell.files(target, '*.html'):
|
||||
fp = open(filename, 'r')
|
||||
try:
|
||||
html = fp.read()
|
||||
finally:
|
||||
fp.close()
|
||||
match = search(html)
|
||||
if match:
|
||||
start = match.start()
|
||||
end = html.find('</table>', start)
|
||||
if end >= 0:
|
||||
end += len('</table>') + 1
|
||||
html = html[:start] + html[end:]
|
||||
fp = open(filename, 'w')
|
||||
try:
|
||||
fp.write(html)
|
||||
finally:
|
||||
fp.close()
|
||||
|
||||
|
||||
_VERSION_SEARCH = _re.compile(
|
||||
r'\bversion\s+(?P<major>\d+)\.(?P<minor>\d+)'
|
||||
).search
|
||||
def epydoc(**kwargs):
|
||||
""" Run epydoc """
|
||||
# pylint: disable = R0912
|
||||
prog = kwargs.get('epydoc') or 'epydoc'
|
||||
if not _os.path.dirname(_os.path.normpath(prog)):
|
||||
prog = _shell.frompath(prog)
|
||||
if not prog:
|
||||
_term.red("%(epydoc)s not found",
|
||||
epydoc=kwargs.get('epydoc') or 'epydoc',
|
||||
)
|
||||
return False
|
||||
|
||||
version = _VERSION_SEARCH(_shell.spawn(prog, "--version", stdout=True))
|
||||
if version is not None:
|
||||
try:
|
||||
version = tuple(map(int, version.group('major', 'minor')))
|
||||
except (TypeError, ValueError):
|
||||
version = None
|
||||
if version is None:
|
||||
_term.red("%(prog)s version not recognized" % locals())
|
||||
return False
|
||||
|
||||
if version < (3, 0):
|
||||
_term.red("%(prog)s is too old %(version)r < (3, 0)" % locals())
|
||||
return False
|
||||
|
||||
env = dict(_os.environ)
|
||||
|
||||
prepend = kwargs.get('prepend')
|
||||
if prepend:
|
||||
toprepend = _os.pathsep.join(map(str, prepend))
|
||||
if 'PYTHONPATH' in env:
|
||||
env['PYTHONPATH'] = _os.pathsep.join((
|
||||
toprepend, env['PYTHONPATH']
|
||||
))
|
||||
else:
|
||||
env['PYTHONPATH'] = toprepend
|
||||
|
||||
append = kwargs.get('append')
|
||||
if append:
|
||||
toappend = _os.pathsep.join(map(str, append))
|
||||
if 'PYTHONPATH' in env:
|
||||
env['PYTHONPATH'] = _os.pathsep.join((
|
||||
env['PYTHONPATH'], toappend
|
||||
))
|
||||
else:
|
||||
env['PYTHONPATH'] = toappend
|
||||
|
||||
moreenv = kwargs.get('env')
|
||||
if moreenv:
|
||||
env.update(moreenv)
|
||||
|
||||
config = kwargs.get('config') or _shell.native('docs/epydoc.conf')
|
||||
|
||||
argv = [prog, '--config', config]
|
||||
res = not _shell.spawn(*argv, **{'env': env})
|
||||
if res:
|
||||
cfg = _util.SafeConfigParser()
|
||||
cfg.read(config)
|
||||
try:
|
||||
target = dict(cfg.items('epydoc'))['target']
|
||||
except KeyError:
|
||||
pass
|
||||
else:
|
||||
_cleanup_epydoc(target)
|
||||
return res
|
50
_setup/py3/dev/userdoc.py
Normal file
50
_setup/py3/dev/userdoc.py
Normal file
@ -0,0 +1,50 @@
|
||||
# -*- coding: ascii -*-
|
||||
#
|
||||
# Copyright 2009, 2010, 2011
|
||||
# Andr\xe9 Malo or his licensors, as applicable
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
"""
|
||||
===================
|
||||
User doc builders
|
||||
===================
|
||||
|
||||
User doc builders.
|
||||
"""
|
||||
__author__ = "Andr\xe9 Malo"
|
||||
__docformat__ = "restructuredtext en"
|
||||
|
||||
import os as _os
|
||||
|
||||
from _setup import shell as _shell
|
||||
from _setup import term as _term
|
||||
|
||||
|
||||
def sphinx(**kwargs):
|
||||
""" Run sphinx """
|
||||
prog = _shell.frompath('sphinx-build')
|
||||
if prog is None:
|
||||
_term.red("sphinx-build not found")
|
||||
return False
|
||||
|
||||
env = dict(_os.environ)
|
||||
|
||||
argv = [
|
||||
prog, '-a',
|
||||
'-d', _os.path.join(kwargs['build'], 'doctrees'),
|
||||
'-b', 'html',
|
||||
kwargs['source'],
|
||||
kwargs['target'],
|
||||
]
|
||||
|
||||
return not _shell.spawn(*argv, **{'env': env})
|
51
_setup/py3/dist.py
Normal file
51
_setup/py3/dist.py
Normal file
@ -0,0 +1,51 @@
|
||||
# -*- coding: ascii -*-
|
||||
#
|
||||
# Copyright 2007, 2008, 2009, 2010, 2011
|
||||
# Andr\xe9 Malo or his licensors, as applicable
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
"""
|
||||
================
|
||||
dist utilities
|
||||
================
|
||||
|
||||
dist utilities.
|
||||
"""
|
||||
__author__ = "Andr\xe9 Malo"
|
||||
__docformat__ = "restructuredtext en"
|
||||
|
||||
import sys as _sys
|
||||
|
||||
from _setup import shell as _shell
|
||||
|
||||
|
||||
def run_setup(*args, **kwargs):
|
||||
""" Run setup """
|
||||
if 'setup' in kwargs:
|
||||
script = kwargs.get('setup') or 'setup.py'
|
||||
del kwargs['setup']
|
||||
else:
|
||||
script = 'setup.py'
|
||||
if 'fakeroot' in kwargs:
|
||||
fakeroot = kwargs['fakeroot']
|
||||
del kwargs['fakeroot']
|
||||
else:
|
||||
fakeroot = None
|
||||
if kwargs:
|
||||
raise TypeError("Unrecognized keyword parameters")
|
||||
|
||||
script = _shell.native(script)
|
||||
argv = [_sys.executable, script] + list(args)
|
||||
if fakeroot:
|
||||
argv.insert(0, fakeroot)
|
||||
return not _shell.spawn(*argv)
|
253
_setup/py3/ext.py
Normal file
253
_setup/py3/ext.py
Normal file
@ -0,0 +1,253 @@
|
||||
# -*- coding: ascii -*-
|
||||
#
|
||||
# Copyright 2007, 2008, 2009, 2010, 2011
|
||||
# Andr\xe9 Malo or his licensors, as applicable
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
"""
|
||||
===================
|
||||
C extension tools
|
||||
===================
|
||||
|
||||
C extension tools.
|
||||
"""
|
||||
__author__ = "Andr\xe9 Malo"
|
||||
__docformat__ = "restructuredtext en"
|
||||
__test__ = False
|
||||
|
||||
from distutils import core as _core
|
||||
from distutils import errors as _distutils_errors
|
||||
from distutils import log
|
||||
import os as _os
|
||||
import posixpath as _posixpath
|
||||
import shutil as _shutil
|
||||
import tempfile as _tempfile
|
||||
|
||||
from _setup import commands as _commands
|
||||
|
||||
def _install_finalizer(installer):
|
||||
if installer.without_c_extensions:
|
||||
installer.distribution.ext_modules = []
|
||||
|
||||
def _build_finalizer(builder):
|
||||
if builder.without_c_extensions:
|
||||
builder.extensions = []
|
||||
|
||||
|
||||
class Extension(_core.Extension):
|
||||
"""
|
||||
Extension with prerequisite check interface
|
||||
|
||||
If your check is cacheable (during the setup run), override
|
||||
`cached_check_prerequisites`, `check_prerequisites` otherwise.
|
||||
|
||||
:IVariables:
|
||||
`cached_check` : ``bool``
|
||||
The cached check result
|
||||
"""
|
||||
cached_check = None
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
""" Initialization """
|
||||
if 'depends' in kwargs:
|
||||
self.depends = kwargs['depends'] or []
|
||||
else:
|
||||
self.depends = []
|
||||
_core.Extension.__init__(self, *args, **kwargs)
|
||||
|
||||
# add include path
|
||||
included = _posixpath.join('_setup', 'include')
|
||||
if included not in self.include_dirs:
|
||||
self.include_dirs.append(included)
|
||||
|
||||
# add cext.h to the dependencies
|
||||
cext_h = _posixpath.join(included, 'cext.h')
|
||||
if cext_h not in self.depends:
|
||||
self.depends.append(cext_h)
|
||||
|
||||
_commands.add_option('install_lib', 'without-c-extensions',
|
||||
help_text='Don\'t install C extensions',
|
||||
inherit='install',
|
||||
)
|
||||
_commands.add_finalizer('install_lib', 'c-extensions',
|
||||
_install_finalizer
|
||||
)
|
||||
_commands.add_option('build_ext', 'without-c-extensions',
|
||||
help_text='Don\'t build C extensions',
|
||||
inherit=('build', 'install_lib'),
|
||||
)
|
||||
_commands.add_finalizer('build_ext', 'c-extensions', _build_finalizer)
|
||||
|
||||
def check_prerequisites(self, build):
|
||||
"""
|
||||
Check prerequisites
|
||||
|
||||
The check should cover all dependencies needed for the extension to
|
||||
be built and run. The method can do the following:
|
||||
|
||||
- return a false value: the extension will be built
|
||||
- return a true value: the extension will be skipped. This is useful
|
||||
for optional extensions
|
||||
- raise an exception. This is useful for mandatory extensions
|
||||
|
||||
If the check result is cacheable (during the setup run), override
|
||||
`cached_check_prerequisites` instead.
|
||||
|
||||
:Parameters:
|
||||
`build` : `BuildExt`
|
||||
The extension builder
|
||||
|
||||
:Return: Skip the extension?
|
||||
:Rtype: ``bool``
|
||||
"""
|
||||
if self.cached_check is None:
|
||||
log.debug("PREREQ check for %s" % self.name)
|
||||
self.cached_check = self.cached_check_prerequisites(build)
|
||||
else:
|
||||
log.debug("PREREQ check for %s (cached)" % self.name)
|
||||
return self.cached_check
|
||||
|
||||
def cached_check_prerequisites(self, build):
|
||||
"""
|
||||
Check prerequisites
|
||||
|
||||
The check should cover all dependencies needed for the extension to
|
||||
be built and run. The method can do the following:
|
||||
|
||||
- return a false value: the extension will be built
|
||||
- return a true value: the extension will be skipped. This is useful
|
||||
for optional extensions
|
||||
- raise an exception. This is useful for mandatory extensions
|
||||
|
||||
If the check result is *not* cacheable (during the setup run),
|
||||
override `check_prerequisites` instead.
|
||||
|
||||
:Parameters:
|
||||
`build` : `BuildExt`
|
||||
The extension builder
|
||||
|
||||
:Return: Skip the extension?
|
||||
:Rtype: ``bool``
|
||||
"""
|
||||
# pylint: disable = W0613
|
||||
log.debug("Nothing to check for %s!" % self.name)
|
||||
return False
|
||||
|
||||
|
||||
class ConfTest(object):
|
||||
"""
|
||||
Single conftest abstraction
|
||||
|
||||
:IVariables:
|
||||
`_tempdir` : ``str``
|
||||
The tempdir created for this test
|
||||
|
||||
`src` : ``str``
|
||||
Name of the source file
|
||||
|
||||
`target` : ``str``
|
||||
Target filename
|
||||
|
||||
`compiler` : ``CCompiler``
|
||||
compiler instance
|
||||
|
||||
`obj` : ``list``
|
||||
List of object filenames (``[str, ...]``)
|
||||
"""
|
||||
_tempdir = None
|
||||
|
||||
def __init__(self, build, source):
|
||||
"""
|
||||
Initialization
|
||||
|
||||
:Parameters:
|
||||
`build` : ``distuils.command.build_ext.build_ext``
|
||||
builder instance
|
||||
|
||||
`source` : ``str``
|
||||
Source of the file to compile
|
||||
"""
|
||||
self._tempdir = tempdir = _tempfile.mkdtemp()
|
||||
src = _os.path.join(tempdir, 'conftest.c')
|
||||
fp = open(src, 'w')
|
||||
try:
|
||||
fp.write(source)
|
||||
finally:
|
||||
fp.close()
|
||||
self.src = src
|
||||
self.compiler = compiler = build.compiler
|
||||
self.target = _os.path.join(tempdir, 'conftest')
|
||||
self.obj = compiler.object_filenames([src], output_dir=tempdir)
|
||||
|
||||
def __del__(self):
|
||||
""" Destruction """
|
||||
self.destroy()
|
||||
|
||||
def destroy(self):
|
||||
""" Destroy the conftest leftovers on disk """
|
||||
tempdir, self._tempdir = self._tempdir, None
|
||||
if tempdir is not None:
|
||||
_shutil.rmtree(tempdir)
|
||||
|
||||
def compile(self, **kwargs):
|
||||
"""
|
||||
Compile the conftest
|
||||
|
||||
:Parameters:
|
||||
`kwargs` : ``dict``
|
||||
Optional keyword parameters for the compiler call
|
||||
|
||||
:Return: Was the compilation successful?
|
||||
:Rtype: ``bool``
|
||||
"""
|
||||
kwargs['output_dir'] = self._tempdir
|
||||
try:
|
||||
self.compiler.compile([self.src], **kwargs)
|
||||
except _distutils_errors.CompileError:
|
||||
return False
|
||||
return True
|
||||
|
||||
def link(self, **kwargs):
|
||||
r"""
|
||||
Link the conftest
|
||||
|
||||
Before you can link the conftest objects they need to be `compile`\d.
|
||||
|
||||
:Parameters:
|
||||
`kwargs` : ``dict``
|
||||
Optional keyword parameters for the linker call
|
||||
|
||||
:Return: Was the linking successful?
|
||||
:Rtype: ``bool``
|
||||
"""
|
||||
try:
|
||||
self.compiler.link_executable(self.obj, self.target, **kwargs)
|
||||
except _distutils_errors.LinkError:
|
||||
return False
|
||||
return True
|
||||
|
||||
def pipe(self, mode="r"):
|
||||
r"""
|
||||
Execute the conftest binary and connect to it using a pipe
|
||||
|
||||
Before you can pipe to or from the conftest binary it needs to
|
||||
be `link`\ed.
|
||||
|
||||
:Parameters:
|
||||
`mode` : ``str``
|
||||
Pipe mode - r/w
|
||||
|
||||
:Return: The open pipe
|
||||
:Rtype: ``file``
|
||||
"""
|
||||
return _os.popen(self.compiler.executable_filename(self.target), mode)
|
28
_setup/py3/make/__init__.py
Normal file
28
_setup/py3/make/__init__.py
Normal file
@ -0,0 +1,28 @@
|
||||
# -*- coding: ascii -*-
|
||||
#
|
||||
# Copyright 2010, 2011
|
||||
# Andr\xe9 Malo or his licensors, as applicable
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
"""
|
||||
=====================
|
||||
Package _setup.make
|
||||
=====================
|
||||
|
||||
Make tools, not distributed.
|
||||
"""
|
||||
__author__ = "Andr\xe9 Malo"
|
||||
__docformat__ = "restructuredtext en"
|
||||
|
||||
# pylint: disable = W0611
|
||||
from _setup.make._make import main, fail, warn, fatal, Target
|
338
_setup/py3/make/_make.py
Normal file
338
_setup/py3/make/_make.py
Normal file
@ -0,0 +1,338 @@
|
||||
# -*- coding: ascii -*-
|
||||
#
|
||||
# Copyright 2007, 2008, 2009, 2010, 2011
|
||||
# Andr\xe9 Malo or his licensors, as applicable
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
"""
|
||||
==================
|
||||
Simple make base
|
||||
==================
|
||||
|
||||
Simple make base.
|
||||
"""
|
||||
__author__ = "Andr\xe9 Malo"
|
||||
__docformat__ = "restructuredtext en"
|
||||
|
||||
import sys as _sys
|
||||
|
||||
from _setup import term as _term
|
||||
|
||||
|
||||
class Failure(SystemExit):
|
||||
""" Failure exception """
|
||||
|
||||
|
||||
def fail(reason):
|
||||
""" Fail for a reason """
|
||||
raise Failure(reason)
|
||||
|
||||
|
||||
def warn(message, name=None):
|
||||
""" Warn """
|
||||
_term.red("%(NAME)sWarning: %(msg)s",
|
||||
NAME=name and "%s:" % name or '', msg=message
|
||||
)
|
||||
|
||||
|
||||
def fatal(reason):
|
||||
""" Fatal error, immediate stop """
|
||||
print(reason, file=_sys.stderr)
|
||||
_sys.exit(1)
|
||||
|
||||
|
||||
class Target(object):
|
||||
""" Target base class """
|
||||
NAME = None
|
||||
DEPS = None
|
||||
HIDDEN = False
|
||||
|
||||
ERROR = None
|
||||
|
||||
def __init__(self, runner):
|
||||
""" Base __init__ """
|
||||
self.runner = runner
|
||||
self.init()
|
||||
|
||||
def init(self):
|
||||
""" Default init hook """
|
||||
pass
|
||||
|
||||
def run(self):
|
||||
""" Default run hook """
|
||||
pass
|
||||
|
||||
def clean(self, scm=True, dist=False):
|
||||
""" Default clean hook """
|
||||
pass
|
||||
|
||||
|
||||
class _Runner(object):
|
||||
""" Runner """
|
||||
|
||||
def __init__(self, *targetscollection):
|
||||
""" Initialization """
|
||||
tdict = {}
|
||||
if not targetscollection:
|
||||
import __main__
|
||||
targetscollection = [__main__]
|
||||
|
||||
from _setup.make import default_targets
|
||||
if default_targets not in targetscollection:
|
||||
targetscollection.append(default_targets)
|
||||
|
||||
for targets in targetscollection:
|
||||
for value in list(vars(targets).values()):
|
||||
if isinstance(value, type) and issubclass(value, Target) and \
|
||||
value.NAME is not None:
|
||||
if value.NAME in tdict:
|
||||
if issubclass(value, tdict[value.NAME]):
|
||||
pass # override base target
|
||||
elif issubclass(tdict[value.NAME], value):
|
||||
continue # found base later. ignore
|
||||
else:
|
||||
warn('Ambiguous target name', value.NAME)
|
||||
continue
|
||||
tdict[value.NAME] = value
|
||||
self._tdict = tdict
|
||||
self._itdict = {}
|
||||
|
||||
def print_help(self):
|
||||
""" Print make help """
|
||||
import textwrap as _textwrap
|
||||
|
||||
targets = self.targetinfo()
|
||||
keys = []
|
||||
for key, info in list(targets.items()):
|
||||
if not info['hide']:
|
||||
keys.append(key)
|
||||
keys.sort()
|
||||
length = max(list(map(len, keys)))
|
||||
info = []
|
||||
for key in keys:
|
||||
info.append("%s%s" % (
|
||||
(key + " " * length)[:length + 2],
|
||||
_textwrap.fill(
|
||||
targets[key]['desc'].strip(),
|
||||
subsequent_indent=" " * (length + 2)
|
||||
),
|
||||
))
|
||||
print("Available targets:\n\n" + "\n".join(info))
|
||||
|
||||
def targetinfo(self):
|
||||
""" Extract target information """
|
||||
result = {}
|
||||
for name, cls in list(self._tdict.items()):
|
||||
result[name] = {
|
||||
'desc': cls.__doc__ or "no description",
|
||||
'hide': cls.HIDDEN,
|
||||
'deps': cls.DEPS or (),
|
||||
}
|
||||
return result
|
||||
|
||||
def _topleveltargets(self):
|
||||
""" Find all top level targets """
|
||||
rev = {} # key is a dep of [values]
|
||||
all_ = self.targetinfo()
|
||||
for target, info in list(all_.items()):
|
||||
for dep in info['deps']:
|
||||
if dep not in all_:
|
||||
fatal("Unknown target '%s' (dep of %s) -> exit" % (
|
||||
dep, target
|
||||
))
|
||||
rev.setdefault(dep, []).append(target)
|
||||
return [target for target, info in list(rev.items()) if not info]
|
||||
|
||||
def _run(self, target, seen=None):
|
||||
""" Run a target """
|
||||
if target.DEPS:
|
||||
self(*target.DEPS, **{'seen': seen})
|
||||
|
||||
if not target.HIDDEN:
|
||||
_term.yellow(">>> %(name)s", name=target.NAME)
|
||||
|
||||
try:
|
||||
result = target.run()
|
||||
except KeyboardInterrupt:
|
||||
result, target.ERROR = False, "^C -> exit"
|
||||
except Failure as e:
|
||||
result, target.ERROR = False, "%s: %s" % (target.NAME, e)
|
||||
except (SystemExit, MemoryError):
|
||||
raise
|
||||
except:
|
||||
import traceback
|
||||
target.ERROR = "%s errored:\n%s" % (target.NAME, ''.join(
|
||||
traceback.format_exception(*_sys.exc_info())
|
||||
))
|
||||
result = False
|
||||
else:
|
||||
if result is None:
|
||||
result = True
|
||||
return result
|
||||
|
||||
def _clean(self, target, scm, dist, seen=None):
|
||||
""" Run a target """
|
||||
if target.DEPS:
|
||||
self.run_clean(
|
||||
*target.DEPS, **{'scm': scm, 'dist': dist, 'seen': seen}
|
||||
)
|
||||
|
||||
try:
|
||||
result = target.clean(scm, dist)
|
||||
except KeyboardInterrupt:
|
||||
result, target.ERROR = False, "^C -> exit"
|
||||
except Failure as e:
|
||||
result, target.ERROR = False, "%s: %s" % (target.NAME, e)
|
||||
except (SystemExit, MemoryError):
|
||||
raise
|
||||
except:
|
||||
import traceback
|
||||
target.ERROR = "%s errored:\n%s" % (target.NAME, ''.join(
|
||||
traceback.format_exception(*_sys.exc_info())
|
||||
))
|
||||
result = False
|
||||
else:
|
||||
if result is None:
|
||||
result = True
|
||||
return result
|
||||
|
||||
def _make_init(self, seen):
|
||||
""" Make init mapper """
|
||||
def init(target):
|
||||
""" Return initialized target """
|
||||
if target not in seen:
|
||||
try:
|
||||
seen[target] = self._tdict[target](self)
|
||||
except KeyError:
|
||||
fatal("Unknown target '%s' -> exit" % target)
|
||||
else:
|
||||
seen[target] = None
|
||||
return seen[target]
|
||||
return init
|
||||
|
||||
def run_clean(self, *targets, **kwargs):
|
||||
""" Run targets """
|
||||
def pop(name, default=None):
|
||||
""" Pop """
|
||||
if name in kwargs:
|
||||
value = kwargs[name]
|
||||
del kwargs[name]
|
||||
if value is None:
|
||||
return default
|
||||
return value
|
||||
else:
|
||||
return default
|
||||
seen = pop('seen', {})
|
||||
scm = pop('scm', True)
|
||||
dist = pop('dist', False)
|
||||
if kwargs:
|
||||
raise TypeError('Unknown keyword parameters')
|
||||
|
||||
if not targets:
|
||||
top_targets = self._topleveltargets()
|
||||
targets = self.targetinfo()
|
||||
for item in top_targets:
|
||||
del targets[item]
|
||||
targets = list(targets.keys())
|
||||
targets.sort()
|
||||
top_targets.sort()
|
||||
targets = top_targets + targets
|
||||
|
||||
init = self._make_init(seen)
|
||||
for name in targets:
|
||||
target = init(name)
|
||||
if target is not None:
|
||||
if not self._clean(target, scm=scm, dist=dist, seen=seen):
|
||||
msg = target.ERROR
|
||||
if msg is None:
|
||||
msg = "Clean target %s returned error -> exit" % name
|
||||
fatal(msg)
|
||||
|
||||
def __call__(self, *targets, **kwargs):
|
||||
""" Run targets """
|
||||
if 'seen' in kwargs:
|
||||
seen = kwargs['seen']
|
||||
del kwargs['seen']
|
||||
else:
|
||||
seen = None
|
||||
if seen is None:
|
||||
seen = self._itdict
|
||||
if kwargs:
|
||||
raise TypeError('Unknown keyword parameters')
|
||||
|
||||
init = self._make_init(seen)
|
||||
for name in targets:
|
||||
target = init(name)
|
||||
if target is not None:
|
||||
if not self._run(target, seen):
|
||||
msg = target.ERROR
|
||||
if msg is None:
|
||||
msg = "Target %s returned error -> exit" % name
|
||||
fatal(msg)
|
||||
|
||||
|
||||
def main(*args, **kwargs):
|
||||
"""
|
||||
main(argv=None, *args, name=None)
|
||||
|
||||
Main start point. This function parses the command line and executes the
|
||||
targets given through `argv`. If there are no targets given, a help output
|
||||
is generated.
|
||||
|
||||
:Parameters:
|
||||
`argv` : sequence
|
||||
Command line arguments. If omitted or ``None``, they are picked from
|
||||
``sys.argv``.
|
||||
|
||||
`args` : ``tuple``
|
||||
The list of modules with targets. If omitted, ``__main__``
|
||||
is imported and treated as target module. Additionally the mechanism
|
||||
always adds the `_setup.make` module (this one) to the list in order
|
||||
to grab some default targets.
|
||||
|
||||
`name` : ``str``
|
||||
Name of the executing module. If omitted or ``None``, ``'__main__'``
|
||||
is assumed. If the final name is not ``'__main__'``, the function
|
||||
returns immediately.
|
||||
"""
|
||||
try:
|
||||
name = kwargs['name']
|
||||
except KeyError:
|
||||
name = '__main__'
|
||||
else:
|
||||
del kwargs['name']
|
||||
if name is None:
|
||||
name = '__main__'
|
||||
|
||||
try:
|
||||
argv = kwargs['argv']
|
||||
except KeyError:
|
||||
if not args:
|
||||
args = (None,)
|
||||
else:
|
||||
del kwargs['argv']
|
||||
args = (argv,) + args
|
||||
|
||||
if kwargs:
|
||||
raise TypeError("Unrecognized keyword arguments for main()")
|
||||
|
||||
if name == '__main__':
|
||||
argv, args = args[0], args[1:]
|
||||
if argv is None:
|
||||
argv = _sys.argv[1:]
|
||||
|
||||
runner = _Runner(*args)
|
||||
if argv:
|
||||
runner(*argv)
|
||||
else:
|
||||
runner.print_help()
|
110
_setup/py3/make/default_targets.py
Normal file
110
_setup/py3/make/default_targets.py
Normal file
@ -0,0 +1,110 @@
|
||||
# -*- coding: ascii -*-
|
||||
#
|
||||
# Copyright 2007, 2008, 2009, 2010, 2011
|
||||
# Andr\xe9 Malo or his licensors, as applicable
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
"""
|
||||
==================
|
||||
Simple make base
|
||||
==================
|
||||
|
||||
Simple make base.
|
||||
"""
|
||||
__author__ = "Andr\xe9 Malo"
|
||||
__docformat__ = "restructuredtext en"
|
||||
|
||||
import os as _os
|
||||
import sys as _sys
|
||||
|
||||
from _setup import make as _make
|
||||
from _setup import shell as _shell
|
||||
|
||||
|
||||
class MakefileTarget(_make.Target):
|
||||
""" Create a make file """
|
||||
NAME = 'makefile'
|
||||
|
||||
def run(self):
|
||||
def escape(value):
|
||||
""" Escape for make and shell """
|
||||
return '"%s"' % value.replace(
|
||||
'\\', '\\\\').replace(
|
||||
'"', '\\"').replace(
|
||||
'$', '\\$$')
|
||||
def decorate(line, prefix='# ', width=78, char='~', padding=' '):
|
||||
""" Decorate a line """
|
||||
line = line.center(width - len(prefix))
|
||||
return '%s%s%s%s%s%s' % (
|
||||
prefix,
|
||||
char * (len(line) - len(line.lstrip()) - len(padding)),
|
||||
padding,
|
||||
line.strip(),
|
||||
padding,
|
||||
char * (len(line) - len(line.rstrip()) - len(padding)),
|
||||
)
|
||||
|
||||
python = escape(_sys.executable)
|
||||
script = escape(_sys.argv[0])
|
||||
targets = self.runner.targetinfo()
|
||||
names = []
|
||||
for name, info in list(targets.items()):
|
||||
if not info['hide']:
|
||||
names.append(name)
|
||||
names.sort()
|
||||
|
||||
fp = open(_shell.native('Makefile'), 'w')
|
||||
print(decorate("Generated Makefile, DO NOT EDIT"), file=fp)
|
||||
print(decorate("python %s %s" % (
|
||||
_os.path.basename(script), self.NAME
|
||||
)), file=fp)
|
||||
print(file=fp)
|
||||
print("_default_:", file=fp)
|
||||
print("\t@%s %s" % (python, script), file=fp)
|
||||
for name in names:
|
||||
print("\n", file=fp)
|
||||
print("# %s" % \
|
||||
targets[name]['desc'].splitlines()[0].strip(), file=fp)
|
||||
print("%s:" % name, file=fp)
|
||||
print("\t@%s %s %s" % (python, script, escape(name)), file=fp)
|
||||
print(file=fp)
|
||||
extension = self.extend(names)
|
||||
if extension is not None:
|
||||
print(extension, file=fp)
|
||||
print(file=fp)
|
||||
print(".PHONY: _default_ %s\n\n" % ' '.join(names), file=fp)
|
||||
fp.close()
|
||||
|
||||
def extend(self, names):
|
||||
pass
|
||||
|
||||
|
||||
class CleanTarget(_make.Target):
|
||||
""" Clean the mess """
|
||||
NAME = 'clean'
|
||||
_scm, _dist = True, False
|
||||
|
||||
def run(self):
|
||||
self.runner.run_clean(scm=self._scm, dist=self._dist)
|
||||
|
||||
|
||||
class DistCleanTarget(CleanTarget):
|
||||
""" Clean as freshly unpacked dist package """
|
||||
NAME = 'distclean'
|
||||
_scm, _dist = False, True
|
||||
|
||||
|
||||
class ExtraCleanTarget(CleanTarget):
|
||||
""" Clean everything """
|
||||
NAME = 'extraclean'
|
||||
_scm, _dist = True, True
|
326
_setup/py3/make/targets.py
Normal file
326
_setup/py3/make/targets.py
Normal file
@ -0,0 +1,326 @@
|
||||
# -*- coding: ascii -*-
|
||||
#
|
||||
# Copyright 2007 - 2013
|
||||
# Andr\xe9 Malo or his licensors, as applicable
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
"""
|
||||
==================
|
||||
Standard targets
|
||||
==================
|
||||
|
||||
Standard targets.
|
||||
"""
|
||||
__author__ = "Andr\xe9 Malo"
|
||||
__docformat__ = "restructuredtext en"
|
||||
|
||||
import os as _os
|
||||
import sys as _sys
|
||||
|
||||
from _setup import dist as _dist
|
||||
from _setup import make as _make
|
||||
from _setup import shell as _shell
|
||||
from _setup import term as _term
|
||||
|
||||
|
||||
class Distribution(_make.Target):
|
||||
""" Build a distribution """
|
||||
NAME = "dist"
|
||||
DEPS = ["MANIFEST"]
|
||||
|
||||
_dist, _ebuilds, _changes = None, None, None
|
||||
|
||||
def init(self):
|
||||
raise NotImplementedError()
|
||||
|
||||
def run(self):
|
||||
exts = self.dist_pkg()
|
||||
digests = self.digest_files(exts)
|
||||
self.sign_digests(digests)
|
||||
self.copy_ebuilds()
|
||||
self.copy_changes()
|
||||
|
||||
def dist_pkg(self):
|
||||
_term.green("Building package...")
|
||||
_dist.run_setup("sdist", "--formats", "tar,zip",
|
||||
fakeroot=_shell.frompath('fakeroot')
|
||||
)
|
||||
exts = ['.zip']
|
||||
for name in _shell.files(self._dist, '*.tar', False):
|
||||
exts.extend(self.compress(name))
|
||||
_shell.rm(name)
|
||||
return exts
|
||||
|
||||
def compress(self, filename):
|
||||
""" Compress file """
|
||||
ext = _os.path.splitext(filename)[1]
|
||||
exts = []
|
||||
exts.append('.'.join((ext, self.compress_gzip(filename))))
|
||||
exts.append('.'.join((ext, self.compress_bzip2(filename))))
|
||||
exts.append('.'.join((ext, self.compress_xz(filename))))
|
||||
return exts
|
||||
|
||||
def compress_xz(self, filename):
|
||||
outfilename = filename + '.xz'
|
||||
self.compress_external(filename, outfilename, 'xz', '-c9')
|
||||
return 'xz'
|
||||
|
||||
def compress_bzip2(self, filename):
|
||||
outfilename = filename + '.bz2'
|
||||
try:
|
||||
import bz2 as _bz2
|
||||
except ImportError:
|
||||
self.compress_external(filename, outfilename, 'bzip2', '-c9')
|
||||
else:
|
||||
outfile = _bz2.BZ2File(outfilename, 'w')
|
||||
self.compress_internal(filename, outfile, outfilename)
|
||||
return 'bz2'
|
||||
|
||||
def compress_gzip(self, filename):
|
||||
outfilename = filename + '.gz'
|
||||
try:
|
||||
import gzip as _gzip
|
||||
except ImportError:
|
||||
self.compress_external(filename, outfilename, 'gzip', '-c9')
|
||||
else:
|
||||
outfile = _gzip.GzipFile(filename, 'wb',
|
||||
fileobj=open(outfilename, 'wb')
|
||||
)
|
||||
self.compress_internal(filename, outfile, outfilename)
|
||||
return 'gz'
|
||||
|
||||
def compress_external(self, infile, outfile, *argv):
|
||||
argv = list(argv)
|
||||
argv[0] = _shell.frompath(argv[0])
|
||||
if argv[0] is not None:
|
||||
return not _shell.spawn(*argv, **{
|
||||
'filepipe': True, 'stdin': infile, 'stdout': outfile,
|
||||
})
|
||||
return None
|
||||
|
||||
def compress_internal(self, filename, outfile, outfilename):
|
||||
infile = open(filename, 'rb')
|
||||
try:
|
||||
try:
|
||||
while 1:
|
||||
chunk = infile.read(8192)
|
||||
if not chunk:
|
||||
break
|
||||
outfile.write(chunk)
|
||||
outfile.close()
|
||||
except:
|
||||
e = _sys.exc_info()
|
||||
try:
|
||||
_shell.rm(outfilename)
|
||||
finally:
|
||||
try:
|
||||
raise e[0](e[1]).with_traceback(e[2])
|
||||
finally:
|
||||
del e
|
||||
finally:
|
||||
infile.close()
|
||||
|
||||
def digest_files(self, exts):
|
||||
""" digest files """
|
||||
digests = {}
|
||||
digestnames = {}
|
||||
for ext in exts:
|
||||
for name in _shell.files(self._dist, '*' + ext, False):
|
||||
basename = _os.path.basename(name)
|
||||
if basename not in digests:
|
||||
digests[basename] = []
|
||||
digests[basename].extend(self.digest(name))
|
||||
digestname = basename[:-len(ext)]
|
||||
if digestname not in digestnames:
|
||||
digestnames[digestname] = []
|
||||
digestnames[digestname].append(basename)
|
||||
|
||||
result = []
|
||||
for name, basenames in digestnames.items():
|
||||
result.append(_os.path.join(self._dist, name + '.digests'))
|
||||
fp = open(result[-1], 'wb')
|
||||
try:
|
||||
fp.write(
|
||||
b'\n# The file may contain MD5, SHA1 and SHA256 digests\n'
|
||||
)
|
||||
fp.write(b'# Check archive integrity with, e.g. md5sum -c\n')
|
||||
fp.write(b'# Check digest file integrity with PGP\n\n')
|
||||
basenames.sort()
|
||||
for basename in basenames:
|
||||
for digest in digests[basename]:
|
||||
fp.write((
|
||||
"%s *%s\n" % (digest, basename)).encode('utf-8')
|
||||
)
|
||||
finally:
|
||||
fp.close()
|
||||
return result
|
||||
|
||||
def digest(self, filename):
|
||||
result = []
|
||||
for method in (self.md5, self.sha1, self.sha256):
|
||||
digest = method(filename)
|
||||
if digest is not None:
|
||||
result.append(digest)
|
||||
return result
|
||||
|
||||
def do_digest(self, hashfunc, name, filename):
|
||||
filename = _shell.native(filename)
|
||||
_term.green("%(digest)s-digesting %(name)s...",
|
||||
digest=name, name=_os.path.basename(filename))
|
||||
fp = open(filename, 'rb')
|
||||
sig = hashfunc()
|
||||
block = fp.read(8192)
|
||||
while block:
|
||||
sig.update(block)
|
||||
block = fp.read(8192)
|
||||
fp.close()
|
||||
return sig.hexdigest()
|
||||
|
||||
param = {'sig': sig.hexdigest(), 'file': _os.path.basename(filename)}
|
||||
fp = open("%s.%s" % (filename, name), "w")
|
||||
fp.write("%(sig)s *%(file)s\n" % param)
|
||||
fp.close()
|
||||
|
||||
return True
|
||||
|
||||
def md5(self, filename):
|
||||
try:
|
||||
from hashlib import md5
|
||||
except ImportError:
|
||||
try:
|
||||
from md5 import new as md5
|
||||
except ImportError:
|
||||
_make.warn("md5 not found -> skip md5 digests", self.NAME)
|
||||
return None
|
||||
return self.do_digest(md5, "md5", filename)
|
||||
|
||||
def sha1(self, filename):
|
||||
try:
|
||||
from hashlib import sha1
|
||||
except ImportError:
|
||||
try:
|
||||
from sha import new as sha1
|
||||
except ImportError:
|
||||
_make.warn("sha1 not found -> skip sha1 digests", self.NAME)
|
||||
return None
|
||||
return self.do_digest(sha1, "sha1", filename)
|
||||
|
||||
def sha256(self, filename):
|
||||
try:
|
||||
from hashlib import sha256
|
||||
except ImportError:
|
||||
try:
|
||||
from Crypto.Hash.SHA256 import new as sha256
|
||||
except ImportError:
|
||||
_make.warn(
|
||||
"sha256 not found -> skip sha256 digests", self.NAME
|
||||
)
|
||||
return None
|
||||
return self.do_digest(sha256, "sha256", filename)
|
||||
|
||||
def copy_ebuilds(self):
|
||||
if self._ebuilds is not None:
|
||||
for src in _shell.files(self._ebuilds, '*.ebuild'):
|
||||
_shell.cp(src, self._dist)
|
||||
|
||||
def copy_changes(self):
|
||||
if self._changes is not None:
|
||||
_shell.cp(self._changes, self._dist)
|
||||
|
||||
def sign_digests(self, digests):
|
||||
for digest in digests:
|
||||
self.sign(digest, detach=False)
|
||||
|
||||
def sign(self, filename, detach=True):
|
||||
filename = _shell.native(filename)
|
||||
try:
|
||||
from pyme import core, errors
|
||||
from pyme.constants.sig import mode
|
||||
except ImportError:
|
||||
return self.sign_external(filename, detach=detach)
|
||||
|
||||
_term.green("signing %(name)s...", name=_os.path.basename(filename))
|
||||
sigmode = [mode.CLEAR, mode.DETACH][bool(detach)]
|
||||
fp = core.Data(file=filename)
|
||||
sig = core.Data()
|
||||
try:
|
||||
c = core.Context()
|
||||
except errors.GPGMEError:
|
||||
return self.sign_external(filename, detach=detach)
|
||||
c.set_armor(1)
|
||||
try:
|
||||
c.op_sign(fp, sig, sigmode)
|
||||
except errors.GPGMEError as e:
|
||||
_make.fail(str(e))
|
||||
|
||||
sig.seek(0, 0)
|
||||
if detach:
|
||||
open("%s.asc" % filename, "w").write(sig.read())
|
||||
else:
|
||||
open(filename, "w").write(sig.read())
|
||||
|
||||
return True
|
||||
|
||||
def sign_external(self, filename, detach=True):
|
||||
""" Sign calling gpg """
|
||||
gpg = _shell.frompath('gpg')
|
||||
if gpg is None:
|
||||
_make.warn('GPG not found -> cannot sign')
|
||||
return False
|
||||
if detach:
|
||||
_shell.spawn(gpg,
|
||||
'--armor',
|
||||
'--output', filename + '.asc',
|
||||
'--detach-sign',
|
||||
'--',
|
||||
filename,
|
||||
)
|
||||
else:
|
||||
_shell.spawn(gpg,
|
||||
'--output', filename + '.signed',
|
||||
'--clearsign',
|
||||
'--',
|
||||
filename,
|
||||
)
|
||||
_os.rename(filename + '.signed', filename)
|
||||
return True
|
||||
|
||||
def clean(self, scm, dist):
|
||||
_term.green("Removing dist files...")
|
||||
_shell.rm_rf(self._dist)
|
||||
|
||||
|
||||
class Manifest(_make.Target):
|
||||
""" Create manifest """
|
||||
NAME = "MANIFEST"
|
||||
HIDDEN = True
|
||||
DEPS = ["doc"]
|
||||
|
||||
def run(self):
|
||||
_term.green("Creating %(name)s...", name=self.NAME)
|
||||
dest = _shell.native(self.NAME)
|
||||
dest = open(dest, 'w')
|
||||
for name in self.manifest_names():
|
||||
dest.write("%s\n" % name)
|
||||
dest.close()
|
||||
|
||||
def manifest_names(self):
|
||||
import setup
|
||||
for item in setup.manifest():
|
||||
yield item
|
||||
|
||||
def clean(self, scm, dist):
|
||||
""" Clean manifest """
|
||||
if scm:
|
||||
_term.green("Removing MANIFEST")
|
||||
_shell.rm(self.NAME)
|
420
_setup/py3/setup.py
Normal file
420
_setup/py3/setup.py
Normal file
@ -0,0 +1,420 @@
|
||||
# -*- coding: ascii -*-
|
||||
#
|
||||
# Copyright 2007 - 2013
|
||||
# Andr\xe9 Malo or his licensors, as applicable
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
"""
|
||||
===================
|
||||
Main setup runner
|
||||
===================
|
||||
|
||||
This module provides a wrapper around the distutils core setup.
|
||||
"""
|
||||
__author__ = "Andr\xe9 Malo"
|
||||
__docformat__ = "restructuredtext en"
|
||||
|
||||
import configparser as _config_parser
|
||||
from distutils import core as _core
|
||||
import os as _os
|
||||
import posixpath as _posixpath
|
||||
import sys as _sys
|
||||
|
||||
from _setup import commands as _commands
|
||||
from _setup import data as _data
|
||||
from _setup import ext as _ext
|
||||
from _setup import util as _util
|
||||
from _setup import shell as _shell
|
||||
|
||||
|
||||
def check_python_version(impl, version_min, version_max):
|
||||
""" Check python version """
|
||||
if impl == 'python':
|
||||
version_info = _sys.version_info
|
||||
elif impl == 'pypy':
|
||||
version_info = getattr(_sys, 'pypy_version_info', None)
|
||||
if not version_info:
|
||||
return
|
||||
elif impl == 'jython':
|
||||
if not 'java' in _sys.platform.lower():
|
||||
return
|
||||
version_info = _sys.version_info
|
||||
else:
|
||||
raise AssertionError("impl not in ('python', 'pypy', 'jython')")
|
||||
|
||||
pyversion = list(map(int, version_info[:3]))
|
||||
if version_min:
|
||||
min_required = list(
|
||||
map(int, '.'.join((version_min, '0.0.0')).split('.')[:3])
|
||||
)
|
||||
if pyversion < min_required:
|
||||
raise EnvironmentError("Need at least %s %s (vs. %s)" % (
|
||||
impl, version_min, '.'.join(map(str, pyversion))
|
||||
))
|
||||
if version_max:
|
||||
max_required = list(map(int, version_max.split('.')))
|
||||
max_required[-1] += 1
|
||||
if pyversion >= max_required:
|
||||
raise EnvironmentError("Need at max %s %s (vs. %s)" % (
|
||||
impl,
|
||||
version_max,
|
||||
'.'.join(map(str, pyversion))
|
||||
))
|
||||
|
||||
|
||||
def find_description(docs):
|
||||
"""
|
||||
Determine the package description from DESCRIPTION
|
||||
|
||||
:Parameters:
|
||||
`docs` : ``dict``
|
||||
Docs config section
|
||||
|
||||
:Return: Tuple of summary, description and license
|
||||
(``('summary', 'description', 'license')``)
|
||||
(all may be ``None``)
|
||||
:Rtype: ``tuple``
|
||||
"""
|
||||
summary = None
|
||||
filename = docs.get('meta.summary', 'SUMMARY').strip()
|
||||
if filename and _os.path.isfile(filename):
|
||||
fp = open(filename)
|
||||
try:
|
||||
try:
|
||||
summary = fp.read().strip().splitlines()[0].rstrip()
|
||||
except IndexError:
|
||||
summary = ''
|
||||
finally:
|
||||
fp.close()
|
||||
|
||||
description = None
|
||||
filename = docs.get('meta.description', 'DESCRIPTION').strip()
|
||||
if filename and _os.path.isfile(filename):
|
||||
fp = open(filename)
|
||||
try:
|
||||
description = fp.read().rstrip()
|
||||
finally:
|
||||
fp.close()
|
||||
|
||||
if summary is None and description:
|
||||
from docutils import core
|
||||
summary = core.publish_parts(
|
||||
source=description,
|
||||
source_path=filename,
|
||||
writer_name='html',
|
||||
)['title'].encode('utf-8')
|
||||
|
||||
return summary, description
|
||||
|
||||
|
||||
def find_classifiers(docs):
|
||||
"""
|
||||
Determine classifiers from CLASSIFIERS
|
||||
|
||||
:return: List of classifiers (``['classifier', ...]``)
|
||||
:rtype: ``list``
|
||||
"""
|
||||
filename = docs.get('meta.classifiers', 'CLASSIFIERS').strip()
|
||||
if filename and _os.path.isfile(filename):
|
||||
fp = open(filename)
|
||||
try:
|
||||
content = fp.read()
|
||||
finally:
|
||||
fp.close()
|
||||
content = [item.strip() for item in content.splitlines()]
|
||||
return [item for item in content if item and not item.startswith('#')]
|
||||
return []
|
||||
|
||||
|
||||
def find_provides(docs):
|
||||
"""
|
||||
Determine provides from PROVIDES
|
||||
|
||||
:return: List of provides (``['provides', ...]``)
|
||||
:rtype: ``list``
|
||||
"""
|
||||
filename = docs.get('meta.provides', 'PROVIDES').strip()
|
||||
if filename and _os.path.isfile(filename):
|
||||
fp = open(filename)
|
||||
try:
|
||||
content = fp.read()
|
||||
finally:
|
||||
fp.close()
|
||||
content = [item.strip() for item in content.splitlines()]
|
||||
return [item for item in content if item and not item.startswith('#')]
|
||||
return []
|
||||
|
||||
|
||||
def find_license(docs):
|
||||
"""
|
||||
Determine license from LICENSE
|
||||
|
||||
:return: License text
|
||||
:rtype: ``str``
|
||||
"""
|
||||
filename = docs.get('meta.license', 'LICENSE').strip()
|
||||
if filename and _os.path.isfile(filename):
|
||||
fp = open(filename)
|
||||
try:
|
||||
return fp.read().rstrip()
|
||||
finally:
|
||||
fp.close()
|
||||
return None
|
||||
|
||||
|
||||
def find_packages(manifest):
|
||||
""" Determine packages and subpackages """
|
||||
packages = {}
|
||||
collect = manifest.get('packages.collect', '').split()
|
||||
lib = manifest.get('packages.lib', '.')
|
||||
try:
|
||||
sep = _os.path.sep
|
||||
except AttributeError:
|
||||
sep = _os.path.join('1', '2')[1:-1]
|
||||
for root in collect:
|
||||
for dirpath, _, filenames in _shell.walk(_os.path.join(lib, root)):
|
||||
if dirpath.find('.svn') >= 0:
|
||||
continue
|
||||
if '__init__.py' in filenames:
|
||||
packages[
|
||||
_os.path.normpath(dirpath).replace(sep, '.')
|
||||
] = None
|
||||
packages = list(packages.keys())
|
||||
packages.sort()
|
||||
return packages
|
||||
|
||||
|
||||
def find_data(name, docs):
|
||||
""" Determine data files """
|
||||
result = []
|
||||
if docs.get('extra', '').strip():
|
||||
result.append(_data.Documentation(docs['extra'].split(),
|
||||
prefix='share/doc/%s' % name,
|
||||
))
|
||||
if docs.get('examples.dir', '').strip():
|
||||
tpl = ['recursive-include %s *' % docs['examples.dir']]
|
||||
if docs.get('examples.ignore', '').strip():
|
||||
tpl.extend(["global-exclude %s" % item
|
||||
for item in docs['examples.ignore'].split()
|
||||
])
|
||||
strip = int(docs.get('examples.strip', '') or 0)
|
||||
result.append(_data.Documentation.from_templates(*tpl, **{
|
||||
'strip': strip,
|
||||
'prefix': 'share/doc/%s' % name,
|
||||
'preserve': 1,
|
||||
}))
|
||||
if docs.get('userdoc.dir', '').strip():
|
||||
tpl = ['recursive-include %s *' % docs['userdoc.dir']]
|
||||
if docs.get('userdoc.ignore', '').strip():
|
||||
tpl.extend(["global-exclude %s" % item
|
||||
for item in docs['userdoc.ignore'].split()
|
||||
])
|
||||
strip = int(docs.get('userdoc.strip', '') or 0)
|
||||
result.append(_data.Documentation.from_templates(*tpl, **{
|
||||
'strip': strip,
|
||||
'prefix': 'share/doc/%s' % name,
|
||||
'preserve': 1,
|
||||
}))
|
||||
if docs.get('apidoc.dir', '').strip():
|
||||
tpl = ['recursive-include %s *' % docs['apidoc.dir']]
|
||||
if docs.get('apidoc.ignore', '').strip():
|
||||
tpl.extend(["global-exclude %s" % item
|
||||
for item in docs['apidoc.ignore'].split()
|
||||
])
|
||||
strip = int(docs.get('apidoc.strip', '') or 0)
|
||||
result.append(_data.Documentation.from_templates(*tpl, **{
|
||||
'strip': strip,
|
||||
'prefix': 'share/doc/%s' % name,
|
||||
'preserve': 1,
|
||||
}))
|
||||
if docs.get('man', '').strip():
|
||||
result.extend(_data.Manpages.dispatch(docs['man'].split()))
|
||||
return result
|
||||
|
||||
|
||||
def make_manifest(manifest, config, docs, kwargs):
|
||||
""" Create file list to pack up """
|
||||
# pylint: disable = R0912
|
||||
kwargs = kwargs.copy()
|
||||
kwargs['script_args'] = ['install']
|
||||
kwargs['packages'] = list(kwargs.get('packages') or ()) + [
|
||||
'_setup', '_setup.py2', '_setup.py3',
|
||||
] + list(manifest.get('packages.extra', '').split() or ())
|
||||
_core._setup_stop_after = "commandline"
|
||||
try:
|
||||
dist = _core.setup(**kwargs)
|
||||
finally:
|
||||
_core._setup_stop_after = None
|
||||
|
||||
result = ['MANIFEST', 'PKG-INFO', 'setup.py'] + list(config)
|
||||
# TODO: work with default values:
|
||||
for key in ('classifiers', 'description', 'summary', 'provides',
|
||||
'license'):
|
||||
filename = docs.get('meta.' + key, '').strip()
|
||||
if filename and _os.path.isfile(filename):
|
||||
result.append(filename)
|
||||
|
||||
cmd = dist.get_command_obj("build_py")
|
||||
cmd.ensure_finalized()
|
||||
#from pprint import pprint; pprint(("build_py", cmd.get_source_files()))
|
||||
for item in cmd.get_source_files():
|
||||
result.append(_posixpath.sep.join(
|
||||
_os.path.normpath(item).split(_os.path.sep)
|
||||
))
|
||||
|
||||
cmd = dist.get_command_obj("build_ext")
|
||||
cmd.ensure_finalized()
|
||||
#from pprint import pprint; pprint(("build_ext", cmd.get_source_files()))
|
||||
for item in cmd.get_source_files():
|
||||
result.append(_posixpath.sep.join(
|
||||
_os.path.normpath(item).split(_os.path.sep)
|
||||
))
|
||||
for ext in cmd.extensions:
|
||||
if ext.depends:
|
||||
result.extend([_posixpath.sep.join(
|
||||
_os.path.normpath(item).split(_os.path.sep)
|
||||
) for item in ext.depends])
|
||||
|
||||
cmd = dist.get_command_obj("build_clib")
|
||||
cmd.ensure_finalized()
|
||||
if cmd.libraries:
|
||||
#import pprint; pprint.pprint(("build_clib", cmd.get_source_files()))
|
||||
for item in cmd.get_source_files():
|
||||
result.append(_posixpath.sep.join(
|
||||
_os.path.normpath(item).split(_os.path.sep)
|
||||
))
|
||||
for lib in cmd.libraries:
|
||||
if lib[1].get('depends'):
|
||||
result.extend([_posixpath.sep.join(
|
||||
_os.path.normpath(item).split(_os.path.sep)
|
||||
) for item in lib[1]['depends']])
|
||||
|
||||
cmd = dist.get_command_obj("build_scripts")
|
||||
cmd.ensure_finalized()
|
||||
#import pprint; pprint.pprint(("build_scripts", cmd.get_source_files()))
|
||||
if cmd.get_source_files():
|
||||
for item in cmd.get_source_files():
|
||||
result.append(_posixpath.sep.join(
|
||||
_os.path.normpath(item).split(_os.path.sep)
|
||||
))
|
||||
|
||||
cmd = dist.get_command_obj("install_data")
|
||||
cmd.ensure_finalized()
|
||||
#from pprint import pprint; pprint(("install_data", cmd.get_inputs()))
|
||||
try:
|
||||
strings = str
|
||||
except NameError:
|
||||
strings = (str, str)
|
||||
|
||||
for item in cmd.get_inputs():
|
||||
if isinstance(item, strings):
|
||||
result.append(item)
|
||||
else:
|
||||
result.extend(item[1])
|
||||
|
||||
for item in manifest.get('dist', '').split():
|
||||
result.append(item)
|
||||
if _os.path.isdir(item):
|
||||
for filename in _shell.files(item):
|
||||
result.append(filename)
|
||||
|
||||
result = list(dict([(item, None) for item in result]).keys())
|
||||
result.sort()
|
||||
return result
|
||||
|
||||
|
||||
def run(config=('package.cfg',), ext=None, script_args=None, manifest_only=0):
|
||||
""" Main runner """
|
||||
if ext is None:
|
||||
ext = []
|
||||
|
||||
cfg = _util.SafeConfigParser()
|
||||
cfg.read(config)
|
||||
pkg = dict(cfg.items('package'))
|
||||
python_min = pkg.get('python.min') or None
|
||||
python_max = pkg.get('python.max') or None
|
||||
check_python_version('python', python_min, python_max)
|
||||
pypy_min = pkg.get('pypy.min') or None
|
||||
pypy_max = pkg.get('pypy.max') or None
|
||||
check_python_version('pypy', pypy_min, pypy_max)
|
||||
jython_min = pkg.get('jython.min') or None
|
||||
jython_max = pkg.get('jython.max') or None
|
||||
check_python_version('jython', jython_min, jython_max)
|
||||
|
||||
manifest = dict(cfg.items('manifest'))
|
||||
try:
|
||||
docs = dict(cfg.items('docs'))
|
||||
except _config_parser.NoSectionError:
|
||||
docs = {}
|
||||
|
||||
summary, description = find_description(docs)
|
||||
scripts = manifest.get('scripts', '').strip() or None
|
||||
if scripts:
|
||||
scripts = scripts.split()
|
||||
modules = manifest.get('modules', '').strip() or None
|
||||
if modules:
|
||||
modules = modules.split()
|
||||
keywords = docs.get('meta.keywords', '').strip() or None
|
||||
if keywords:
|
||||
keywords = keywords.split()
|
||||
revision = pkg.get('version.revision', '').strip()
|
||||
if revision:
|
||||
revision = "-r%s" % (revision,)
|
||||
|
||||
kwargs = {
|
||||
'name': pkg['name'],
|
||||
'version': "%s%s" % (
|
||||
pkg['version.number'],
|
||||
["", "-dev%s" % (revision,)][_util.humanbool(
|
||||
'version.dev', pkg.get('version.dev', 'false')
|
||||
)],
|
||||
),
|
||||
'provides': find_provides(docs),
|
||||
'description': summary,
|
||||
'long_description': description,
|
||||
'classifiers': find_classifiers(docs),
|
||||
'keywords': keywords,
|
||||
'author': pkg['author.name'],
|
||||
'author_email': pkg['author.email'],
|
||||
'maintainer': pkg.get('maintainer.name'),
|
||||
'maintainer_email': pkg.get('maintainer.email'),
|
||||
'url': pkg.get('url.homepage'),
|
||||
'download_url': pkg.get('url.download'),
|
||||
'license': find_license(docs),
|
||||
'package_dir': {'': manifest.get('packages.lib', '.')},
|
||||
'packages': find_packages(manifest),
|
||||
'py_modules': modules,
|
||||
'ext_modules': ext,
|
||||
'scripts': scripts,
|
||||
'script_args': script_args,
|
||||
'data_files': find_data(pkg['name'], docs),
|
||||
'cmdclass': {
|
||||
'build' : _commands.Build,
|
||||
'build_ext' : _commands.BuildExt,
|
||||
'install' : _commands.Install,
|
||||
'install_data': _commands.InstallData,
|
||||
'install_lib' : _commands.InstallLib,
|
||||
}
|
||||
}
|
||||
for key in ('provides',):
|
||||
if key not in _core.setup_keywords:
|
||||
del kwargs[key]
|
||||
|
||||
if manifest_only:
|
||||
return make_manifest(manifest, config, docs, kwargs)
|
||||
|
||||
# monkey-patch crappy manifest writer away.
|
||||
from distutils.command import sdist
|
||||
sdist.sdist.get_file_list = sdist.sdist.read_manifest
|
||||
|
||||
return _core.setup(**kwargs)
|
351
_setup/py3/shell.py
Normal file
351
_setup/py3/shell.py
Normal file
@ -0,0 +1,351 @@
|
||||
# -*- coding: ascii -*-
|
||||
#
|
||||
# Copyright 2007 - 2013
|
||||
# Andr\xe9 Malo or his licensors, as applicable
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
"""
|
||||
=================
|
||||
Shell utilities
|
||||
=================
|
||||
|
||||
Shell utilities.
|
||||
"""
|
||||
__author__ = "Andr\xe9 Malo"
|
||||
__docformat__ = "restructuredtext en"
|
||||
|
||||
import errno as _errno
|
||||
import fnmatch as _fnmatch
|
||||
import os as _os
|
||||
import shutil as _shutil
|
||||
import subprocess as _subprocess
|
||||
import sys as _sys
|
||||
import tempfile as _tempfile
|
||||
|
||||
cwd = _os.path.dirname(_os.path.abspath(_sys.argv[0]))
|
||||
|
||||
class ExitError(RuntimeError):
|
||||
""" Exit error """
|
||||
def __init__(self, code):
|
||||
RuntimeError.__init__(self, code)
|
||||
self.code = code
|
||||
self.signal = None
|
||||
|
||||
|
||||
class SignalError(ExitError):
|
||||
""" Signal error """
|
||||
def __init__(self, code, signal):
|
||||
ExitError.__init__(self, code)
|
||||
import signal as _signal
|
||||
self.signal = signal
|
||||
for key, val in vars(_signal).items():
|
||||
if key.startswith('SIG') and not key.startswith('SIG_'):
|
||||
if val == signal:
|
||||
self.signalstr = key[3:]
|
||||
break
|
||||
else:
|
||||
self.signalstr = '%04d' % signal
|
||||
|
||||
|
||||
def native(path):
|
||||
""" Convert slash path to native """
|
||||
path = _os.path.sep.join(path.split('/'))
|
||||
return _os.path.normpath(_os.path.join(cwd, path))
|
||||
|
||||
|
||||
def cp(src, dest):
|
||||
""" Copy src to dest """
|
||||
_shutil.copy2(native(src), native(dest))
|
||||
|
||||
|
||||
def cp_r(src, dest):
|
||||
""" Copy -r src to dest """
|
||||
_shutil.copytree(native(src), native(dest))
|
||||
|
||||
|
||||
def rm(dest):
|
||||
""" Remove a file """
|
||||
try:
|
||||
_os.unlink(native(dest))
|
||||
except OSError as e:
|
||||
if _errno.ENOENT != e.errno:
|
||||
raise
|
||||
|
||||
def rm_rf(dest):
|
||||
""" Remove a tree """
|
||||
dest = native(dest)
|
||||
if _os.path.exists(dest):
|
||||
for path in files(dest, '*'):
|
||||
_os.chmod(native(path), 0o644)
|
||||
_shutil.rmtree(dest)
|
||||
|
||||
|
||||
mkstemp = _tempfile.mkstemp
|
||||
|
||||
|
||||
def _pipespawn(argv, env):
|
||||
""" Pipe spawn """
|
||||
# pylint: disable = R0912
|
||||
import pickle as _pickle
|
||||
fd, name = mkstemp('.py')
|
||||
try:
|
||||
_os.write(fd, ((r"""
|
||||
import os
|
||||
import pickle
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
argv = pickle.loads(%(argv)s)
|
||||
env = pickle.loads(%(env)s)
|
||||
if 'X_JYTHON_WA_PATH' in env:
|
||||
env['PATH'] = env['X_JYTHON_WA_PATH']
|
||||
|
||||
p = subprocess.Popen(argv, env=env)
|
||||
result = p.wait()
|
||||
if result < 0:
|
||||
print("\n%%d 1" %% (-result))
|
||||
sys.exit(2)
|
||||
if result == 0:
|
||||
sys.exit(0)
|
||||
print("\n%%d" %% (result & 7,))
|
||||
sys.exit(3)
|
||||
""".strip() + "\n") % {
|
||||
'argv': repr(_pickle.dumps(argv)),
|
||||
'env': repr(_pickle.dumps(dict(env))),
|
||||
}).encode('utf-8'))
|
||||
fd, _ = None, _os.close(fd)
|
||||
if _sys.platform == 'win32':
|
||||
argv = []
|
||||
for arg in [_sys.executable, name]:
|
||||
if ' ' in arg or arg.startswith('"'):
|
||||
arg = '"%s"' % arg.replace('"', '\\"')
|
||||
argv.append(arg)
|
||||
argv = ' '.join(argv)
|
||||
shell = True
|
||||
close_fds = False
|
||||
else:
|
||||
argv = [_sys.executable, name]
|
||||
shell = False
|
||||
close_fds = True
|
||||
|
||||
res = 0
|
||||
if 'X_JYTHON_WA_PATH' in env:
|
||||
env['PATH'] = env['X_JYTHON_WA_PATH']
|
||||
|
||||
proc = _subprocess.Popen(argv,
|
||||
shell=shell,
|
||||
stdin=_subprocess.PIPE,
|
||||
stdout=_subprocess.PIPE,
|
||||
close_fds=close_fds,
|
||||
env=env,
|
||||
)
|
||||
try:
|
||||
proc.stdin.close()
|
||||
result = proc.stdout.read()
|
||||
finally:
|
||||
res = proc.wait()
|
||||
if res != 0:
|
||||
if res == 2:
|
||||
signal, code = list(map(int, result.splitlines()[-1].split()))
|
||||
raise SignalError(code, signal)
|
||||
elif res == 3:
|
||||
code = int(result.splitlines()[-1].strip())
|
||||
raise ExitError(code)
|
||||
raise ExitError(res)
|
||||
|
||||
return result.decode('latin-1')
|
||||
finally:
|
||||
try:
|
||||
if fd is not None:
|
||||
_os.close(fd)
|
||||
finally:
|
||||
_os.unlink(name)
|
||||
|
||||
|
||||
def _filepipespawn(infile, outfile, argv, env):
|
||||
""" File Pipe spawn """
|
||||
import pickle as _pickle
|
||||
fd, name = mkstemp('.py')
|
||||
try:
|
||||
_os.write(fd, (("""
|
||||
import os
|
||||
import pickle
|
||||
import sys
|
||||
|
||||
infile = pickle.loads(%(infile)s)
|
||||
outfile = pickle.loads(%(outfile)s)
|
||||
argv = pickle.loads(%(argv)s)
|
||||
env = pickle.loads(%(env)s)
|
||||
|
||||
if infile is not None:
|
||||
infile = open(infile, 'rb')
|
||||
os.dup2(infile.fileno(), 0)
|
||||
infile.close()
|
||||
if outfile is not None:
|
||||
outfile = open(outfile, 'wb')
|
||||
os.dup2(outfile.fileno(), 1)
|
||||
outfile.close()
|
||||
|
||||
pid = os.spawnve(os.P_NOWAIT, argv[0], argv, env)
|
||||
result = os.waitpid(pid, 0)[1]
|
||||
sys.exit(result & 7)
|
||||
""".strip() + "\n") % {
|
||||
'infile': repr(_pickle.dumps(_os.path.abspath(infile))),
|
||||
'outfile': repr(_pickle.dumps(_os.path.abspath(outfile))),
|
||||
'argv': repr(_pickle.dumps(argv)),
|
||||
'env': repr(_pickle.dumps(env)),
|
||||
}))
|
||||
fd, _ = None, _os.close(fd)
|
||||
if _sys.platform == 'win32':
|
||||
argv = []
|
||||
for arg in [_sys.executable, name]:
|
||||
if ' ' in arg or arg.startswith('"'):
|
||||
arg = '"%s"' % arg.replace('"', '\\"')
|
||||
argv.append(arg)
|
||||
argv = ' '.join(argv)
|
||||
close_fds = False
|
||||
shell = True
|
||||
else:
|
||||
argv = [_sys.executable, name]
|
||||
close_fds = True
|
||||
shell = False
|
||||
|
||||
p = _subprocess.Popen(
|
||||
argv, env=env, shell=shell, close_fds=close_fds
|
||||
)
|
||||
return p.wait()
|
||||
finally:
|
||||
try:
|
||||
if fd is not None:
|
||||
_os.close(fd)
|
||||
finally:
|
||||
_os.unlink(name)
|
||||
|
||||
|
||||
def spawn(*argv, **kwargs):
|
||||
""" Spawn a process """
|
||||
if _sys.platform == 'win32':
|
||||
newargv = []
|
||||
for arg in argv:
|
||||
if not arg or ' ' in arg or arg.startswith('"'):
|
||||
arg = '"%s"' % arg.replace('"', '\\"')
|
||||
newargv.append(arg)
|
||||
argv = newargv
|
||||
close_fds = False
|
||||
shell = True
|
||||
else:
|
||||
close_fds = True
|
||||
shell = False
|
||||
|
||||
env = kwargs.get('env')
|
||||
if env is None:
|
||||
env = dict(_os.environ)
|
||||
if 'X_JYTHON_WA_PATH' in env:
|
||||
env['PATH'] = env['X_JYTHON_WA_PATH']
|
||||
|
||||
echo = kwargs.get('echo')
|
||||
if echo:
|
||||
print(' '.join(argv))
|
||||
filepipe = kwargs.get('filepipe')
|
||||
if filepipe:
|
||||
return _filepipespawn(
|
||||
kwargs.get('stdin'), kwargs.get('stdout'), argv, env
|
||||
)
|
||||
pipe = kwargs.get('stdout')
|
||||
if pipe:
|
||||
return _pipespawn(argv, env)
|
||||
|
||||
p = _subprocess.Popen(argv, env=env, shell=shell, close_fds=close_fds)
|
||||
return p.wait()
|
||||
|
||||
|
||||
walk = _os.walk
|
||||
|
||||
|
||||
def files(base, wildcard='[!.]*', recursive=1, prune=('.svn', 'CVS')):
|
||||
""" Determine a filelist """
|
||||
for dirpath, dirnames, filenames in walk(native(base)):
|
||||
for item in prune:
|
||||
if item in dirnames:
|
||||
dirnames.remove(item)
|
||||
|
||||
filenames.sort()
|
||||
for name in _fnmatch.filter(filenames, wildcard):
|
||||
dest = _os.path.join(dirpath, name)
|
||||
if dest.startswith(cwd):
|
||||
dest = dest.replace(cwd, '', 1)
|
||||
aslist = []
|
||||
head, tail = _os.path.split(dest)
|
||||
while tail:
|
||||
aslist.append(tail)
|
||||
head, tail = _os.path.split(head)
|
||||
aslist.reverse()
|
||||
dest = '/'.join(aslist)
|
||||
yield dest
|
||||
|
||||
if not recursive:
|
||||
break
|
||||
dirnames.sort()
|
||||
|
||||
|
||||
def dirs(base, wildcard='[!.]*', recursive=1, prune=('.svn', 'CVS')):
|
||||
""" Determine a filelist """
|
||||
for dirpath, dirnames, filenames in walk(native(base)):
|
||||
for item in prune:
|
||||
if item in dirnames:
|
||||
dirnames.remove(item)
|
||||
|
||||
dirnames.sort()
|
||||
for name in _fnmatch.filter(dirnames, wildcard):
|
||||
dest = _os.path.join(dirpath, name)
|
||||
if dest.startswith(cwd):
|
||||
dest = dest.replace(cwd, '', 1)
|
||||
aslist = []
|
||||
head, tail = _os.path.split(dest)
|
||||
while tail:
|
||||
aslist.append(tail)
|
||||
head, tail = _os.path.split(head)
|
||||
aslist.reverse()
|
||||
dest = '/'.join(aslist)
|
||||
yield dest
|
||||
|
||||
if not recursive:
|
||||
break
|
||||
|
||||
|
||||
def frompath(executable):
|
||||
""" Find executable in PATH """
|
||||
# Based on distutils.spawn.find_executable.
|
||||
path = _os.environ.get('PATH', '')
|
||||
paths = [
|
||||
_os.path.expanduser(item)
|
||||
for item in path.split(_os.pathsep)
|
||||
]
|
||||
ext = _os.path.splitext(executable)[1]
|
||||
exts = ['']
|
||||
if _sys.platform == 'win32' or _os.name == 'os2':
|
||||
eext = ['.exe', '.bat', '.py']
|
||||
if ext not in eext:
|
||||
exts.extend(eext)
|
||||
|
||||
for ext in exts:
|
||||
if not _os.path.isfile(executable + ext):
|
||||
for path in paths:
|
||||
fname = _os.path.join(path, executable + ext)
|
||||
if _os.path.isfile(fname):
|
||||
# the file exists, we have a shot at spawn working
|
||||
return fname
|
||||
else:
|
||||
return executable + ext
|
||||
|
||||
return None
|
28
_setup/py3/term/__init__.py
Normal file
28
_setup/py3/term/__init__.py
Normal file
@ -0,0 +1,28 @@
|
||||
# -*- coding: ascii -*-
|
||||
#
|
||||
# Copyright 2010, 2011
|
||||
# Andr\xe9 Malo or his licensors, as applicable
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
"""
|
||||
=====================
|
||||
Package _setup.term
|
||||
=====================
|
||||
|
||||
Terminal tools, not distributed.
|
||||
"""
|
||||
__author__ = "Andr\xe9 Malo"
|
||||
__docformat__ = "restructuredtext en"
|
||||
|
||||
# pylint: disable = W0611
|
||||
from _setup.term._term import terminfo, write, green, red, yellow, announce
|
116
_setup/py3/term/_term.py
Normal file
116
_setup/py3/term/_term.py
Normal file
@ -0,0 +1,116 @@
|
||||
# -*- coding: ascii -*-
|
||||
#
|
||||
# Copyright 2007, 2008, 2009, 2010, 2011
|
||||
# Andr\xe9 Malo or his licensors, as applicable
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
"""
|
||||
=================
|
||||
Terminal writer
|
||||
=================
|
||||
"""
|
||||
__author__ = "Andr\xe9 Malo"
|
||||
__docformat__ = "restructuredtext en"
|
||||
|
||||
import sys as _sys
|
||||
|
||||
|
||||
class _INFO(dict):
|
||||
""" Terminal info dict """
|
||||
|
||||
def __init__(self):
|
||||
""" Initialization """
|
||||
dict.__init__(self, {
|
||||
'NORMAL': '',
|
||||
'BOLD': '',
|
||||
'ERASE': '\n',
|
||||
'RED': '',
|
||||
'YELLOW': '',
|
||||
'GREEN': '',
|
||||
})
|
||||
try:
|
||||
import curses as _curses
|
||||
except ImportError:
|
||||
# fixup if a submodule of curses failed.
|
||||
if 'curses' in _sys.modules:
|
||||
del _sys.modules['curses']
|
||||
else:
|
||||
try:
|
||||
_curses.setupterm()
|
||||
except (TypeError, _curses.error):
|
||||
pass
|
||||
else:
|
||||
def make_color(color):
|
||||
""" Make color control string """
|
||||
seq = _curses.tigetstr('setaf').decode('ascii')
|
||||
if seq is not None:
|
||||
# XXX may fail - need better logic
|
||||
seq = seq.replace("%p1", "") % color
|
||||
return seq
|
||||
|
||||
self['NORMAL'] = _curses.tigetstr('sgr0').decode('ascii')
|
||||
self['BOLD'] = _curses.tigetstr('bold').decode('ascii')
|
||||
|
||||
erase = _curses.tigetstr('el1').decode('ascii')
|
||||
if erase is not None:
|
||||
self['ERASE'] = erase + \
|
||||
_curses.tigetstr('cr').decode('ascii')
|
||||
|
||||
self['RED'] = make_color(_curses.COLOR_RED)
|
||||
self['YELLOW'] = make_color(_curses.COLOR_YELLOW)
|
||||
self['GREEN'] = make_color(_curses.COLOR_GREEN)
|
||||
|
||||
def __getitem__(self, key):
|
||||
""" Deliver always """
|
||||
dict.get(self, key) or ""
|
||||
|
||||
|
||||
def terminfo():
|
||||
""" Get info singleton """
|
||||
# pylint: disable = E1101, W0612
|
||||
if terminfo.info is None:
|
||||
terminfo.info = _INFO()
|
||||
return terminfo.info
|
||||
terminfo.info = None
|
||||
|
||||
|
||||
def write(fmt, **kwargs):
|
||||
""" Write stuff on the terminal """
|
||||
parm = dict(terminfo())
|
||||
parm.update(kwargs)
|
||||
_sys.stdout.write(fmt % parm)
|
||||
_sys.stdout.flush()
|
||||
|
||||
|
||||
def green(bmt, **kwargs):
|
||||
""" Write something in green on screen """
|
||||
announce("%%(GREEN)s%s%%(NORMAL)s" % bmt, **kwargs)
|
||||
|
||||
|
||||
def red(bmt, **kwargs):
|
||||
""" Write something in red on the screen """
|
||||
announce("%%(BOLD)s%%(RED)s%s%%(NORMAL)s" % bmt, **kwargs)
|
||||
|
||||
|
||||
def yellow(fmt, **kwargs):
|
||||
""" Write something in yellow on the screen """
|
||||
announce("%%(BOLD)s%%(YELLOW)s%s%%(NORMAL)s" % fmt, **kwargs)
|
||||
|
||||
|
||||
def announce(fmt, **kwargs):
|
||||
""" Announce something """
|
||||
write(fmt, **kwargs)
|
||||
_sys.stdout.write("\n")
|
||||
_sys.stdout.flush()
|
||||
|
||||
|
63
_setup/py3/util.py
Normal file
63
_setup/py3/util.py
Normal file
@ -0,0 +1,63 @@
|
||||
# -*- coding: ascii -*-
|
||||
#
|
||||
# Copyright 2007, 2008, 2009, 2010, 2011
|
||||
# Andr\xe9 Malo or his licensors, as applicable
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
"""
|
||||
=================
|
||||
Setup utilities
|
||||
=================
|
||||
|
||||
Setup utilities.
|
||||
"""
|
||||
__author__ = "Andr\xe9 Malo"
|
||||
__docformat__ = "restructuredtext en"
|
||||
|
||||
from distutils import util as _util
|
||||
try:
|
||||
from configparser import SafeConfigParser
|
||||
except ImportError:
|
||||
import configparser as _config_parser
|
||||
class SafeConfigParser(_config_parser.ConfigParser):
|
||||
""" Safe config parser """
|
||||
def _interpolate(self, section, option, rawval, vars):
|
||||
return rawval
|
||||
|
||||
def items(self, section):
|
||||
return [(key, self.get(section, key))
|
||||
for key in self.options(section)
|
||||
]
|
||||
|
||||
|
||||
def humanbool(name, value):
|
||||
"""
|
||||
Determine human boolean value
|
||||
|
||||
:Parameters:
|
||||
`name` : ``str``
|
||||
The config key (used for error message)
|
||||
|
||||
`value` : ``str``
|
||||
The config value
|
||||
|
||||
:Return: The boolean value
|
||||
:Rtype: ``bool``
|
||||
|
||||
:Exceptions:
|
||||
- `ValueError` : The value could not be recognized
|
||||
"""
|
||||
try:
|
||||
return _util.strtobool(str(value).strip().lower() or 'no')
|
||||
except ValueError:
|
||||
raise ValueError("Unrecognized config value: %s = %s" % (name, value))
|
172
bench.py
Executable file
172
bench.py
Executable file
@ -0,0 +1,172 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: ascii -*-
|
||||
#
|
||||
# Copyright 2011, 2012
|
||||
# Andr\xe9 Malo or his licensors, as applicable
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
"""
|
||||
=================================
|
||||
Benchmark jsmin implementations
|
||||
=================================
|
||||
|
||||
Benchmark jsmin implementations.
|
||||
|
||||
Usage::
|
||||
|
||||
bench.py [-c COUNT] jsfile ...
|
||||
|
||||
-c COUNT number of runs per jsfile and minifier. Defaults to 10.
|
||||
|
||||
"""
|
||||
__author__ = "Andr\xe9 Malo"
|
||||
__author__ = getattr(__author__, 'decode', lambda x: __author__)('latin-1')
|
||||
__docformat__ = "restructuredtext en"
|
||||
__license__ = "Apache License, Version 2.0"
|
||||
__version__ = "1.0.0"
|
||||
|
||||
import sys as _sys
|
||||
import time as _time
|
||||
|
||||
class jsmins(object):
|
||||
from bench import jsmin as p_01_simple_port
|
||||
if _sys.version_info >= (2, 4):
|
||||
from bench import jsmin_2_0_2 as p_02_jsmin_2_0_2
|
||||
else:
|
||||
print("jsmin_2_0_2 available for python 2.4 and later...")
|
||||
if _sys.version_info < (3, 0):
|
||||
try:
|
||||
import slimit as _slimit_0_7
|
||||
except ImportError:
|
||||
print("slimit_0_7 not installed for python %d.%d..." %
|
||||
_sys.version_info[:2]
|
||||
)
|
||||
else:
|
||||
class p_03_slimit_0_7(object):
|
||||
pass
|
||||
p_03_slimit_0_7 = p_03_slimit_0_7()
|
||||
p_03_slimit_0_7.jsmin = _slimit_0_7.minify
|
||||
class p_04_slimit_0_7_mangle(object):
|
||||
pass
|
||||
p_04_slimit_0_7_mangle = p_04_slimit_0_7_mangle()
|
||||
p_04_slimit_0_7_mangle.jsmin = \
|
||||
lambda x, s=_slimit_0_7: s.minify(x, True)
|
||||
else:
|
||||
print("slimit_0_7 not available for python 3...")
|
||||
|
||||
import rjsmin as p_05_rjsmin
|
||||
try:
|
||||
import _rjsmin as p_06__rjsmin
|
||||
except ImportError:
|
||||
print("_rjsmin (C-Port) not available")
|
||||
jsmins.p_05_rjsmin.jsmin = jsmins.p_05_rjsmin._make_jsmin(
|
||||
python_only=True
|
||||
)
|
||||
print("Python Release: %s" % ".".join(map(str, _sys.version_info[:3])))
|
||||
print("")
|
||||
|
||||
|
||||
def slurp(filename):
|
||||
""" Load a file """
|
||||
fp = open(filename)
|
||||
try:
|
||||
return fp.read()
|
||||
finally:
|
||||
fp.close()
|
||||
|
||||
|
||||
def print_(*value, **kwargs):
|
||||
""" Print stuff """
|
||||
(kwargs.get('file') or _sys.stdout).write(
|
||||
''.join(value) + kwargs.get('end', '\n')
|
||||
)
|
||||
|
||||
|
||||
def bench(filenames, count):
|
||||
"""
|
||||
Benchmark the minifiers with given javascript samples
|
||||
|
||||
:Parameters:
|
||||
`filenames` : sequence
|
||||
List of filenames
|
||||
|
||||
`count` : ``int``
|
||||
Number of runs per js file and minifier
|
||||
|
||||
:Exceptions:
|
||||
- `RuntimeError` : empty filenames sequence
|
||||
"""
|
||||
if not filenames:
|
||||
raise RuntimeError("Missing files to benchmark")
|
||||
try:
|
||||
xrange
|
||||
except NameError:
|
||||
xrange = range
|
||||
try:
|
||||
cmp
|
||||
except NameError:
|
||||
cmp = lambda a, b: (a > b) - (a < b)
|
||||
|
||||
ports = [item for item in dir(jsmins) if item.startswith('p_')]
|
||||
ports.sort()
|
||||
space = max(map(len, ports)) - 4
|
||||
ports = [(item[5:], getattr(jsmins, item).jsmin) for item in ports]
|
||||
counted = [None for _ in xrange(count)]
|
||||
flush = _sys.stdout.flush
|
||||
|
||||
inputs = [(filename, slurp(filename)) for filename in filenames]
|
||||
for filename, script in inputs:
|
||||
print_("Benchmarking %r..." % filename, end=" ")
|
||||
flush()
|
||||
outputs = [jsmin(script) for _, jsmin in ports]
|
||||
print_("(%.1f KiB)" % (len(script) / 1024.0))
|
||||
flush()
|
||||
times = []
|
||||
for idx, (name, jsmin) in enumerate(ports):
|
||||
print_(" Timing %s%s... (%5.1f KiB %s)" % (
|
||||
name,
|
||||
" " * (space - len(name)),
|
||||
len(outputs[idx]) / 1024.0,
|
||||
idx == 0 and '*' or
|
||||
['=', '>', '<'][cmp(len(outputs[idx]), len(outputs[0]))],
|
||||
), end=" ")
|
||||
flush()
|
||||
start = _time.time()
|
||||
for _ in counted:
|
||||
jsmin(script)
|
||||
end = _time.time()
|
||||
times.append((end - start) * 1000 / count)
|
||||
print_("%8.2f ms" % times[-1], end=" ")
|
||||
flush()
|
||||
if len(times) <= 1:
|
||||
print_()
|
||||
else:
|
||||
print_("(factor: %s)" % (', '.join([
|
||||
'%.2f' % (timed / times[-1]) for timed in times[:-1]
|
||||
])))
|
||||
flush()
|
||||
print_()
|
||||
|
||||
|
||||
def main(argv):
|
||||
""" Main """
|
||||
count, idx = 10, 0
|
||||
if argv and argv[0] == '-c':
|
||||
count, idx = int(argv[1]), 2
|
||||
elif argv and argv[0].startswith('-c'):
|
||||
count, idx = int(argv[0][2:]), 1
|
||||
bench(argv[idx:], count)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main(_sys.argv[1:])
|
0
bench/__init__.py
Normal file
0
bench/__init__.py
Normal file
178
bench/apiviewer.js
Normal file
178
bench/apiviewer.js
Normal file
File diff suppressed because one or more lines are too long
1829
bench/bootstrap.js
vendored
Normal file
1829
bench/bootstrap.js
vendored
Normal file
File diff suppressed because it is too large
Load Diff
9266
bench/jquery-1.7.1.js
vendored
Normal file
9266
bench/jquery-1.7.1.js
vendored
Normal file
File diff suppressed because it is too large
Load Diff
291
bench/jsmin.c
Normal file
291
bench/jsmin.c
Normal file
@ -0,0 +1,291 @@
|
||||
/* jsmin.c
|
||||
2011-01-22
|
||||
|
||||
Copyright (c) 2002 Douglas Crockford (www.crockford.com)
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do
|
||||
so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
The Software shall be used for Good, not Evil.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
static int theA;
|
||||
static int theB;
|
||||
static int theLookahead = EOF;
|
||||
|
||||
|
||||
/* isAlphanum -- return true if the character is a letter, digit, underscore,
|
||||
dollar sign, or non-ASCII character.
|
||||
*/
|
||||
|
||||
static int
|
||||
isAlphanum(int c)
|
||||
{
|
||||
return ((c >= 'a' && c <= 'z') || (c >= '0' && c <= '9') ||
|
||||
(c >= 'A' && c <= 'Z') || c == '_' || c == '$' || c == '\\' ||
|
||||
c > 126);
|
||||
}
|
||||
|
||||
|
||||
/* get -- return the next character from stdin. Watch out for lookahead. If
|
||||
the character is a control character, translate it to a space or
|
||||
linefeed.
|
||||
*/
|
||||
|
||||
static int
|
||||
get()
|
||||
{
|
||||
int c = theLookahead;
|
||||
theLookahead = EOF;
|
||||
if (c == EOF) {
|
||||
c = getc(stdin);
|
||||
}
|
||||
if (c >= ' ' || c == '\n' || c == EOF) {
|
||||
return c;
|
||||
}
|
||||
if (c == '\r') {
|
||||
return '\n';
|
||||
}
|
||||
return ' ';
|
||||
}
|
||||
|
||||
|
||||
/* peek -- get the next character without getting it.
|
||||
*/
|
||||
|
||||
static int
|
||||
peek()
|
||||
{
|
||||
theLookahead = get();
|
||||
return theLookahead;
|
||||
}
|
||||
|
||||
|
||||
/* next -- get the next character, excluding comments. peek() is used to see
|
||||
if a '/' is followed by a '/' or '*'.
|
||||
*/
|
||||
|
||||
static int
|
||||
next()
|
||||
{
|
||||
int c = get();
|
||||
if (c == '/') {
|
||||
switch (peek()) {
|
||||
case '/':
|
||||
for (;;) {
|
||||
c = get();
|
||||
if (c <= '\n') {
|
||||
return c;
|
||||
}
|
||||
}
|
||||
case '*':
|
||||
get();
|
||||
for (;;) {
|
||||
switch (get()) {
|
||||
case '*':
|
||||
if (peek() == '/') {
|
||||
get();
|
||||
return ' ';
|
||||
}
|
||||
break;
|
||||
case EOF:
|
||||
fprintf(stderr, "Error: JSMIN Unterminated comment.\n");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
default:
|
||||
return c;
|
||||
}
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
|
||||
/* action -- do something! What you do is determined by the argument:
|
||||
1 Output A. Copy B to A. Get the next B.
|
||||
2 Copy B to A. Get the next B. (Delete A).
|
||||
3 Get the next B. (Delete B).
|
||||
action treats a string as a single character. Wow!
|
||||
action recognizes a regular expression if it is preceded by ( or , or =.
|
||||
*/
|
||||
|
||||
static void
|
||||
action(int d)
|
||||
{
|
||||
switch (d) {
|
||||
case 1:
|
||||
putc(theA, stdout);
|
||||
case 2:
|
||||
theA = theB;
|
||||
if (theA == '\'' || theA == '"') {
|
||||
for (;;) {
|
||||
putc(theA, stdout);
|
||||
theA = get();
|
||||
if (theA == theB) {
|
||||
break;
|
||||
}
|
||||
if (theA == '\\') {
|
||||
putc(theA, stdout);
|
||||
theA = get();
|
||||
}
|
||||
if (theA == EOF) {
|
||||
fprintf(stderr, "Error: JSMIN unterminated string literal.");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
case 3:
|
||||
theB = next();
|
||||
if (theB == '/' && (theA == '(' || theA == ',' || theA == '=' ||
|
||||
theA == ':' || theA == '[' || theA == '!' ||
|
||||
theA == '&' || theA == '|' || theA == '?' ||
|
||||
theA == '{' || theA == '}' || theA == ';' ||
|
||||
theA == '\n')) {
|
||||
putc(theA, stdout);
|
||||
putc(theB, stdout);
|
||||
for (;;) {
|
||||
theA = get();
|
||||
if (theA == '[') {
|
||||
for (;;) {
|
||||
putc(theA, stdout);
|
||||
theA = get();
|
||||
if (theA == ']') {
|
||||
break;
|
||||
}
|
||||
if (theA == '\\') {
|
||||
putc(theA, stdout);
|
||||
theA = get();
|
||||
}
|
||||
if (theA == EOF) {
|
||||
fprintf(stderr,
|
||||
"Error: JSMIN unterminated set in Regular Expression literal.\n");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
} else if (theA == '/') {
|
||||
break;
|
||||
} else if (theA =='\\') {
|
||||
putc(theA, stdout);
|
||||
theA = get();
|
||||
}
|
||||
if (theA == EOF) {
|
||||
fprintf(stderr,
|
||||
"Error: JSMIN unterminated Regular Expression literal.\n");
|
||||
exit(1);
|
||||
}
|
||||
putc(theA, stdout);
|
||||
}
|
||||
theB = next();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* jsmin -- Copy the input to the output, deleting the characters which are
|
||||
insignificant to JavaScript. Comments will be removed. Tabs will be
|
||||
replaced with spaces. Carriage returns will be replaced with linefeeds.
|
||||
Most spaces and linefeeds will be removed.
|
||||
*/
|
||||
|
||||
static void
|
||||
jsmin()
|
||||
{
|
||||
theA = '\n';
|
||||
action(3);
|
||||
while (theA != EOF) {
|
||||
switch (theA) {
|
||||
case ' ':
|
||||
if (isAlphanum(theB)) {
|
||||
action(1);
|
||||
} else {
|
||||
action(2);
|
||||
}
|
||||
break;
|
||||
case '\n':
|
||||
switch (theB) {
|
||||
case '{':
|
||||
case '[':
|
||||
case '(':
|
||||
case '+':
|
||||
case '-':
|
||||
action(1);
|
||||
break;
|
||||
case ' ':
|
||||
action(3);
|
||||
break;
|
||||
default:
|
||||
if (isAlphanum(theB)) {
|
||||
action(1);
|
||||
} else {
|
||||
action(2);
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
switch (theB) {
|
||||
case ' ':
|
||||
if (isAlphanum(theA)) {
|
||||
action(1);
|
||||
break;
|
||||
}
|
||||
action(3);
|
||||
break;
|
||||
case '\n':
|
||||
switch (theA) {
|
||||
case '}':
|
||||
case ']':
|
||||
case ')':
|
||||
case '+':
|
||||
case '-':
|
||||
case '"':
|
||||
case '\'':
|
||||
action(1);
|
||||
break;
|
||||
default:
|
||||
if (isAlphanum(theA)) {
|
||||
action(1);
|
||||
} else {
|
||||
action(3);
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
action(1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* main -- Output any command line arguments as comments
|
||||
and then minify the input.
|
||||
*/
|
||||
extern int
|
||||
main(int argc, char* argv[])
|
||||
{
|
||||
int i;
|
||||
for (i = 1; i < argc; i += 1) {
|
||||
fprintf(stdout, "// %s\n", argv[i]);
|
||||
}
|
||||
jsmin();
|
||||
return 0;
|
||||
}
|
226
bench/jsmin.py
Executable file
226
bench/jsmin.py
Executable file
@ -0,0 +1,226 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
# This code is original from jsmin by Douglas Crockford, it was translated to
|
||||
# Python by Baruch Even. The original code had the following copyright and
|
||||
# license.
|
||||
#
|
||||
# /* jsmin.c
|
||||
# 2007-05-22
|
||||
#
|
||||
# Copyright (c) 2002 Douglas Crockford (www.crockford.com)
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
# this software and associated documentation files (the "Software"), to deal in
|
||||
# the Software without restriction, including without limitation the rights to
|
||||
# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
# of the Software, and to permit persons to whom the Software is furnished to do
|
||||
# so, subject to the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be included in all
|
||||
# copies or substantial portions of the Software.
|
||||
#
|
||||
# The Software shall be used for Good, not Evil.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
# SOFTWARE.
|
||||
# */
|
||||
|
||||
# imports adjusted for speed (cStringIO) and python 3 (io) -- nd
|
||||
try:
|
||||
from cStringIO import StringIO
|
||||
except ImportError:
|
||||
try:
|
||||
from StringIO import StringIO
|
||||
except ImportError:
|
||||
from io import StringIO
|
||||
|
||||
|
||||
def jsmin(js):
|
||||
ins = StringIO(js)
|
||||
outs = StringIO()
|
||||
JavascriptMinify().minify(ins, outs)
|
||||
str = outs.getvalue()
|
||||
if len(str) > 0 and str[0] == '\n':
|
||||
str = str[1:]
|
||||
return str
|
||||
|
||||
def isAlphanum(c):
|
||||
"""return true if the character is a letter, digit, underscore,
|
||||
dollar sign, or non-ASCII character.
|
||||
"""
|
||||
return ((c >= 'a' and c <= 'z') or (c >= '0' and c <= '9') or
|
||||
(c >= 'A' and c <= 'Z') or c == '_' or c == '$' or c == '\\' or (c is not None and ord(c) > 126));
|
||||
|
||||
class UnterminatedComment(Exception):
|
||||
pass
|
||||
|
||||
class UnterminatedStringLiteral(Exception):
|
||||
pass
|
||||
|
||||
class UnterminatedRegularExpression(Exception):
|
||||
pass
|
||||
|
||||
class JavascriptMinify(object):
|
||||
|
||||
def _outA(self):
|
||||
self.outstream.write(self.theA)
|
||||
def _outB(self):
|
||||
self.outstream.write(self.theB)
|
||||
|
||||
def _get(self):
|
||||
"""return the next character from stdin. Watch out for lookahead. If
|
||||
the character is a control character, translate it to a space or
|
||||
linefeed.
|
||||
"""
|
||||
c = self.theLookahead
|
||||
self.theLookahead = None
|
||||
if c == None:
|
||||
c = self.instream.read(1)
|
||||
if c >= ' ' or c == '\n':
|
||||
return c
|
||||
if c == '': # EOF
|
||||
return '\000'
|
||||
if c == '\r':
|
||||
return '\n'
|
||||
return ' '
|
||||
|
||||
def _peek(self):
|
||||
self.theLookahead = self._get()
|
||||
return self.theLookahead
|
||||
|
||||
def _next(self):
|
||||
"""get the next character, excluding comments. peek() is used to see
|
||||
if an unescaped '/' is followed by a '/' or '*'.
|
||||
"""
|
||||
c = self._get()
|
||||
if c == '/' and self.theA != '\\':
|
||||
p = self._peek()
|
||||
if p == '/':
|
||||
c = self._get()
|
||||
while c > '\n':
|
||||
c = self._get()
|
||||
return c
|
||||
if p == '*':
|
||||
c = self._get()
|
||||
while 1:
|
||||
c = self._get()
|
||||
if c == '*':
|
||||
if self._peek() == '/':
|
||||
self._get()
|
||||
return ' '
|
||||
if c == '\000':
|
||||
raise UnterminatedComment()
|
||||
|
||||
return c
|
||||
|
||||
def _action(self, action):
|
||||
"""do something! What you do is determined by the argument:
|
||||
1 Output A. Copy B to A. Get the next B.
|
||||
2 Copy B to A. Get the next B. (Delete A).
|
||||
3 Get the next B. (Delete B).
|
||||
action treats a string as a single character. Wow!
|
||||
action recognizes a regular expression if it is preceded by ( or , or =.
|
||||
"""
|
||||
if action <= 1:
|
||||
self._outA()
|
||||
|
||||
if action <= 2:
|
||||
self.theA = self.theB
|
||||
if self.theA == "'" or self.theA == '"':
|
||||
while 1:
|
||||
self._outA()
|
||||
self.theA = self._get()
|
||||
if self.theA == self.theB:
|
||||
break
|
||||
if self.theA <= '\n':
|
||||
raise UnterminatedStringLiteral()
|
||||
if self.theA == '\\':
|
||||
self._outA()
|
||||
self.theA = self._get()
|
||||
|
||||
|
||||
if action <= 3:
|
||||
self.theB = self._next()
|
||||
if self.theB == '/' and (self.theA == '(' or self.theA == ',' or
|
||||
self.theA == '=' or self.theA == ':' or
|
||||
self.theA == '[' or self.theA == '?' or
|
||||
self.theA == '!' or self.theA == '&' or
|
||||
self.theA == '|' or self.theA == ';' or
|
||||
self.theA == '{' or self.theA == '}' or
|
||||
self.theA == '\n'):
|
||||
self._outA()
|
||||
self._outB()
|
||||
while 1:
|
||||
self.theA = self._get()
|
||||
if self.theA == '/':
|
||||
break
|
||||
elif self.theA == '\\':
|
||||
self._outA()
|
||||
self.theA = self._get()
|
||||
elif self.theA <= '\n':
|
||||
raise UnterminatedRegularExpression()
|
||||
self._outA()
|
||||
self.theB = self._next()
|
||||
|
||||
|
||||
def _jsmin(self):
|
||||
"""Copy the input to the output, deleting the characters which are
|
||||
insignificant to JavaScript. Comments will be removed. Tabs will be
|
||||
replaced with spaces. Carriage returns will be replaced with linefeeds.
|
||||
Most spaces and linefeeds will be removed.
|
||||
"""
|
||||
self.theA = '\n'
|
||||
self._action(3)
|
||||
|
||||
while self.theA != '\000':
|
||||
if self.theA == ' ':
|
||||
if isAlphanum(self.theB):
|
||||
self._action(1)
|
||||
else:
|
||||
self._action(2)
|
||||
elif self.theA == '\n':
|
||||
if self.theB in ['{', '[', '(', '+', '-']:
|
||||
self._action(1)
|
||||
elif self.theB == ' ':
|
||||
self._action(3)
|
||||
else:
|
||||
if isAlphanum(self.theB):
|
||||
self._action(1)
|
||||
else:
|
||||
self._action(2)
|
||||
else:
|
||||
if self.theB == ' ':
|
||||
if isAlphanum(self.theA):
|
||||
self._action(1)
|
||||
else:
|
||||
self._action(3)
|
||||
elif self.theB == '\n':
|
||||
if self.theA in ['}', ']', ')', '+', '-', '"', '\'']:
|
||||
self._action(1)
|
||||
else:
|
||||
if isAlphanum(self.theA):
|
||||
self._action(1)
|
||||
else:
|
||||
self._action(3)
|
||||
else:
|
||||
self._action(1)
|
||||
|
||||
def minify(self, instream, outstream):
|
||||
self.instream = instream
|
||||
self.outstream = outstream
|
||||
self.theA = '\n'
|
||||
self.theB = None
|
||||
self.theLookahead = None
|
||||
|
||||
self._jsmin()
|
||||
self.instream.close()
|
||||
|
||||
if __name__ == '__main__':
|
||||
import sys
|
||||
jsm = JavascriptMinify()
|
||||
jsm.minify(sys.stdin, sys.stdout)
|
202
bench/jsmin_2_0_2.py
Executable file
202
bench/jsmin_2_0_2.py
Executable file
@ -0,0 +1,202 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
# This code is original from jsmin by Douglas Crockford, it was translated to
|
||||
# Python by Baruch Even. It was refactored by Dave St.Germain for speed.
|
||||
# The original code had the following copyright and license.
|
||||
#
|
||||
# /* jsmin.c
|
||||
# 2007-01-08
|
||||
#
|
||||
# Copyright (c) 2002 Douglas Crockford (www.crockford.com)
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
# of this software and associated documentation files (the "Software"), to deal
|
||||
# in the Software without restriction, including without limitation the rights
|
||||
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
# copies of the Software, and to permit persons to whom the Software is
|
||||
# furnished to do so, subject to the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be included in
|
||||
# all copies or substantial portions of the Software.
|
||||
#
|
||||
# The Software shall be used for Good, not Evil.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
# SOFTWARE.
|
||||
# */
|
||||
|
||||
import sys
|
||||
is_3 = sys.version_info >= (3, 0)
|
||||
if is_3:
|
||||
import io
|
||||
else:
|
||||
import StringIO
|
||||
try:
|
||||
import cStringIO
|
||||
except ImportError:
|
||||
cStringIO = None
|
||||
|
||||
|
||||
__all__ = ['jsmin', 'JavascriptMinify']
|
||||
__version__ = '2.0.2'
|
||||
|
||||
|
||||
def jsmin(js):
|
||||
"""
|
||||
returns a minified version of the javascript string
|
||||
"""
|
||||
if not is_3:
|
||||
if cStringIO and not isinstance(js, unicode):
|
||||
# strings can use cStringIO for a 3x performance
|
||||
# improvement, but unicode (in python2) cannot
|
||||
klass = cStringIO.StringIO
|
||||
else:
|
||||
klass = StringIO.StringIO
|
||||
else:
|
||||
klass = io.StringIO
|
||||
ins = klass(js)
|
||||
outs = klass()
|
||||
JavascriptMinify(ins, outs).minify()
|
||||
return outs.getvalue()
|
||||
|
||||
|
||||
class JavascriptMinify(object):
|
||||
"""
|
||||
Minify an input stream of javascript, writing
|
||||
to an output stream
|
||||
"""
|
||||
|
||||
def __init__(self, instream=None, outstream=None):
|
||||
self.ins = instream
|
||||
self.outs = outstream
|
||||
|
||||
def minify(self, instream=None, outstream=None):
|
||||
if instream and outstream:
|
||||
self.ins, self.outs = instream, outstream
|
||||
write = self.outs.write
|
||||
read = self.ins.read
|
||||
|
||||
space_strings = "abcdefghijklmnopqrstuvwxyz"\
|
||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_$\\"
|
||||
starters, enders = '{[(+-', '}])+-"\''
|
||||
newlinestart_strings = starters + space_strings
|
||||
newlineend_strings = enders + space_strings
|
||||
do_newline = False
|
||||
do_space = False
|
||||
doing_single_comment = False
|
||||
previous_before_comment = ''
|
||||
doing_multi_comment = False
|
||||
in_re = False
|
||||
in_quote = ''
|
||||
quote_buf = []
|
||||
|
||||
previous = read(1)
|
||||
next1 = read(1)
|
||||
if previous == '/':
|
||||
if next1 == '/':
|
||||
doing_single_comment = True
|
||||
elif next1 == '*':
|
||||
doing_multi_comment = True
|
||||
else:
|
||||
write(previous)
|
||||
elif not previous:
|
||||
return
|
||||
elif previous >= '!':
|
||||
if previous in "'\"":
|
||||
in_quote = previous
|
||||
write(previous)
|
||||
previous_non_space = previous
|
||||
else:
|
||||
previous_non_space = ' '
|
||||
if not next1:
|
||||
return
|
||||
|
||||
while 1:
|
||||
next2 = read(1)
|
||||
if not next2:
|
||||
last = next1.strip()
|
||||
if not (doing_single_comment or doing_multi_comment)\
|
||||
and last not in ('', '/'):
|
||||
write(last)
|
||||
break
|
||||
if doing_multi_comment:
|
||||
if next1 == '*' and next2 == '/':
|
||||
doing_multi_comment = False
|
||||
next2 = read(1)
|
||||
elif doing_single_comment:
|
||||
if next1 in '\r\n':
|
||||
doing_single_comment = False
|
||||
while next2 in '\r\n':
|
||||
next2 = read(1)
|
||||
if previous_before_comment in ')}]':
|
||||
do_newline = True
|
||||
elif in_quote:
|
||||
quote_buf.append(next1)
|
||||
|
||||
if next1 == in_quote:
|
||||
numslashes = 0
|
||||
for c in reversed(quote_buf[:-1]):
|
||||
if c != '\\':
|
||||
break
|
||||
else:
|
||||
numslashes += 1
|
||||
if numslashes % 2 == 0:
|
||||
in_quote = ''
|
||||
write(''.join(quote_buf))
|
||||
elif next1 in '\r\n':
|
||||
if previous_non_space in newlineend_strings \
|
||||
or previous_non_space > '~':
|
||||
while 1:
|
||||
if next2 < '!':
|
||||
next2 = read(1)
|
||||
if not next2:
|
||||
break
|
||||
else:
|
||||
if next2 in newlinestart_strings \
|
||||
or next2 > '~' or next2 == '/':
|
||||
do_newline = True
|
||||
break
|
||||
elif next1 < '!' and not in_re:
|
||||
if (previous_non_space in space_strings \
|
||||
or previous_non_space > '~') \
|
||||
and (next2 in space_strings or next2 > '~'):
|
||||
do_space = True
|
||||
elif next1 == '/':
|
||||
if (previous in ';\n\r{}' or previous < '!') and next2 in '/*':
|
||||
if next2 == '/':
|
||||
doing_single_comment = True
|
||||
previous_before_comment = previous_non_space
|
||||
elif next2 == '*':
|
||||
doing_multi_comment = True
|
||||
else:
|
||||
if not in_re:
|
||||
in_re = previous_non_space in '(,=:[?!&|'
|
||||
elif previous_non_space != '\\':
|
||||
in_re = not in_re
|
||||
write('/')
|
||||
else:
|
||||
if do_space:
|
||||
do_space = False
|
||||
write(' ')
|
||||
if do_newline:
|
||||
write('\n')
|
||||
do_newline = False
|
||||
write(next1)
|
||||
if not in_re and next1 in "'\"":
|
||||
in_quote = next1
|
||||
quote_buf = []
|
||||
previous = next1
|
||||
next1 = next2
|
||||
|
||||
if previous >= '!':
|
||||
previous_non_space = previous
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
import sys as _sys
|
||||
_sys.stdout.write(jsmin(_sys.stdin.read()))
|
239
bench/jsmin_playground.py
Executable file
239
bench/jsmin_playground.py
Executable file
@ -0,0 +1,239 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
# This code is original from jsmin.c by Douglas Crockford. This is a
|
||||
# playground port for understanding the semantics by Andr\xe9 Malo. Here's the
|
||||
# jsmin.c license:
|
||||
#
|
||||
# /* jsmin.c
|
||||
# 2007-01-08
|
||||
#
|
||||
# Copyright (c) 2002 Douglas Crockford (www.crockford.com)
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
# of this software and associated documentation files (the "Software"), to deal
|
||||
# in the Software without restriction, including without limitation the rights
|
||||
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
# copies of the Software, and to permit persons to whom the Software is
|
||||
# furnished to do so, subject to the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be included in
|
||||
# all copies or substantial portions of the Software.
|
||||
#
|
||||
# The Software shall be used for Good, not Evil.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
# SOFTWARE.
|
||||
# */
|
||||
|
||||
import re as _re
|
||||
try:
|
||||
import cStringIO as _string_io
|
||||
except ImportError:
|
||||
try:
|
||||
import StringIO as _string_io
|
||||
except ImportError:
|
||||
import io as _string_io
|
||||
|
||||
|
||||
class JSMinError(Exception):
|
||||
""" Minifier base error """
|
||||
|
||||
class UnterminatedComment(JSMinError):
|
||||
""" Unterminated comment """
|
||||
|
||||
class UnterminatedRegex(JSMinError):
|
||||
""" Unterminated Regex literal """
|
||||
|
||||
class UnterminatedString(JSMinError):
|
||||
""" Unterminated String literal """
|
||||
|
||||
|
||||
class PrintableLookAheadStream(object):
|
||||
""" Stream wrapper providing get and peek methods """
|
||||
|
||||
def __init__(self, stream):
|
||||
""" Initialization """
|
||||
self._stream = stream
|
||||
self._looked = None
|
||||
|
||||
def get(self):
|
||||
""" Get one character """
|
||||
char, self._looked = self._looked, None
|
||||
if char is not None:
|
||||
return char
|
||||
char = self._stream.read(1)
|
||||
if not char:
|
||||
raise EOFError()
|
||||
if char == '\r':
|
||||
return '\n'
|
||||
if ord(char) >= 32 or char == '\n':
|
||||
return char
|
||||
return ' '
|
||||
|
||||
def peek(self):
|
||||
""" Peek one character ahead """
|
||||
self._looked = self.get()
|
||||
return self._looked
|
||||
|
||||
|
||||
def m(regex):
|
||||
""" Regex -> matcher """
|
||||
return _re.compile(regex).match
|
||||
|
||||
|
||||
def next_char(stream):
|
||||
""" Next character leaving out comments """
|
||||
get, peek = stream.get, stream.peek
|
||||
char = get()
|
||||
if char == '/':
|
||||
try:
|
||||
c_next = peek()
|
||||
except EOFError:
|
||||
return char
|
||||
if c_next == '/': # // comment
|
||||
while char != '\n':
|
||||
char = get()
|
||||
elif c_next == '*': # /* comment */
|
||||
get()
|
||||
try:
|
||||
while not(char == '*' and peek() == '/'):
|
||||
char = get()
|
||||
get()
|
||||
char = ' '
|
||||
except EOFError:
|
||||
raise UnterminatedComment()
|
||||
return char
|
||||
|
||||
|
||||
def action3(stream, out, first, second,
|
||||
pre_regex_match=m(r'[(,=:\[!&|?{};\n]')):
|
||||
""" throw away second, skip comments and regexps """
|
||||
try:
|
||||
second = next_char(stream)
|
||||
except EOFError:
|
||||
out.write(first)
|
||||
raise
|
||||
if second == '/' and pre_regex_match(first):
|
||||
# Regex found. Parse it till the end.
|
||||
write, get = out.write, stream.get
|
||||
write(first)
|
||||
write(second)
|
||||
try:
|
||||
first = get()
|
||||
while first != '/':
|
||||
if first == '\\':
|
||||
write(first)
|
||||
first = get()
|
||||
elif first == '[':
|
||||
write(first)
|
||||
first = get()
|
||||
while first != ']':
|
||||
if first == '\\':
|
||||
write(first)
|
||||
first = get()
|
||||
write(first)
|
||||
first = get()
|
||||
write(first)
|
||||
first = get()
|
||||
second = next_char(stream)
|
||||
except EOFError:
|
||||
raise UnterminatedRegex()
|
||||
return first, second
|
||||
|
||||
|
||||
def action2(stream, out, first, second):
|
||||
""" shift, skip strings, comments and regexps """
|
||||
first = second
|
||||
if first in (r''''"'''):
|
||||
quote = first
|
||||
write, get = out.write, stream.get
|
||||
write(first)
|
||||
try:
|
||||
first = get()
|
||||
while first != quote:
|
||||
if first == '\\':
|
||||
write(first)
|
||||
first = get()
|
||||
write(first)
|
||||
first = get()
|
||||
except EOFError:
|
||||
raise UnterminatedString()
|
||||
return action3(stream, out, first, second)
|
||||
|
||||
|
||||
def action1(stream, out, first, second):
|
||||
""" write, shift, skip strings, comments and regexps """
|
||||
out.write(first)
|
||||
return action2(stream, out, first, second)
|
||||
|
||||
|
||||
def jsmin_stream(stream, out,
|
||||
id_literal=m(r'[a-zA-Z0-9_$\\\177-\377]'),
|
||||
open_match=m(r'[{\[(+-]'),
|
||||
close_match=m(r'[}\])+"\047-]')):
|
||||
"""
|
||||
JSMin after jsmin.c by Douglas Crockford
|
||||
|
||||
http://www.crockford.com/javascript/jsmin.c
|
||||
"""
|
||||
# pylint: disable = R0912
|
||||
stream = PrintableLookAheadStream(stream)
|
||||
try:
|
||||
first, second = action3(stream, out, '\n', None)
|
||||
while 1:
|
||||
if first == ' ':
|
||||
if id_literal(second):
|
||||
first, second = action1(stream, out, first, second)
|
||||
else:
|
||||
first, second = action2(stream, out, first, second)
|
||||
elif first == '\n':
|
||||
if open_match(second):
|
||||
first, second = action1(stream, out, first, second)
|
||||
elif second == ' ':
|
||||
first, second = action3(stream, out, first, second)
|
||||
elif id_literal(second):
|
||||
first, second = action1(stream, out, first, second)
|
||||
else:
|
||||
first, second = action2(stream, out, first, second)
|
||||
elif second == ' ':
|
||||
if id_literal(first):
|
||||
first, second = action1(stream, out, first, second)
|
||||
else:
|
||||
first, second = action3(stream, out, first, second)
|
||||
elif second == '\n':
|
||||
if close_match(first):
|
||||
first, second = action1(stream, out, first, second)
|
||||
elif id_literal(first):
|
||||
first, second = action1(stream, out, first, second)
|
||||
else:
|
||||
first, second = action3(stream, out, first, second)
|
||||
else:
|
||||
first, second = action1(stream, out, first, second)
|
||||
except EOFError:
|
||||
pass # done.
|
||||
|
||||
|
||||
def jsmin(script):
|
||||
"""
|
||||
Minify JS
|
||||
|
||||
:Parameters:
|
||||
`script` : ``str``
|
||||
JS to minify
|
||||
|
||||
:Return: Minified JS
|
||||
:Rtype: ``str``
|
||||
"""
|
||||
out = _string_io.StringIO()
|
||||
jsmin_stream(_string_io.StringIO(script), out)
|
||||
return out.getvalue().strip()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
import sys as _sys
|
||||
_sys.stdout.write(jsmin(_sys.stdin.read()))
|
97
bench/knockout-2.0.0.js
vendored
Normal file
97
bench/knockout-2.0.0.js
vendored
Normal file
@ -0,0 +1,97 @@
|
||||
// Knockout JavaScript library v2.0.0
|
||||
// (c) Steven Sanderson - http://knockoutjs.com/
|
||||
// License: MIT (http://www.opensource.org/licenses/mit-license.php)
|
||||
|
||||
(function(window,undefined){
|
||||
function c(a){throw a;}var l=void 0,m=!0,o=null,p=!1,r=window.ko={};r.b=function(a,b){for(var d=a.split("."),e=window,f=0;f<d.length-1;f++)e=e[d[f]];e[d[d.length-1]]=b};r.l=function(a,b,d){a[b]=d};
|
||||
r.a=new function(){function a(a,e){if("INPUT"!=a.tagName||!a.type)return p;if("click"!=e.toLowerCase())return p;var b=a.type.toLowerCase();return"checkbox"==b||"radio"==b}var b=/^(\s|\u00A0)+|(\s|\u00A0)+$/g,d={},e={};d[/Firefox\/2/i.test(navigator.userAgent)?"KeyboardEvent":"UIEvents"]=["keyup","keydown","keypress"];d.MouseEvents="click,dblclick,mousedown,mouseup,mousemove,mouseover,mouseout,mouseenter,mouseleave".split(",");for(var f in d){var h=d[f];if(h.length)for(var g=0,i=h.length;g<i;g++)e[h[g]]=
|
||||
f}var j=function(){for(var a=3,e=document.createElement("div"),b=e.getElementsByTagName("i");e.innerHTML="<\!--[if gt IE "+ ++a+"]><i></i><![endif]--\>",b[0];);return 4<a?a:l}();return{Ba:["authenticity_token",/^__RequestVerificationToken(_.*)?$/],n:function(a,e){for(var b=0,f=a.length;b<f;b++)e(a[b])},k:function(a,e){if("function"==typeof Array.prototype.indexOf)return Array.prototype.indexOf.call(a,e);for(var b=0,f=a.length;b<f;b++)if(a[b]===e)return b;return-1},Wa:function(a,e,b){for(var f=0,d=
|
||||
a.length;f<d;f++)if(e.call(b,a[f]))return a[f];return o},ca:function(a,e){var b=r.a.k(a,e);0<=b&&a.splice(b,1)},ya:function(a){for(var a=a||[],e=[],b=0,f=a.length;b<f;b++)0>r.a.k(e,a[b])&&e.push(a[b]);return e},ba:function(a,e){for(var a=a||[],b=[],f=0,d=a.length;f<d;f++)b.push(e(a[f]));return b},aa:function(a,e){for(var a=a||[],b=[],f=0,d=a.length;f<d;f++)e(a[f])&&b.push(a[f]);return b},J:function(a,e){for(var b=0,f=e.length;b<f;b++)a.push(e[b]);return a},extend:function(a,e){for(var b in e)e.hasOwnProperty(b)&&
|
||||
(a[b]=e[b]);return a},U:function(a){for(;a.firstChild;)r.removeNode(a.firstChild)},oa:function(a,e){r.a.U(a);e&&r.a.n(e,function(e){a.appendChild(e)})},Ja:function(a,e){var b=a.nodeType?[a]:a;if(0<b.length){for(var f=b[0],d=f.parentNode,h=0,g=e.length;h<g;h++)d.insertBefore(e[h],f);h=0;for(g=b.length;h<g;h++)r.removeNode(b[h])}},La:function(a,e){0<=navigator.userAgent.indexOf("MSIE 6")?a.setAttribute("selected",e):a.selected=e},z:function(a){return(a||"").replace(b,"")},Db:function(a,e){for(var b=
|
||||
[],f=(a||"").split(e),d=0,h=f.length;d<h;d++){var g=r.a.z(f[d]);""!==g&&b.push(g)}return b},Cb:function(a,e){a=a||"";return e.length>a.length?p:a.substring(0,e.length)===e},hb:function(a){for(var e=Array.prototype.slice.call(arguments,1),b="return ("+a+")",f=0;f<e.length;f++)e[f]&&"object"==typeof e[f]&&(b="with(sc["+f+"]) { "+b+" } ");return(new Function("sc",b))(e)},fb:function(a,e){if(e.compareDocumentPosition)return 16==(e.compareDocumentPosition(a)&16);for(;a!=o;){if(a==e)return m;a=a.parentNode}return p},
|
||||
ga:function(a){return r.a.fb(a,document)},s:function(e,b,f){if("undefined"!=typeof jQuery){if(a(e,b))var d=f,f=function(a,e){var b=this.checked;if(e)this.checked=e.Ya!==m;d.call(this,a);this.checked=b};jQuery(e).bind(b,f)}else"function"==typeof e.addEventListener?e.addEventListener(b,f,p):"undefined"!=typeof e.attachEvent?e.attachEvent("on"+b,function(a){f.call(e,a)}):c(Error("Browser doesn't support addEventListener or attachEvent"))},sa:function(b,f){(!b||!b.nodeType)&&c(Error("element must be a DOM node when calling triggerEvent"));
|
||||
if("undefined"!=typeof jQuery){var d=[];a(b,f)&&d.push({Ya:b.checked});jQuery(b).trigger(f,d)}else if("function"==typeof document.createEvent)"function"==typeof b.dispatchEvent?(d=document.createEvent(e[f]||"HTMLEvents"),d.initEvent(f,m,m,window,0,0,0,0,0,p,p,p,p,0,b),b.dispatchEvent(d)):c(Error("The supplied element doesn't support dispatchEvent"));else if("undefined"!=typeof b.fireEvent){if("click"==f&&"INPUT"==b.tagName&&("checkbox"==b.type.toLowerCase()||"radio"==b.type.toLowerCase()))b.checked=
|
||||
b.checked!==m;b.fireEvent("on"+f)}else c(Error("Browser doesn't support triggering events"))},d:function(a){return r.V(a)?a():a},eb:function(a,e){return 0<=r.a.k((a.className||"").split(/\s+/),e)},Qa:function(a,e,b){var f=r.a.eb(a,e);if(b&&!f)a.className=(a.className||"")+" "+e;else if(f&&!b){for(var b=(a.className||"").split(/\s+/),f="",d=0;d<b.length;d++)b[d]!=e&&(f+=b[d]+" ");a.className=r.a.z(f)}},outerHTML:function(a){if(j===l){var e=a.outerHTML;if("string"==typeof e)return e}e=window.document.createElement("div");
|
||||
e.appendChild(a.cloneNode(m));return e.innerHTML},Ma:function(a,e){var b=r.a.d(e);if(b===o||b===l)b="";"innerText"in a?a.innerText=b:a.textContent=b;if(9<=j)a.innerHTML=a.innerHTML},yb:function(a,e){for(var a=r.a.d(a),e=r.a.d(e),b=[],f=a;f<=e;f++)b.push(f);return b},X:function(a){for(var e=[],b=0,f=a.length;b<f;b++)e.push(a[b]);return e},ob:6===j,pb:7===j,Ca:function(a,e){for(var b=r.a.X(a.getElementsByTagName("INPUT")).concat(r.a.X(a.getElementsByTagName("TEXTAREA"))),f="string"==typeof e?function(a){return a.name===
|
||||
e}:function(a){return e.test(a.name)},d=[],h=b.length-1;0<=h;h--)f(b[h])&&d.push(b[h]);return d},vb:function(a){return"string"==typeof a&&(a=r.a.z(a))?window.JSON&&window.JSON.parse?window.JSON.parse(a):(new Function("return "+a))():o},qa:function(a){("undefined"==typeof JSON||"undefined"==typeof JSON.stringify)&&c(Error("Cannot find JSON.stringify(). Some browsers (e.g., IE < 8) don't support it natively, but you can overcome this by adding a script reference to json2.js, downloadable from http://www.json.org/json2.js"));
|
||||
return JSON.stringify(r.a.d(a))},wb:function(a,e,b){var b=b||{},f=b.params||{},d=b.includeFields||this.Ba,h=a;if("object"==typeof a&&"FORM"==a.tagName)for(var h=a.action,g=d.length-1;0<=g;g--)for(var j=r.a.Ca(a,d[g]),i=j.length-1;0<=i;i--)f[j[i].name]=j[i].value;var e=r.a.d(e),u=document.createElement("FORM");u.style.display="none";u.action=h;u.method="post";for(var y in e)a=document.createElement("INPUT"),a.name=y,a.value=r.a.qa(r.a.d(e[y])),u.appendChild(a);for(y in f)a=document.createElement("INPUT"),
|
||||
a.name=y,a.value=f[y],u.appendChild(a);document.body.appendChild(u);b.submitter?b.submitter(u):u.submit();setTimeout(function(){u.parentNode.removeChild(u)},0)}}};r.b("ko.utils",r.a);
|
||||
r.a.n([["arrayForEach",r.a.n],["arrayFirst",r.a.Wa],["arrayFilter",r.a.aa],["arrayGetDistinctValues",r.a.ya],["arrayIndexOf",r.a.k],["arrayMap",r.a.ba],["arrayPushAll",r.a.J],["arrayRemoveItem",r.a.ca],["extend",r.a.extend],["fieldsIncludedWithJsonPost",r.a.Ba],["getFormFields",r.a.Ca],["postJson",r.a.wb],["parseJson",r.a.vb],["registerEventHandler",r.a.s],["stringifyJson",r.a.qa],["range",r.a.yb],["toggleDomNodeCssClass",r.a.Qa],["triggerEvent",r.a.sa],["unwrapObservable",r.a.d]],function(a){r.b("ko.utils."+
|
||||
a[0],a[1])});Function.prototype.bind||(Function.prototype.bind=function(a){var b=this,d=Array.prototype.slice.call(arguments),a=d.shift();return function(){return b.apply(a,d.concat(Array.prototype.slice.call(arguments)))}});
|
||||
r.a.e=new function(){var a=0,b="__ko__"+(new Date).getTime(),d={};return{get:function(a,b){var d=r.a.e.getAll(a,p);return d===l?l:d[b]},set:function(a,b,d){d===l&&r.a.e.getAll(a,p)===l||(r.a.e.getAll(a,m)[b]=d)},getAll:function(e,f){var h=e[b];if(!(h&&"null"!==h)){if(!f)return;h=e[b]="ko"+a++;d[h]={}}return d[h]},clear:function(a){var f=a[b];f&&(delete d[f],a[b]=o)}}};r.b("ko.utils.domData",r.a.e);r.b("ko.utils.domData.clear",r.a.e.clear);
|
||||
r.a.A=new function(){function a(a,b){var h=r.a.e.get(a,d);h===l&&b&&(h=[],r.a.e.set(a,d,h));return h}function b(e){var b=a(e,p);if(b)for(var b=b.slice(0),d=0;d<b.length;d++)b[d](e);r.a.e.clear(e);"function"==typeof jQuery&&"function"==typeof jQuery.cleanData&&jQuery.cleanData([e])}var d="__ko_domNodeDisposal__"+(new Date).getTime();return{va:function(e,b){"function"!=typeof b&&c(Error("Callback must be a function"));a(e,m).push(b)},Ia:function(e,b){var h=a(e,p);h&&(r.a.ca(h,b),0==h.length&&r.a.e.set(e,
|
||||
d,l))},F:function(a){if(!(1!=a.nodeType&&9!=a.nodeType)){b(a);var f=[];r.a.J(f,a.getElementsByTagName("*"));for(var a=0,d=f.length;a<d;a++)b(f[a])}},removeNode:function(a){r.F(a);a.parentNode&&a.parentNode.removeChild(a)}}};r.F=r.a.A.F;r.removeNode=r.a.A.removeNode;r.b("ko.cleanNode",r.F);r.b("ko.removeNode",r.removeNode);r.b("ko.utils.domNodeDisposal",r.a.A);r.b("ko.utils.domNodeDisposal.addDisposeCallback",r.a.A.va);r.b("ko.utils.domNodeDisposal.removeDisposeCallback",r.a.A.Ia);
|
||||
r.a.ma=function(a){var b;if("undefined"!=typeof jQuery){if((b=jQuery.clean([a]))&&b[0]){for(a=b[0];a.parentNode&&11!==a.parentNode.nodeType;)a=a.parentNode;a.parentNode&&a.parentNode.removeChild(a)}}else{var d=r.a.z(a).toLowerCase();b=document.createElement("div");d=d.match(/^<(thead|tbody|tfoot)/)&&[1,"<table>","</table>"]||!d.indexOf("<tr")&&[2,"<table><tbody>","</tbody></table>"]||(!d.indexOf("<td")||!d.indexOf("<th"))&&[3,"<table><tbody><tr>","</tr></tbody></table>"]||[0,"",""];a="ignored<div>"+
|
||||
d[1]+a+d[2]+"</div>";for("function"==typeof window.innerShiv?b.appendChild(window.innerShiv(a)):b.innerHTML=a;d[0]--;)b=b.lastChild;b=r.a.X(b.lastChild.childNodes)}return b};r.a.Z=function(a,b){r.a.U(a);if(b!==o&&b!==l)if("string"!=typeof b&&(b=b.toString()),"undefined"!=typeof jQuery)jQuery(a).html(b);else for(var d=r.a.ma(b),e=0;e<d.length;e++)a.appendChild(d[e])};r.b("ko.utils.parseHtmlFragment",r.a.ma);r.b("ko.utils.setHtml",r.a.Z);
|
||||
r.r=function(){function a(){return(4294967296*(1+Math.random())|0).toString(16).substring(1)}function b(a,f){if(a)if(8==a.nodeType){var d=r.r.Ga(a.nodeValue);d!=o&&f.push({cb:a,tb:d})}else if(1==a.nodeType)for(var d=0,g=a.childNodes,i=g.length;d<i;d++)b(g[d],f)}var d={};return{ka:function(b){"function"!=typeof b&&c(Error("You can only pass a function to ko.memoization.memoize()"));var f=a()+a();d[f]=b;return"<\!--[ko_memo:"+f+"]--\>"},Ra:function(a,b){var h=d[a];h===l&&c(Error("Couldn't find any memo with ID "+
|
||||
a+". Perhaps it's already been unmemoized."));try{return h.apply(o,b||[]),m}finally{delete d[a]}},Sa:function(a,f){var d=[];b(a,d);for(var g=0,i=d.length;g<i;g++){var j=d[g].cb,k=[j];f&&r.a.J(k,f);r.r.Ra(d[g].tb,k);j.nodeValue="";j.parentNode&&j.parentNode.removeChild(j)}},Ga:function(a){return(a=a.match(/^\[ko_memo\:(.*?)\]$/))?a[1]:o}}}();r.b("ko.memoization",r.r);r.b("ko.memoization.memoize",r.r.ka);r.b("ko.memoization.unmemoize",r.r.Ra);r.b("ko.memoization.parseMemoText",r.r.Ga);
|
||||
r.b("ko.memoization.unmemoizeDomNodeAndDescendants",r.r.Sa);r.Aa={throttle:function(a,b){a.throttleEvaluation=b;var d=o;return r.i({read:a,write:function(e){clearTimeout(d);d=setTimeout(function(){a(e)},b)}})},notify:function(a,b){a.equalityComparer="always"==b?function(){return p}:r.w.fn.equalityComparer;return a}};r.b("ko.extenders",r.Aa);r.Oa=function(a,b){this.da=a;this.bb=b;r.l(this,"dispose",this.v)};r.Oa.prototype.v=function(){this.nb=m;this.bb()};
|
||||
r.R=function(){this.u={};r.a.extend(this,r.R.fn);r.l(this,"subscribe",this.ra);r.l(this,"extend",this.extend);r.l(this,"getSubscriptionsCount",this.kb)};
|
||||
r.R.fn={ra:function(a,b,d){var d=d||"change",a=b?a.bind(b):a,e=new r.Oa(a,function(){r.a.ca(this.u[d],e)}.bind(this));this.u[d]||(this.u[d]=[]);this.u[d].push(e);return e},notifySubscribers:function(a,b){b=b||"change";this.u[b]&&r.a.n(this.u[b].slice(0),function(b){b&&b.nb!==m&&b.da(a)})},kb:function(){var a=0,b;for(b in this.u)this.u.hasOwnProperty(b)&&(a+=this.u[b].length);return a},extend:function(a){var b=this;if(a)for(var d in a){var e=r.Aa[d];"function"==typeof e&&(b=e(b,a[d]))}return b}};
|
||||
r.Ea=function(a){return"function"==typeof a.ra&&"function"==typeof a.notifySubscribers};r.b("ko.subscribable",r.R);r.b("ko.isSubscribable",r.Ea);r.T=function(){var a=[];return{Xa:function(b){a.push({da:b,za:[]})},end:function(){a.pop()},Ha:function(b){r.Ea(b)||c("Only subscribable things can act as dependencies");if(0<a.length){var d=a[a.length-1];0<=r.a.k(d.za,b)||(d.za.push(b),d.da(b))}}}}();var B={undefined:m,"boolean":m,number:m,string:m};
|
||||
r.w=function(a){function b(){if(0<arguments.length){if(!b.equalityComparer||!b.equalityComparer(d,arguments[0]))b.H(),d=arguments[0],b.G();return this}r.T.Ha(b);return d}var d=a;r.R.call(b);b.G=function(){b.notifySubscribers(d)};b.H=function(){b.notifySubscribers(d,"beforeChange")};r.a.extend(b,r.w.fn);r.l(b,"valueHasMutated",b.G);r.l(b,"valueWillMutate",b.H);return b};r.w.fn={B:r.w,equalityComparer:function(a,b){return a===o||typeof a in B?a===b:p}};
|
||||
r.V=function(a){return a===o||a===l||a.B===l?p:a.B===r.w?m:r.V(a.B)};r.P=function(a){return"function"==typeof a&&a.B===r.w?m:"function"==typeof a&&a.B===r.i&&a.lb?m:p};r.b("ko.observable",r.w);r.b("ko.isObservable",r.V);r.b("ko.isWriteableObservable",r.P);
|
||||
r.Q=function(a){0==arguments.length&&(a=[]);a!==o&&a!==l&&!("length"in a)&&c(Error("The argument passed when initializing an observable array must be an array, or null, or undefined."));var b=new r.w(a);r.a.extend(b,r.Q.fn);r.l(b,"remove",b.remove);r.l(b,"removeAll",b.zb);r.l(b,"destroy",b.fa);r.l(b,"destroyAll",b.ab);r.l(b,"indexOf",b.indexOf);r.l(b,"replace",b.replace);return b};
|
||||
r.Q.fn={remove:function(a){for(var b=this(),d=[],e="function"==typeof a?a:function(b){return b===a},f=0;f<b.length;f++){var h=b[f];e(h)&&(0===d.length&&this.H(),d.push(h),b.splice(f,1),f--)}d.length&&this.G();return d},zb:function(a){if(a===l){var b=this(),d=b.slice(0);this.H();b.splice(0,b.length);this.G();return d}return!a?[]:this.remove(function(b){return 0<=r.a.k(a,b)})},fa:function(a){var b=this(),d="function"==typeof a?a:function(b){return b===a};this.H();for(var e=b.length-1;0<=e;e--)d(b[e])&&
|
||||
(b[e]._destroy=m);this.G()},ab:function(a){return a===l?this.fa(function(){return m}):!a?[]:this.fa(function(b){return 0<=r.a.k(a,b)})},indexOf:function(a){var b=this();return r.a.k(b,a)},replace:function(a,b){var d=this.indexOf(a);0<=d&&(this.H(),this()[d]=b,this.G())}};r.a.n("pop,push,reverse,shift,sort,splice,unshift".split(","),function(a){r.Q.fn[a]=function(){var b=this();this.H();b=b[a].apply(b,arguments);this.G();return b}});
|
||||
r.a.n(["slice"],function(a){r.Q.fn[a]=function(){var b=this();return b[a].apply(b,arguments)}});r.b("ko.observableArray",r.Q);function C(a,b){a&&"object"==typeof a?b=a:(b=b||{},b.read=a||b.read);"function"!=typeof b.read&&c("Pass a function that returns the value of the dependentObservable");return b}
|
||||
r.i=function(a,b,d){function e(){r.a.n(q,function(a){a.v()});q=[]}function f(){var a=g.throttleEvaluation;a&&0<=a?(clearTimeout(v),v=setTimeout(h,a)):h()}function h(){if(j&&"function"==typeof d.disposeWhen&&d.disposeWhen())g.v();else{try{e();r.T.Xa(function(a){q.push(a.ra(f))});var a=d.read.call(d.owner||b);g.notifySubscribers(i,"beforeChange");i=a}finally{r.T.end()}g.notifySubscribers(i);j=m}}function g(){if(0<arguments.length)"function"===typeof d.write?d.write.apply(d.owner||b,arguments):c("Cannot write a value to a dependentObservable unless you specify a 'write' option. If you wish to read the current value, don't pass any parameters.");
|
||||
else return j||h(),r.T.Ha(g),i}var i,j=p,d=C(a,d),k="object"==typeof d.disposeWhenNodeIsRemoved?d.disposeWhenNodeIsRemoved:o,n=o;if(k){n=function(){g.v()};r.a.A.va(k,n);var t=d.disposeWhen;d.disposeWhen=function(){return!r.a.ga(k)||"function"==typeof t&&t()}}var q=[],v=o;g.jb=function(){return q.length};g.lb="function"===typeof d.write;g.v=function(){k&&r.a.A.Ia(k,n);e()};r.R.call(g);r.a.extend(g,r.i.fn);d.deferEvaluation!==m&&h();r.l(g,"dispose",g.v);r.l(g,"getDependenciesCount",g.jb);return g};
|
||||
r.i.fn={B:r.i};r.i.B=r.w;r.b("ko.dependentObservable",r.i);r.b("ko.computed",r.i);
|
||||
(function(){function a(e,f,h){h=h||new d;e=f(e);if(!("object"==typeof e&&e!==o&&e!==l&&!(e instanceof Date)))return e;var g=e instanceof Array?[]:{};h.save(e,g);b(e,function(b){var d=f(e[b]);switch(typeof d){case "boolean":case "number":case "string":case "function":g[b]=d;break;case "object":case "undefined":var k=h.get(d);g[b]=k!==l?k:a(d,f,h)}});return g}function b(a,b){if(a instanceof Array)for(var d=0;d<a.length;d++)b(d);else for(d in a)b(d)}function d(){var a=[],b=[];this.save=function(d,g){var i=
|
||||
r.a.k(a,d);0<=i?b[i]=g:(a.push(d),b.push(g))};this.get=function(d){d=r.a.k(a,d);return 0<=d?b[d]:l}}r.Pa=function(b){0==arguments.length&&c(Error("When calling ko.toJS, pass the object you want to convert."));return a(b,function(a){for(var b=0;r.V(a)&&10>b;b++)a=a();return a})};r.toJSON=function(a){a=r.Pa(a);return r.a.qa(a)}})();r.b("ko.toJS",r.Pa);r.b("ko.toJSON",r.toJSON);
|
||||
r.h={q:function(a){return"OPTION"==a.tagName?a.__ko__hasDomDataOptionValue__===m?r.a.e.get(a,r.c.options.la):a.getAttribute("value"):"SELECT"==a.tagName?0<=a.selectedIndex?r.h.q(a.options[a.selectedIndex]):l:a.value},S:function(a,b){if("OPTION"==a.tagName)switch(typeof b){case "string":r.a.e.set(a,r.c.options.la,l);"__ko__hasDomDataOptionValue__"in a&&delete a.__ko__hasDomDataOptionValue__;a.value=b;break;default:r.a.e.set(a,r.c.options.la,b),a.__ko__hasDomDataOptionValue__=m,a.value="number"===typeof b?
|
||||
b:""}else if("SELECT"==a.tagName)for(var d=a.options.length-1;0<=d;d--){if(r.h.q(a.options[d])==b){a.selectedIndex=d;break}}else{if(b===o||b===l)b="";a.value=b}}};r.b("ko.selectExtensions",r.h);r.b("ko.selectExtensions.readValue",r.h.q);r.b("ko.selectExtensions.writeValue",r.h.S);
|
||||
r.j=function(){function a(a,e){for(var d=o;a!=d;)d=a,a=a.replace(b,function(a,b){return e[b]});return a}var b=/\@ko_token_(\d+)\@/g,d=/^[\_$a-z][\_$a-z0-9]*(\[.*?\])*(\.[\_$a-z][\_$a-z0-9]*(\[.*?\])*)*$/i,e=["true","false"];return{D:[],Y:function(b){var e=r.a.z(b);if(3>e.length)return[];"{"===e.charAt(0)&&(e=e.substring(1,e.length-1));for(var b=[],d=o,i,j=0;j<e.length;j++){var k=e.charAt(j);if(d===o)switch(k){case '"':case "'":case "/":d=j,i=k}else if(k==i&&"\\"!==e.charAt(j-1)){k=e.substring(d,j+
|
||||
1);b.push(k);var n="@ko_token_"+(b.length-1)+"@",e=e.substring(0,d)+n+e.substring(j+1),j=j-(k.length-n.length),d=o}}i=d=o;for(var t=0,q=o,j=0;j<e.length;j++){k=e.charAt(j);if(d===o)switch(k){case "{":d=j;q=k;i="}";break;case "(":d=j;q=k;i=")";break;case "[":d=j,q=k,i="]"}k===q?t++:k===i&&(t--,0===t&&(k=e.substring(d,j+1),b.push(k),n="@ko_token_"+(b.length-1)+"@",e=e.substring(0,d)+n+e.substring(j+1),j-=k.length-n.length,d=o))}i=[];e=e.split(",");d=0;for(j=e.length;d<j;d++)t=e[d],q=t.indexOf(":"),
|
||||
0<q&&q<t.length-1?(k=t.substring(q+1),i.push({key:a(t.substring(0,q),b),value:a(k,b)})):i.push({unknown:a(t,b)});return i},ia:function(a){for(var b="string"===typeof a?r.j.Y(a):a,g=[],a=[],i,j=0;i=b[j];j++)if(0<g.length&&g.push(","),i.key){var k;a:{k=i.key;var n=r.a.z(k);switch(n.length&&n.charAt(0)){case "'":case '"':break a;default:k="'"+n+"'"}}i=i.value;g.push(k);g.push(":");g.push(i);n=r.a.z(i);if(0<=r.a.k(e,r.a.z(n).toLowerCase())?0:n.match(d)!==o)0<a.length&&a.push(", "),a.push(k+" : function(__ko_value) { "+
|
||||
i+" = __ko_value; }")}else i.unknown&&g.push(i.unknown);b=g.join("");0<a.length&&(b=b+", '_ko_property_writers' : { "+a.join("")+" } ");return b},rb:function(a,b){for(var e=0;e<a.length;e++)if(r.a.z(a[e].key)==b)return m;return p}}}();r.b("ko.jsonExpressionRewriting",r.j);r.b("ko.jsonExpressionRewriting.bindingRewriteValidators",r.j.D);r.b("ko.jsonExpressionRewriting.parseObjectLiteral",r.j.Y);r.b("ko.jsonExpressionRewriting.insertPropertyAccessorsIntoJson",r.j.ia);
|
||||
(function(){function a(a){return 8==a.nodeType&&(f?a.text:a.nodeValue).match(h)}function b(a){return 8==a.nodeType&&(f?a.text:a.nodeValue).match(g)}function d(e,d){for(var f=e,g=1,h=[];f=f.nextSibling;){if(b(f)&&(g--,0===g))return h;h.push(f);a(f)&&g++}d||c(Error("Cannot find closing comment tag to match: "+e.nodeValue));return o}function e(a,b){var e=d(a,b);return e?0<e.length?e[e.length-1].nextSibling:a.nextSibling:o}var f="<\!--test--\>"===document.createComment("test").text,h=f?/^<\!--\s*ko\s+(.*\:.*)\s*--\>$/:
|
||||
/^\s*ko\s+(.*\:.*)\s*$/,g=f?/^<\!--\s*\/ko\s*--\>$/:/^\s*\/ko\s*$/,i={ul:m,ol:m};r.f={C:{},childNodes:function(b){return a(b)?d(b):b.childNodes},ha:function(b){if(a(b))for(var b=r.f.childNodes(b),e=0,d=b.length;e<d;e++)r.removeNode(b[e]);else r.a.U(b)},oa:function(b,e){if(a(b)){r.f.ha(b);for(var d=b.nextSibling,f=0,g=e.length;f<g;f++)d.parentNode.insertBefore(e[f],d)}else r.a.oa(b,e)},xb:function(b,e){a(b)?b.parentNode.insertBefore(e,b.nextSibling):b.firstChild?b.insertBefore(e,b.firstChild):b.appendChild(e)},
|
||||
mb:function(b,e,d){a(b)?b.parentNode.insertBefore(e,d.nextSibling):d.nextSibling?b.insertBefore(e,d.nextSibling):b.appendChild(e)},nextSibling:function(d){return a(d)?e(d).nextSibling:d.nextSibling&&b(d.nextSibling)?l:d.nextSibling},ta:function(b){return(b=a(b))?b[1]:o},ib:function(a){if(r.f.ta(a)){var b;b=r.f.childNodes(a);for(var e=[],d=0,f=b.length;d<f;d++)r.a.A.F(b[d]),e.push(r.a.outerHTML(b[d]));b=String.prototype.concat.apply("",e);r.f.ha(a);(new r.m.I(a)).text(b)}},Fa:function(d){if(i[d.tagName.toLowerCase()]){var f=
|
||||
d.firstChild;if(f){do if(1===f.nodeType){var g;g=f.firstChild;var h=o;if(g){do if(h)h.push(g);else if(a(g)){var q=e(g,m);q?g=q:h=[g]}else b(g)&&(h=[g]);while(g=g.nextSibling)}if(g=h){h=f.nextSibling;for(q=0;q<g.length;q++)h?d.insertBefore(g[q],h):d.appendChild(g[q])}}while(f=f.nextSibling)}}}}})();r.L=function(){};
|
||||
r.a.extend(r.L.prototype,{nodeHasBindings:function(a){switch(a.nodeType){case 1:return a.getAttribute("data-bind")!=o;case 8:return r.f.ta(a)!=o;default:return p}},getBindings:function(a,b){var d=this.getBindingsString(a,b);return d?this.parseBindingsString(d,b):o},getBindingsString:function(a){switch(a.nodeType){case 1:return a.getAttribute("data-bind");case 8:return r.f.ta(a);default:return o}},parseBindingsString:function(a,b){try{var d=b.$data,e=" { "+r.j.ia(a)+" } ";return r.a.hb(e,d===o?window:
|
||||
d,b)}catch(f){c(Error("Unable to parse bindings.\nMessage: "+f+";\nBindings value: "+a))}}});r.L.instance=new r.L;r.b("ko.bindingProvider",r.L);
|
||||
(function(){function a(a,d){for(var h,g=d.childNodes[0];h=g;)g=r.f.nextSibling(h),b(a,h,p)}function b(b,f,h){var g=m,i=1==f.nodeType;i&&r.f.Fa(f);if(i&&h||r.L.instance.nodeHasBindings(f))g=d(f,o,b,h).Bb;i&&g&&a(b,f)}function d(a,b,d,g){function i(a){return function(){return n[a]}}function j(){return n}var k=0;r.f.ib(a);var n,t;new r.i(function(){var q=d&&d instanceof r.K?d:new r.K(r.a.d(d)),v=q.$data;g&&r.Na(a,q);if(n=("function"==typeof b?b():b)||r.L.instance.getBindings(a,q)){if(0===k){k=1;for(var s in n){var w=
|
||||
r.c[s];w&&8===a.nodeType&&!r.f.C[s]&&c(Error("The binding '"+s+"' cannot be used with virtual elements"));if(w&&"function"==typeof w.init&&(w=(0,w.init)(a,i(s),j,v,q))&&w.controlsDescendantBindings)t!==l&&c(Error("Multiple bindings ("+t+" and "+s+") are trying to control descendant bindings of the same element. You cannot use these bindings together on the same element.")),t=s}k=2}if(2===k)for(s in n)(w=r.c[s])&&"function"==typeof w.update&&(0,w.update)(a,i(s),j,v,q)}},o,{disposeWhenNodeIsRemoved:a});
|
||||
return{Bb:t===l}}r.c={};r.K=function(a,b){this.$data=a;b?(this.$parent=b.$data,this.$parents=(b.$parents||[]).slice(0),this.$parents.unshift(this.$parent),this.$root=b.$root):(this.$parents=[],this.$root=a)};r.K.prototype.createChildContext=function(a){return new r.K(a,this)};r.Na=function(a,b){if(2==arguments.length)r.a.e.set(a,"__ko_bindingContext__",b);else return r.a.e.get(a,"__ko_bindingContext__")};r.xa=function(a,b,h){1===a.nodeType&&r.f.Fa(a);return d(a,b,h,m)};r.Ta=function(b,d){1===d.nodeType&&
|
||||
a(b,d)};r.wa=function(a,d){d&&1!==d.nodeType&&8!==d.nodeType&&c(Error("ko.applyBindings: first parameter should be your view model; second parameter should be a DOM node"));d=d||window.document.body;b(a,d,m)};r.ea=function(a){switch(a.nodeType){case 1:case 8:var b=r.Na(a);if(b)return b;if(a.parentNode)return r.ea(a.parentNode)}};r.$a=function(a){return(a=r.ea(a))?a.$data:l};r.b("ko.bindingHandlers",r.c);r.b("ko.applyBindings",r.wa);r.b("ko.applyBindingsToDescendants",r.Ta);r.b("ko.applyBindingsToNode",
|
||||
r.xa);r.b("ko.contextFor",r.ea);r.b("ko.dataFor",r.$a)})();r.a.n(["click"],function(a){r.c[a]={init:function(b,d,e,f){return r.c.event.init.call(this,b,function(){var b={};b[a]=d();return b},e,f)}}});
|
||||
r.c.event={init:function(a,b,d,e){var f=b()||{},h;for(h in f)(function(){var f=h;"string"==typeof f&&r.a.s(a,f,function(a){var h,k=b()[f];if(k){var n=d();try{var t=r.a.X(arguments);t.unshift(e);h=k.apply(e,t)}finally{if(h!==m)a.preventDefault?a.preventDefault():a.returnValue=p}if(n[f+"Bubble"]===p)a.cancelBubble=m,a.stopPropagation&&a.stopPropagation()}})})()}};
|
||||
r.c.submit={init:function(a,b,d,e){"function"!=typeof b()&&c(Error("The value for a submit binding must be a function"));r.a.s(a,"submit",function(d){var h,g=b();try{h=g.call(e,a)}finally{if(h!==m)d.preventDefault?d.preventDefault():d.returnValue=p}})}};r.c.visible={update:function(a,b){var d=r.a.d(b()),e="none"!=a.style.display;if(d&&!e)a.style.display="";else if(!d&&e)a.style.display="none"}};
|
||||
r.c.enable={update:function(a,b){var d=r.a.d(b());if(d&&a.disabled)a.removeAttribute("disabled");else if(!d&&!a.disabled)a.disabled=m}};r.c.disable={update:function(a,b){r.c.enable.update(a,function(){return!r.a.d(b())})}};function D(a,b,d){d&&b!==r.h.q(a)&&r.h.S(a,b);b!==r.h.q(a)&&r.a.sa(a,"change")}
|
||||
r.c.value={init:function(a,b,d){var e=["change"],f=d().valueUpdate;f&&("string"==typeof f&&(f=[f]),r.a.J(e,f),e=r.a.ya(e));r.a.n(e,function(e){var f=p;r.a.Cb(e,"after")&&(f=m,e=e.substring(5));var i=f?function(a){setTimeout(a,0)}:function(a){a()};r.a.s(a,e,function(){i(function(){var e=b(),f=r.h.q(a);r.P(e)?e(f):(e=d(),e._ko_property_writers&&e._ko_property_writers.value&&e._ko_property_writers.value(f))})})})},update:function(a,b){var d=r.a.d(b()),e=r.h.q(a),f=d!=e;0===d&&0!==e&&"0"!==e&&(f=m);f&&
|
||||
(e=function(){r.h.S(a,d)},e(),"SELECT"==a.tagName&&setTimeout(e,0));"SELECT"==a.tagName&&0<a.length&&D(a,d,p)}};
|
||||
r.c.options={update:function(a,b,d){"SELECT"!=a.tagName&&c(Error("options binding applies only to SELECT elements"));var e=0==a.length,f=r.a.ba(r.a.aa(a.childNodes,function(a){return a.tagName&&"OPTION"==a.tagName&&a.selected}),function(a){return r.h.q(a)||a.innerText||a.textContent}),h=a.scrollTop;a.scrollTop=0;for(var g=r.a.d(b());0<a.length;)r.F(a.options[0]),a.remove(0);if(g){d=d();"number"!=typeof g.length&&(g=[g]);if(d.optionsCaption){var i=document.createElement("OPTION");r.a.Z(i,d.optionsCaption);
|
||||
r.h.S(i,l);a.appendChild(i)}for(var b=0,j=g.length;b<j;b++){var i=document.createElement("OPTION"),k="string"==typeof d.optionsValue?g[b][d.optionsValue]:g[b],k=r.a.d(k);r.h.S(i,k);var n=d.optionsText,k="function"==typeof n?n(g[b]):"string"==typeof n?g[b][n]:k;if(k===o||k===l)k="";r.a.Ma(i,k);a.appendChild(i)}g=a.getElementsByTagName("OPTION");b=i=0;for(j=g.length;b<j;b++)0<=r.a.k(f,r.h.q(g[b]))&&(r.a.La(g[b],m),i++);if(h)a.scrollTop=h;e&&"value"in d&&D(a,r.a.d(d.value),m)}}};r.c.options.la="__ko.optionValueDomData__";
|
||||
r.c.selectedOptions={Da:function(a){for(var b=[],a=a.childNodes,d=0,e=a.length;d<e;d++){var f=a[d];"OPTION"==f.tagName&&f.selected&&b.push(r.h.q(f))}return b},init:function(a,b,d){r.a.s(a,"change",function(){var a=b();r.P(a)?a(r.c.selectedOptions.Da(this)):(a=d(),a._ko_property_writers&&a._ko_property_writers.value&&a._ko_property_writers.value(r.c.selectedOptions.Da(this)))})},update:function(a,b){"SELECT"!=a.tagName&&c(Error("values binding applies only to SELECT elements"));var d=r.a.d(b());if(d&&
|
||||
"number"==typeof d.length)for(var e=a.childNodes,f=0,h=e.length;f<h;f++){var g=e[f];"OPTION"==g.tagName&&r.a.La(g,0<=r.a.k(d,r.h.q(g)))}}};r.c.text={update:function(a,b){r.a.Ma(a,b())}};r.c.html={init:function(){return{controlsDescendantBindings:m}},update:function(a,b){var d=r.a.d(b());r.a.Z(a,d)}};r.c.css={update:function(a,b){var d=r.a.d(b()||{}),e;for(e in d)if("string"==typeof e){var f=r.a.d(d[e]);r.a.Qa(a,e,f)}}};
|
||||
r.c.style={update:function(a,b){var d=r.a.d(b()||{}),e;for(e in d)if("string"==typeof e){var f=r.a.d(d[e]);a.style[e]=f||""}}};r.c.uniqueName={init:function(a,b){if(b())a.name="ko_unique_"+ ++r.c.uniqueName.Za,(r.a.ob||r.a.pb)&&a.mergeAttributes(document.createElement("<input name='"+a.name+"'/>"),p)}};r.c.uniqueName.Za=0;
|
||||
r.c.checked={init:function(a,b,d){r.a.s(a,"click",function(){var e;if("checkbox"==a.type)e=a.checked;else if("radio"==a.type&&a.checked)e=a.value;else return;var f=b();"checkbox"==a.type&&r.a.d(f)instanceof Array?(e=r.a.k(r.a.d(f),a.value),a.checked&&0>e?f.push(a.value):!a.checked&&0<=e&&f.splice(e,1)):r.P(f)?f()!==e&&f(e):(f=d(),f._ko_property_writers&&f._ko_property_writers.checked&&f._ko_property_writers.checked(e))});"radio"==a.type&&!a.name&&r.c.uniqueName.init(a,function(){return m})},update:function(a,
|
||||
b){var d=r.a.d(b());if("checkbox"==a.type)a.checked=d instanceof Array?0<=r.a.k(d,a.value):d;else if("radio"==a.type)a.checked=a.value==d}};r.c.attr={update:function(a,b){var d=r.a.d(b())||{},e;for(e in d)if("string"==typeof e){var f=r.a.d(d[e]);f===p||f===o||f===l?a.removeAttribute(e):a.setAttribute(e,f.toString())}}};
|
||||
r.c.hasfocus={init:function(a,b,d){function e(a){var e=b();a!=r.a.d(e)&&(r.P(e)?e(a):(e=d(),e._ko_property_writers&&e._ko_property_writers.hasfocus&&e._ko_property_writers.hasfocus(a)))}r.a.s(a,"focus",function(){e(m)});r.a.s(a,"focusin",function(){e(m)});r.a.s(a,"blur",function(){e(p)});r.a.s(a,"focusout",function(){e(p)})},update:function(a,b){var d=r.a.d(b());d?a.focus():a.blur();r.a.sa(a,d?"focusin":"focusout")}};
|
||||
r.c["with"]={o:function(a){return function(){var b=a();return{"if":b,data:b,templateEngine:r.p.M}}},init:function(a,b){return r.c.template.init(a,r.c["with"].o(b))},update:function(a,b,d,e,f){return r.c.template.update(a,r.c["with"].o(b),d,e,f)}};r.j.D["with"]=p;r.f.C["with"]=m;r.c["if"]={o:function(a){return function(){return{"if":a(),templateEngine:r.p.M}}},init:function(a,b){return r.c.template.init(a,r.c["if"].o(b))},update:function(a,b,d,e,f){return r.c.template.update(a,r.c["if"].o(b),d,e,f)}};
|
||||
r.j.D["if"]=p;r.f.C["if"]=m;r.c.ifnot={o:function(a){return function(){return{ifnot:a(),templateEngine:r.p.M}}},init:function(a,b){return r.c.template.init(a,r.c.ifnot.o(b))},update:function(a,b,d,e,f){return r.c.template.update(a,r.c.ifnot.o(b),d,e,f)}};r.j.D.ifnot=p;r.f.C.ifnot=m;
|
||||
r.c.foreach={o:function(a){return function(){var b=r.a.d(a());return!b||"number"==typeof b.length?{foreach:b,templateEngine:r.p.M}:{foreach:b.data,includeDestroyed:b.includeDestroyed,afterAdd:b.afterAdd,beforeRemove:b.beforeRemove,afterRender:b.afterRender,templateEngine:r.p.M}}},init:function(a,b){return r.c.template.init(a,r.c.foreach.o(b))},update:function(a,b,d,e,f){return r.c.template.update(a,r.c.foreach.o(b),d,e,f)}};r.j.D.foreach=p;r.f.C.foreach=m;r.b("ko.allowedVirtualElementBindings",r.f.C);
|
||||
r.t=function(){};r.t.prototype.renderTemplateSource=function(){c("Override renderTemplateSource")};r.t.prototype.createJavaScriptEvaluatorBlock=function(){c("Override createJavaScriptEvaluatorBlock")};r.t.prototype.makeTemplateSource=function(a){if("string"==typeof a){var b=document.getElementById(a);b||c(Error("Cannot find template with ID "+a));return new r.m.g(b)}if(1==a.nodeType||8==a.nodeType)return new r.m.I(a);c(Error("Unknown template type: "+a))};
|
||||
r.t.prototype.renderTemplate=function(a,b,d){return this.renderTemplateSource(this.makeTemplateSource(a),b,d)};r.t.prototype.isTemplateRewritten=function(a){return this.allowTemplateRewriting===p?m:this.W&&this.W[a]?m:this.makeTemplateSource(a).data("isRewritten")};r.t.prototype.rewriteTemplate=function(a,b){var d=this.makeTemplateSource(a),e=b(d.text());d.text(e);d.data("isRewritten",m);if("string"==typeof a)this.W=this.W||{},this.W[a]=m};r.b("ko.templateEngine",r.t);
|
||||
r.$=function(){function a(a,b,d){for(var a=r.j.Y(a),g=r.j.D,i=0;i<a.length;i++){var j=a[i].key;if(g.hasOwnProperty(j)){var k=g[j];"function"===typeof k?(j=k(a[i].value))&&c(Error(j)):k||c(Error("This template engine does not support the '"+j+"' binding within its templates"))}}a="ko.templateRewriting.applyMemoizedBindingsToNextSibling(function() { return (function() { return { "+r.j.ia(a)+" } })() })";return d.createJavaScriptEvaluatorBlock(a)+b}var b=/(<[a-z]+\d*(\s+(?!data-bind=)[a-z0-9\-]+(=(\"[^\"]*\"|\'[^\']*\'))?)*\s+)data-bind=(["'])([\s\S]*?)\5/gi,
|
||||
d=/<\!--\s*ko\b\s*([\s\S]*?)\s*--\>/g;return{gb:function(a,b){b.isTemplateRewritten(a)||b.rewriteTemplate(a,function(a){return r.$.ub(a,b)})},ub:function(e,f){return e.replace(b,function(b,e,d,j,k,n,t){return a(t,e,f)}).replace(d,function(b,e){return a(e,"<\!-- ko --\>",f)})},Ua:function(a){return r.r.ka(function(b,d){b.nextSibling&&r.xa(b.nextSibling,a,d)})}}}();r.b("ko.templateRewriting",r.$);r.b("ko.templateRewriting.applyMemoizedBindingsToNextSibling",r.$.Ua);r.m={};r.m.g=function(a){this.g=a};
|
||||
r.m.g.prototype.text=function(){if(0==arguments.length)return"script"==this.g.tagName.toLowerCase()?this.g.text:this.g.innerHTML;var a=arguments[0];"script"==this.g.tagName.toLowerCase()?this.g.text=a:r.a.Z(this.g,a)};r.m.g.prototype.data=function(a){if(1===arguments.length)return r.a.e.get(this.g,"templateSourceData_"+a);r.a.e.set(this.g,"templateSourceData_"+a,arguments[1])};r.m.I=function(a){this.g=a};r.m.I.prototype=new r.m.g;
|
||||
r.m.I.prototype.text=function(){if(0==arguments.length)return r.a.e.get(this.g,"__ko_anon_template__");r.a.e.set(this.g,"__ko_anon_template__",arguments[0])};r.b("ko.templateSources",r.m);r.b("ko.templateSources.domElement",r.m.g);r.b("ko.templateSources.anonymousTemplate",r.m.I);
|
||||
(function(){function a(a,b,d){for(var g=0;node=a[g];g++)node.parentNode===b&&(1===node.nodeType||8===node.nodeType)&&d(node)}function b(a,b,h,g,i){var i=i||{},j=i.templateEngine||d;r.$.gb(h,j);h=j.renderTemplate(h,g,i);("number"!=typeof h.length||0<h.length&&"number"!=typeof h[0].nodeType)&&c("Template engine must return an array of DOM nodes");j=p;switch(b){case "replaceChildren":r.f.oa(a,h);j=m;break;case "replaceNode":r.a.Ja(a,h);j=m;break;case "ignoreTargetNode":break;default:c(Error("Unknown renderMode: "+
|
||||
b))}j&&(r.ua(h,g),i.afterRender&&i.afterRender(h,g.$data));return h}var d;r.pa=function(a){a!=l&&!(a instanceof r.t)&&c("templateEngine must inherit from ko.templateEngine");d=a};r.ua=function(b,d){var h=r.a.J([],b),g=0<b.length?b[0].parentNode:o;a(h,g,function(a){r.wa(d,a)});a(h,g,function(a){r.r.Sa(a,[d])})};r.na=function(a,f,h,g,i){h=h||{};(h.templateEngine||d)==l&&c("Set a template engine before calling renderTemplate");i=i||"replaceChildren";if(g){var j=g.nodeType?g:0<g.length?g[0]:o;return new r.i(function(){var d=
|
||||
f&&f instanceof r.K?f:new r.K(r.a.d(f)),n="function"==typeof a?a(d.$data):a,d=b(g,i,n,d,h);"replaceNode"==i&&(g=d,j=g.nodeType?g:0<g.length?g[0]:o)},o,{disposeWhen:function(){return!j||!r.a.ga(j)},disposeWhenNodeIsRemoved:j&&"replaceNode"==i?j.parentNode:j})}return r.r.ka(function(b){r.na(a,f,h,b,"replaceNode")})};r.Ab=function(a,d,h,g,i){function j(a,b){var d=k(a);r.ua(b,d);h.afterRender&&h.afterRender(b,d.$data)}function k(a){return i.createChildContext(r.a.d(a))}return new r.i(function(){var i=
|
||||
r.a.d(d)||[];"undefined"==typeof i.length&&(i=[i]);i=r.a.aa(i,function(a){return h.includeDestroyed||a===l||a===o||!r.a.d(a._destroy)});r.a.Ka(g,i,function(d){var f="function"==typeof a?a(d):a;return b(o,"ignoreTargetNode",f,k(d),h)},h,j)},o,{disposeWhenNodeIsRemoved:g})};r.c.template={init:function(a,b){var d=r.a.d(b());"string"!=typeof d&&!d.name&&1==a.nodeType&&((new r.m.I(a)).text(a.innerHTML),r.a.U(a));return{controlsDescendantBindings:m}},update:function(a,b,d,g,i){b=r.a.d(b());g=m;"string"==
|
||||
typeof b?d=b:(d=b.name,"if"in b&&(g=g&&r.a.d(b["if"])),"ifnot"in b&&(g=g&&!r.a.d(b.ifnot)));var j=o;"object"===typeof b&&"foreach"in b?j=r.Ab(d||a,g&&b.foreach||[],b,a,i):g?(i="object"==typeof b&&"data"in b?i.createChildContext(r.a.d(b.data)):i,j=r.na(d||a,i,b,a)):r.f.ha(a);i=j;(b=r.a.e.get(a,"__ko__templateSubscriptionDomDataKey__"))&&"function"==typeof b.v&&b.v();r.a.e.set(a,"__ko__templateSubscriptionDomDataKey__",i)}};r.j.D.template=function(a){a=r.j.Y(a);return 1==a.length&&a[0].unknown?o:r.j.rb(a,
|
||||
"name")?o:"This template engine does not support anonymous templates nested within its templates"};r.f.C.template=m})();r.b("ko.setTemplateEngine",r.pa);r.b("ko.renderTemplate",r.na);
|
||||
r.a.N=function(a,b,d){if(d===l)return r.a.N(a,b,1)||r.a.N(a,b,10)||r.a.N(a,b,Number.MAX_VALUE);for(var a=a||[],b=b||[],e=a,f=b,h=[],g=0;g<=f.length;g++)h[g]=[];for(var g=0,i=Math.min(e.length,d);g<=i;g++)h[0][g]=g;g=1;for(i=Math.min(f.length,d);g<=i;g++)h[g][0]=g;for(var i=e.length,j,k=f.length,g=1;g<=i;g++){j=Math.max(1,g-d);for(var n=Math.min(k,g+d);j<=n;j++)h[j][g]=e[g-1]===f[j-1]?h[j-1][g-1]:Math.min(h[j-1][g]===l?Number.MAX_VALUE:h[j-1][g]+1,h[j][g-1]===l?Number.MAX_VALUE:h[j][g-1]+1)}d=a.length;
|
||||
e=b.length;f=[];g=h[e][d];if(g===l)h=o;else{for(;0<d||0<e;){i=h[e][d];k=0<e?h[e-1][d]:g+1;n=0<d?h[e][d-1]:g+1;j=0<e&&0<d?h[e-1][d-1]:g+1;if(k===l||k<i-1)k=g+1;if(n===l||n<i-1)n=g+1;j<i-1&&(j=g+1);k<=n&&k<j?(f.push({status:"added",value:b[e-1]}),e--):(n<k&&n<j?f.push({status:"deleted",value:a[d-1]}):(f.push({status:"retained",value:a[d-1]}),e--),d--)}h=f.reverse()}return h};r.b("ko.utils.compareArrays",r.a.N);
|
||||
(function(){function a(a){if(2<a.length){for(var b=a[0],f=a[a.length-1],h=[b];b!==f;){b=b.nextSibling;if(!b)return;h.push(b)}Array.prototype.splice.apply(a,[0,a.length].concat(h))}}function b(b,e,f,h){var g=[],b=r.i(function(){var b=e(f)||[];0<g.length&&(a(g),r.a.Ja(g,b),h&&h(f,b));g.splice(0,g.length);r.a.J(g,b)},o,{disposeWhenNodeIsRemoved:b,disposeWhen:function(){return 0==g.length||!r.a.ga(g[0])}});return{sb:g,i:b}}r.a.Ka=function(d,e,f,h,g){for(var e=e||[],h=h||{},i=r.a.e.get(d,"setDomNodeChildrenFromArrayMapping_lastMappingResult")===
|
||||
l,j=r.a.e.get(d,"setDomNodeChildrenFromArrayMapping_lastMappingResult")||[],k=r.a.ba(j,function(a){return a.Va}),n=r.a.N(k,e),e=[],t=0,q=[],k=[],v=o,s=0,w=n.length;s<w;s++)switch(n[s].status){case "retained":var x=j[t];e.push(x);0<x.O.length&&(v=x.O[x.O.length-1]);t++;break;case "deleted":j[t].i.v();a(j[t].O);r.a.n(j[t].O,function(a){q.push({element:a,index:s,value:n[s].value});v=a});t++;break;case "added":var x=n[s].value,z=b(d,f,x,g),u=z.sb;e.push({Va:n[s].value,O:u,i:z.i});for(var z=0,y=u.length;z<
|
||||
y;z++){var A=u[z];k.push({element:A,index:s,value:n[s].value});v==o?r.f.xb(d,A):r.f.mb(d,A,v);v=A}g&&g(x,u)}r.a.n(q,function(a){r.F(a.element)});f=p;if(!i){if(h.afterAdd)for(s=0;s<k.length;s++)h.afterAdd(k[s].element,k[s].index,k[s].value);if(h.beforeRemove){for(s=0;s<q.length;s++)h.beforeRemove(q[s].element,q[s].index,q[s].value);f=m}}f||r.a.n(q,function(a){r.removeNode(a.element)});r.a.e.set(d,"setDomNodeChildrenFromArrayMapping_lastMappingResult",e)}})();
|
||||
r.b("ko.utils.setDomNodeChildrenFromArrayMapping",r.a.Ka);r.p=function(){this.allowTemplateRewriting=p};r.p.prototype=new r.t;r.p.prototype.renderTemplateSource=function(a){a=a.text();return r.a.ma(a)};r.p.M=new r.p;r.pa(r.p.M);r.b("ko.nativeTemplateEngine",r.p);
|
||||
(function(){r.ja=function(){var a=this.qb=function(){if("undefined"==typeof jQuery||!jQuery.tmpl)return 0;try{if(0<=jQuery.tmpl.tag.tmpl.open.toString().indexOf("__"))return 2}catch(a){}return 1}();this.renderTemplateSource=function(d,e,f){f=f||{};2>a&&c(Error("Your version of jQuery.tmpl is too old. Please upgrade to jQuery.tmpl 1.0.0pre or later."));var h=d.data("precompiled");h||(h=d.text()||"",h=jQuery.template(o,"{{ko_with $item.koBindingContext}}"+h+"{{/ko_with}}"),d.data("precompiled",h));
|
||||
d=[e.$data];e=jQuery.extend({koBindingContext:e},f.templateOptions);e=jQuery.tmpl(h,d,e);e.appendTo(document.createElement("div"));jQuery.fragments={};return e};this.createJavaScriptEvaluatorBlock=function(a){return"{{ko_code ((function() { return "+a+" })()) }}"};this.addTemplate=function(a,b){document.write("<script type='text/html' id='"+a+"'>"+b+"<\/script>")};if(0<a)jQuery.tmpl.tag.ko_code={open:"__.push($1 || '');"},jQuery.tmpl.tag.ko_with={open:"with($1) {",close:"} "}};r.ja.prototype=new r.t;
|
||||
var a=new r.ja;0<a.qb&&r.pa(a);r.b("ko.jqueryTmplTemplateEngine",r.ja)})();
|
||||
})(window);
|
976
bench/markermanager.js
Normal file
976
bench/markermanager.js
Normal file
@ -0,0 +1,976 @@
|
||||
/**
|
||||
* @name MarkerManager v3
|
||||
* @version 1.0
|
||||
* @copyright (c) 2007 Google Inc.
|
||||
* @author Doug Ricket, Bjorn Brala (port to v3), others,
|
||||
*
|
||||
* @fileoverview Marker manager is an interface between the map and the user,
|
||||
* designed to manage adding and removing many points when the viewport changes.
|
||||
* <br /><br />
|
||||
* <b>How it Works</b>:<br/>
|
||||
* The MarkerManager places its markers onto a grid, similar to the map tiles.
|
||||
* When the user moves the viewport, it computes which grid cells have
|
||||
* entered or left the viewport, and shows or hides all the markers in those
|
||||
* cells.
|
||||
* (If the users scrolls the viewport beyond the markers that are loaded,
|
||||
* no markers will be visible until the <code>EVENT_moveend</code>
|
||||
* triggers an update.)
|
||||
* In practical consequences, this allows 10,000 markers to be distributed over
|
||||
* a large area, and as long as only 100-200 are visible in any given viewport,
|
||||
* the user will see good performance corresponding to the 100 visible markers,
|
||||
* rather than poor performance corresponding to the total 10,000 markers.
|
||||
* Note that some code is optimized for speed over space,
|
||||
* with the goal of accommodating thousands of markers.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @name MarkerManagerOptions
|
||||
* @class This class represents optional arguments to the {@link MarkerManager}
|
||||
* constructor.
|
||||
* @property {Number} maxZoom Sets the maximum zoom level monitored by a
|
||||
* marker manager. If not given, the manager assumes the maximum map zoom
|
||||
* level. This value is also used when markers are added to the manager
|
||||
* without the optional {@link maxZoom} parameter.
|
||||
* @property {Number} borderPadding Specifies, in pixels, the extra padding
|
||||
* outside the map's current viewport monitored by a manager. Markers that
|
||||
* fall within this padding are added to the map, even if they are not fully
|
||||
* visible.
|
||||
* @property {Boolean} trackMarkers=false Indicates whether or not a marker
|
||||
* manager should track markers' movements. If you wish to move managed
|
||||
* markers using the {@link setPoint}/{@link setLatLng} methods,
|
||||
* this option should be set to {@link true}.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Creates a new MarkerManager that will show/hide markers on a map.
|
||||
*
|
||||
* Events:
|
||||
* @event changed (Parameters: shown bounds, shown markers) Notify listeners when the state of what is displayed changes.
|
||||
* @event loaded MarkerManager has succesfully been initialized.
|
||||
*
|
||||
* @constructor
|
||||
* @param {Map} map The map to manage.
|
||||
* @param {Object} opt_opts A container for optional arguments:
|
||||
* {Number} maxZoom The maximum zoom level for which to create tiles.
|
||||
* {Number} borderPadding The width in pixels beyond the map border,
|
||||
* where markers should be display.
|
||||
* {Boolean} trackMarkers Whether or not this manager should track marker
|
||||
* movements.
|
||||
*/
|
||||
function MarkerManager(map, opt_opts) {
|
||||
var me = this;
|
||||
me.map_ = map;
|
||||
me.mapZoom_ = map.getZoom();
|
||||
|
||||
me.projectionHelper_ = new ProjectionHelperOverlay(map);
|
||||
google.maps.event.addListener(me.projectionHelper_, 'ready', function () {
|
||||
me.projection_ = this.getProjection();
|
||||
me.initialize(map, opt_opts);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
MarkerManager.prototype.initialize = function (map, opt_opts) {
|
||||
var me = this;
|
||||
|
||||
opt_opts = opt_opts || {};
|
||||
me.tileSize_ = MarkerManager.DEFAULT_TILE_SIZE_;
|
||||
|
||||
var mapTypes = map.mapTypes;
|
||||
|
||||
// Find max zoom level
|
||||
var mapMaxZoom = 1;
|
||||
for (var sType in mapTypes ) {
|
||||
if (typeof map.mapTypes.get(sType) === 'object' && typeof map.mapTypes.get(sType).maxZoom === 'number') {
|
||||
var mapTypeMaxZoom = map.mapTypes.get(sType).maxZoom;
|
||||
if (mapTypeMaxZoom > mapMaxZoom) {
|
||||
mapMaxZoom = mapTypeMaxZoom;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
me.maxZoom_ = opt_opts.maxZoom || 19;
|
||||
|
||||
me.trackMarkers_ = opt_opts.trackMarkers;
|
||||
me.show_ = opt_opts.show || true;
|
||||
|
||||
var padding;
|
||||
if (typeof opt_opts.borderPadding === 'number') {
|
||||
padding = opt_opts.borderPadding;
|
||||
} else {
|
||||
padding = MarkerManager.DEFAULT_BORDER_PADDING_;
|
||||
}
|
||||
// The padding in pixels beyond the viewport, where we will pre-load markers.
|
||||
me.swPadding_ = new google.maps.Size(-padding, padding);
|
||||
me.nePadding_ = new google.maps.Size(padding, -padding);
|
||||
me.borderPadding_ = padding;
|
||||
|
||||
me.gridWidth_ = {};
|
||||
|
||||
me.grid_ = {};
|
||||
me.grid_[me.maxZoom_] = {};
|
||||
me.numMarkers_ = {};
|
||||
me.numMarkers_[me.maxZoom_] = 0;
|
||||
|
||||
|
||||
google.maps.event.addListener(map, 'dragend', function () {
|
||||
me.onMapMoveEnd_();
|
||||
});
|
||||
google.maps.event.addListener(map, 'zoom_changed', function () {
|
||||
me.onMapMoveEnd_();
|
||||
});
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* This closure provide easy access to the map.
|
||||
* They are used as callbacks, not as methods.
|
||||
* @param GMarker marker Marker to be removed from the map
|
||||
* @private
|
||||
*/
|
||||
me.removeOverlay_ = function (marker) {
|
||||
marker.setMap(null);
|
||||
me.shownMarkers_--;
|
||||
};
|
||||
|
||||
/**
|
||||
* This closure provide easy access to the map.
|
||||
* They are used as callbacks, not as methods.
|
||||
* @param GMarker marker Marker to be added to the map
|
||||
* @private
|
||||
*/
|
||||
me.addOverlay_ = function (marker) {
|
||||
if (me.show_) {
|
||||
marker.setMap(me.map_);
|
||||
me.shownMarkers_++;
|
||||
}
|
||||
};
|
||||
|
||||
me.resetManager_();
|
||||
me.shownMarkers_ = 0;
|
||||
|
||||
me.shownBounds_ = me.getMapGridBounds_();
|
||||
|
||||
google.maps.event.trigger(me, 'loaded');
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* Default tile size used for deviding the map into a grid.
|
||||
*/
|
||||
MarkerManager.DEFAULT_TILE_SIZE_ = 1024;
|
||||
|
||||
/*
|
||||
* How much extra space to show around the map border so
|
||||
* dragging doesn't result in an empty place.
|
||||
*/
|
||||
MarkerManager.DEFAULT_BORDER_PADDING_ = 100;
|
||||
|
||||
/**
|
||||
* Default tilesize of single tile world.
|
||||
*/
|
||||
MarkerManager.MERCATOR_ZOOM_LEVEL_ZERO_RANGE = 256;
|
||||
|
||||
|
||||
/**
|
||||
* Initializes MarkerManager arrays for all zoom levels
|
||||
* Called by constructor and by clearAllMarkers
|
||||
*/
|
||||
MarkerManager.prototype.resetManager_ = function () {
|
||||
var mapWidth = MarkerManager.MERCATOR_ZOOM_LEVEL_ZERO_RANGE;
|
||||
for (var zoom = 0; zoom <= this.maxZoom_; ++zoom) {
|
||||
this.grid_[zoom] = {};
|
||||
this.numMarkers_[zoom] = 0;
|
||||
this.gridWidth_[zoom] = Math.ceil(mapWidth / this.tileSize_);
|
||||
mapWidth <<= 1;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* Removes all markers in the manager, and
|
||||
* removes any visible markers from the map.
|
||||
*/
|
||||
MarkerManager.prototype.clearMarkers = function () {
|
||||
this.processAll_(this.shownBounds_, this.removeOverlay_);
|
||||
this.resetManager_();
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Gets the tile coordinate for a given latlng point.
|
||||
*
|
||||
* @param {LatLng} latlng The geographical point.
|
||||
* @param {Number} zoom The zoom level.
|
||||
* @param {google.maps.Size} padding The padding used to shift the pixel coordinate.
|
||||
* Used for expanding a bounds to include an extra padding
|
||||
* of pixels surrounding the bounds.
|
||||
* @return {GPoint} The point in tile coordinates.
|
||||
*
|
||||
*/
|
||||
MarkerManager.prototype.getTilePoint_ = function (latlng, zoom, padding) {
|
||||
|
||||
var pixelPoint = this.projectionHelper_.LatLngToPixel(latlng, zoom);
|
||||
|
||||
var point = new google.maps.Point(
|
||||
Math.floor((pixelPoint.x + padding.width) / this.tileSize_),
|
||||
Math.floor((pixelPoint.y + padding.height) / this.tileSize_)
|
||||
);
|
||||
|
||||
return point;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Finds the appropriate place to add the marker to the grid.
|
||||
* Optimized for speed; does not actually add the marker to the map.
|
||||
* Designed for batch-processing thousands of markers.
|
||||
*
|
||||
* @param {Marker} marker The marker to add.
|
||||
* @param {Number} minZoom The minimum zoom for displaying the marker.
|
||||
* @param {Number} maxZoom The maximum zoom for displaying the marker.
|
||||
*/
|
||||
MarkerManager.prototype.addMarkerBatch_ = function (marker, minZoom, maxZoom) {
|
||||
var me = this;
|
||||
|
||||
var mPoint = marker.getPosition();
|
||||
marker.MarkerManager_minZoom = minZoom;
|
||||
|
||||
|
||||
// Tracking markers is expensive, so we do this only if the
|
||||
// user explicitly requested it when creating marker manager.
|
||||
if (this.trackMarkers_) {
|
||||
google.maps.event.addListener(marker, 'changed', function (a, b, c) {
|
||||
me.onMarkerMoved_(a, b, c);
|
||||
});
|
||||
}
|
||||
|
||||
var gridPoint = this.getTilePoint_(mPoint, maxZoom, new google.maps.Size(0, 0, 0, 0));
|
||||
|
||||
for (var zoom = maxZoom; zoom >= minZoom; zoom--) {
|
||||
var cell = this.getGridCellCreate_(gridPoint.x, gridPoint.y, zoom);
|
||||
cell.push(marker);
|
||||
|
||||
gridPoint.x = gridPoint.x >> 1;
|
||||
gridPoint.y = gridPoint.y >> 1;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Returns whether or not the given point is visible in the shown bounds. This
|
||||
* is a helper method that takes care of the corner case, when shownBounds have
|
||||
* negative minX value.
|
||||
*
|
||||
* @param {Point} point a point on a grid.
|
||||
* @return {Boolean} Whether or not the given point is visible in the currently
|
||||
* shown bounds.
|
||||
*/
|
||||
MarkerManager.prototype.isGridPointVisible_ = function (point) {
|
||||
var vertical = this.shownBounds_.minY <= point.y &&
|
||||
point.y <= this.shownBounds_.maxY;
|
||||
var minX = this.shownBounds_.minX;
|
||||
var horizontal = minX <= point.x && point.x <= this.shownBounds_.maxX;
|
||||
if (!horizontal && minX < 0) {
|
||||
// Shifts the negative part of the rectangle. As point.x is always less
|
||||
// than grid width, only test shifted minX .. 0 part of the shown bounds.
|
||||
var width = this.gridWidth_[this.shownBounds_.z];
|
||||
horizontal = minX + width <= point.x && point.x <= width - 1;
|
||||
}
|
||||
return vertical && horizontal;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Reacts to a notification from a marker that it has moved to a new location.
|
||||
* It scans the grid all all zoom levels and moves the marker from the old grid
|
||||
* location to a new grid location.
|
||||
*
|
||||
* @param {Marker} marker The marker that moved.
|
||||
* @param {LatLng} oldPoint The old position of the marker.
|
||||
* @param {LatLng} newPoint The new position of the marker.
|
||||
*/
|
||||
MarkerManager.prototype.onMarkerMoved_ = function (marker, oldPoint, newPoint) {
|
||||
// NOTE: We do not know the minimum or maximum zoom the marker was
|
||||
// added at, so we start at the absolute maximum. Whenever we successfully
|
||||
// remove a marker at a given zoom, we add it at the new grid coordinates.
|
||||
var zoom = this.maxZoom_;
|
||||
var changed = false;
|
||||
var oldGrid = this.getTilePoint_(oldPoint, zoom, new google.maps.Size(0, 0, 0, 0));
|
||||
var newGrid = this.getTilePoint_(newPoint, zoom, new google.maps.Size(0, 0, 0, 0));
|
||||
while (zoom >= 0 && (oldGrid.x !== newGrid.x || oldGrid.y !== newGrid.y)) {
|
||||
var cell = this.getGridCellNoCreate_(oldGrid.x, oldGrid.y, zoom);
|
||||
if (cell) {
|
||||
if (this.removeFromArray_(cell, marker)) {
|
||||
this.getGridCellCreate_(newGrid.x, newGrid.y, zoom).push(marker);
|
||||
}
|
||||
}
|
||||
// For the current zoom we also need to update the map. Markers that no
|
||||
// longer are visible are removed from the map. Markers that moved into
|
||||
// the shown bounds are added to the map. This also lets us keep the count
|
||||
// of visible markers up to date.
|
||||
if (zoom === this.mapZoom_) {
|
||||
if (this.isGridPointVisible_(oldGrid)) {
|
||||
if (!this.isGridPointVisible_(newGrid)) {
|
||||
this.removeOverlay_(marker);
|
||||
changed = true;
|
||||
}
|
||||
} else {
|
||||
if (this.isGridPointVisible_(newGrid)) {
|
||||
this.addOverlay_(marker);
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
oldGrid.x = oldGrid.x >> 1;
|
||||
oldGrid.y = oldGrid.y >> 1;
|
||||
newGrid.x = newGrid.x >> 1;
|
||||
newGrid.y = newGrid.y >> 1;
|
||||
--zoom;
|
||||
}
|
||||
if (changed) {
|
||||
this.notifyListeners_();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Removes marker from the manager and from the map
|
||||
* (if it's currently visible).
|
||||
* @param {GMarker} marker The marker to delete.
|
||||
*/
|
||||
MarkerManager.prototype.removeMarker = function (marker) {
|
||||
var zoom = this.maxZoom_;
|
||||
var changed = false;
|
||||
var point = marker.getPosition();
|
||||
var grid = this.getTilePoint_(point, zoom, new google.maps.Size(0, 0, 0, 0));
|
||||
while (zoom >= 0) {
|
||||
var cell = this.getGridCellNoCreate_(grid.x, grid.y, zoom);
|
||||
|
||||
if (cell) {
|
||||
this.removeFromArray_(cell, marker);
|
||||
}
|
||||
// For the current zoom we also need to update the map. Markers that no
|
||||
// longer are visible are removed from the map. This also lets us keep the count
|
||||
// of visible markers up to date.
|
||||
if (zoom === this.mapZoom_) {
|
||||
if (this.isGridPointVisible_(grid)) {
|
||||
this.removeOverlay_(marker);
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
grid.x = grid.x >> 1;
|
||||
grid.y = grid.y >> 1;
|
||||
--zoom;
|
||||
}
|
||||
if (changed) {
|
||||
this.notifyListeners_();
|
||||
}
|
||||
this.numMarkers_[marker.MarkerManager_minZoom]--;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Add many markers at once.
|
||||
* Does not actually update the map, just the internal grid.
|
||||
*
|
||||
* @param {Array of Marker} markers The markers to add.
|
||||
* @param {Number} minZoom The minimum zoom level to display the markers.
|
||||
* @param {Number} opt_maxZoom The maximum zoom level to display the markers.
|
||||
*/
|
||||
MarkerManager.prototype.addMarkers = function (markers, minZoom, opt_maxZoom) {
|
||||
var maxZoom = this.getOptMaxZoom_(opt_maxZoom);
|
||||
for (var i = markers.length - 1; i >= 0; i--) {
|
||||
this.addMarkerBatch_(markers[i], minZoom, maxZoom);
|
||||
}
|
||||
|
||||
this.numMarkers_[minZoom] += markers.length;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Returns the value of the optional maximum zoom. This method is defined so
|
||||
* that we have just one place where optional maximum zoom is calculated.
|
||||
*
|
||||
* @param {Number} opt_maxZoom The optinal maximum zoom.
|
||||
* @return The maximum zoom.
|
||||
*/
|
||||
MarkerManager.prototype.getOptMaxZoom_ = function (opt_maxZoom) {
|
||||
return opt_maxZoom || this.maxZoom_;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Calculates the total number of markers potentially visible at a given
|
||||
* zoom level.
|
||||
*
|
||||
* @param {Number} zoom The zoom level to check.
|
||||
*/
|
||||
MarkerManager.prototype.getMarkerCount = function (zoom) {
|
||||
var total = 0;
|
||||
for (var z = 0; z <= zoom; z++) {
|
||||
total += this.numMarkers_[z];
|
||||
}
|
||||
return total;
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns a marker given latitude, longitude and zoom. If the marker does not
|
||||
* exist, the method will return a new marker. If a new marker is created,
|
||||
* it will NOT be added to the manager.
|
||||
*
|
||||
* @param {Number} lat - the latitude of a marker.
|
||||
* @param {Number} lng - the longitude of a marker.
|
||||
* @param {Number} zoom - the zoom level
|
||||
* @return {GMarker} marker - the marker found at lat and lng
|
||||
*/
|
||||
MarkerManager.prototype.getMarker = function (lat, lng, zoom) {
|
||||
var mPoint = new google.maps.LatLng(lat, lng);
|
||||
var gridPoint = this.getTilePoint_(mPoint, zoom, new google.maps.Size(0, 0, 0, 0));
|
||||
|
||||
var marker = new google.maps.Marker({position: mPoint});
|
||||
|
||||
var cellArray = this.getGridCellNoCreate_(gridPoint.x, gridPoint.y, zoom);
|
||||
if (cellArray !== undefined) {
|
||||
for (var i = 0; i < cellArray.length; i++)
|
||||
{
|
||||
if (lat === cellArray[i].getLatLng().lat() && lng === cellArray[i].getLatLng().lng()) {
|
||||
marker = cellArray[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
return marker;
|
||||
};
|
||||
|
||||
/**
|
||||
* Add a single marker to the map.
|
||||
*
|
||||
* @param {Marker} marker The marker to add.
|
||||
* @param {Number} minZoom The minimum zoom level to display the marker.
|
||||
* @param {Number} opt_maxZoom The maximum zoom level to display the marker.
|
||||
*/
|
||||
MarkerManager.prototype.addMarker = function (marker, minZoom, opt_maxZoom) {
|
||||
var maxZoom = this.getOptMaxZoom_(opt_maxZoom);
|
||||
this.addMarkerBatch_(marker, minZoom, maxZoom);
|
||||
var gridPoint = this.getTilePoint_(marker.getPosition(), this.mapZoom_, new google.maps.Size(0, 0, 0, 0));
|
||||
if (this.isGridPointVisible_(gridPoint) &&
|
||||
minZoom <= this.shownBounds_.z &&
|
||||
this.shownBounds_.z <= maxZoom) {
|
||||
this.addOverlay_(marker);
|
||||
this.notifyListeners_();
|
||||
}
|
||||
this.numMarkers_[minZoom]++;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Helper class to create a bounds of INT ranges.
|
||||
* @param bounds Array.<Object.<string, number>> Bounds object.
|
||||
* @constructor
|
||||
*/
|
||||
function GridBounds(bounds) {
|
||||
// [sw, ne]
|
||||
|
||||
this.minX = Math.min(bounds[0].x, bounds[1].x);
|
||||
this.maxX = Math.max(bounds[0].x, bounds[1].x);
|
||||
this.minY = Math.min(bounds[0].y, bounds[1].y);
|
||||
this.maxY = Math.max(bounds[0].y, bounds[1].y);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if this bounds equal the given bounds.
|
||||
* @param {GridBounds} gridBounds GridBounds The bounds to test.
|
||||
* @return {Boolean} This Bounds equals the given GridBounds.
|
||||
*/
|
||||
GridBounds.prototype.equals = function (gridBounds) {
|
||||
if (this.maxX === gridBounds.maxX && this.maxY === gridBounds.maxY && this.minX === gridBounds.minX && this.minY === gridBounds.minY) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns true if this bounds (inclusively) contains the given point.
|
||||
* @param {Point} point The point to test.
|
||||
* @return {Boolean} This Bounds contains the given Point.
|
||||
*/
|
||||
GridBounds.prototype.containsPoint = function (point) {
|
||||
var outer = this;
|
||||
return (outer.minX <= point.x && outer.maxX >= point.x && outer.minY <= point.y && outer.maxY >= point.y);
|
||||
};
|
||||
|
||||
/**
|
||||
* Get a cell in the grid, creating it first if necessary.
|
||||
*
|
||||
* Optimization candidate
|
||||
*
|
||||
* @param {Number} x The x coordinate of the cell.
|
||||
* @param {Number} y The y coordinate of the cell.
|
||||
* @param {Number} z The z coordinate of the cell.
|
||||
* @return {Array} The cell in the array.
|
||||
*/
|
||||
MarkerManager.prototype.getGridCellCreate_ = function (x, y, z) {
|
||||
var grid = this.grid_[z];
|
||||
if (x < 0) {
|
||||
x += this.gridWidth_[z];
|
||||
}
|
||||
var gridCol = grid[x];
|
||||
if (!gridCol) {
|
||||
gridCol = grid[x] = [];
|
||||
return (gridCol[y] = []);
|
||||
}
|
||||
var gridCell = gridCol[y];
|
||||
if (!gridCell) {
|
||||
return (gridCol[y] = []);
|
||||
}
|
||||
return gridCell;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Get a cell in the grid, returning undefined if it does not exist.
|
||||
*
|
||||
* NOTE: Optimized for speed -- otherwise could combine with getGridCellCreate_.
|
||||
*
|
||||
* @param {Number} x The x coordinate of the cell.
|
||||
* @param {Number} y The y coordinate of the cell.
|
||||
* @param {Number} z The z coordinate of the cell.
|
||||
* @return {Array} The cell in the array.
|
||||
*/
|
||||
MarkerManager.prototype.getGridCellNoCreate_ = function (x, y, z) {
|
||||
var grid = this.grid_[z];
|
||||
|
||||
if (x < 0) {
|
||||
x += this.gridWidth_[z];
|
||||
}
|
||||
var gridCol = grid[x];
|
||||
return gridCol ? gridCol[y] : undefined;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Turns at geographical bounds into a grid-space bounds.
|
||||
*
|
||||
* @param {LatLngBounds} bounds The geographical bounds.
|
||||
* @param {Number} zoom The zoom level of the bounds.
|
||||
* @param {google.maps.Size} swPadding The padding in pixels to extend beyond the
|
||||
* given bounds.
|
||||
* @param {google.maps.Size} nePadding The padding in pixels to extend beyond the
|
||||
* given bounds.
|
||||
* @return {GridBounds} The bounds in grid space.
|
||||
*/
|
||||
MarkerManager.prototype.getGridBounds_ = function (bounds, zoom, swPadding, nePadding) {
|
||||
zoom = Math.min(zoom, this.maxZoom_);
|
||||
|
||||
var bl = bounds.getSouthWest();
|
||||
var tr = bounds.getNorthEast();
|
||||
var sw = this.getTilePoint_(bl, zoom, swPadding);
|
||||
|
||||
var ne = this.getTilePoint_(tr, zoom, nePadding);
|
||||
var gw = this.gridWidth_[zoom];
|
||||
|
||||
// Crossing the prime meridian requires correction of bounds.
|
||||
if (tr.lng() < bl.lng() || ne.x < sw.x) {
|
||||
sw.x -= gw;
|
||||
}
|
||||
if (ne.x - sw.x + 1 >= gw) {
|
||||
// Computed grid bounds are larger than the world; truncate.
|
||||
sw.x = 0;
|
||||
ne.x = gw - 1;
|
||||
}
|
||||
|
||||
var gridBounds = new GridBounds([sw, ne]);
|
||||
gridBounds.z = zoom;
|
||||
|
||||
return gridBounds;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Gets the grid-space bounds for the current map viewport.
|
||||
*
|
||||
* @return {Bounds} The bounds in grid space.
|
||||
*/
|
||||
MarkerManager.prototype.getMapGridBounds_ = function () {
|
||||
return this.getGridBounds_(this.map_.getBounds(), this.mapZoom_, this.swPadding_, this.nePadding_);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Event listener for map:movend.
|
||||
* NOTE: Use a timeout so that the user is not blocked
|
||||
* from moving the map.
|
||||
*
|
||||
* Removed this because a a lack of a scopy override/callback function on events.
|
||||
*/
|
||||
MarkerManager.prototype.onMapMoveEnd_ = function () {
|
||||
this.objectSetTimeout_(this, this.updateMarkers_, 0);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Call a function or evaluate an expression after a specified number of
|
||||
* milliseconds.
|
||||
*
|
||||
* Equivalent to the standard window.setTimeout function, but the given
|
||||
* function executes as a method of this instance. So the function passed to
|
||||
* objectSetTimeout can contain references to this.
|
||||
* objectSetTimeout(this, function () { alert(this.x) }, 1000);
|
||||
*
|
||||
* @param {Object} object The target object.
|
||||
* @param {Function} command The command to run.
|
||||
* @param {Number} milliseconds The delay.
|
||||
* @return {Boolean} Success.
|
||||
*/
|
||||
MarkerManager.prototype.objectSetTimeout_ = function (object, command, milliseconds) {
|
||||
return window.setTimeout(function () {
|
||||
command.call(object);
|
||||
}, milliseconds);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Is this layer visible?
|
||||
*
|
||||
* Returns visibility setting
|
||||
*
|
||||
* @return {Boolean} Visible
|
||||
*/
|
||||
MarkerManager.prototype.visible = function () {
|
||||
return this.show_ ? true : false;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Returns true if the manager is hidden.
|
||||
* Otherwise returns false.
|
||||
* @return {Boolean} Hidden
|
||||
*/
|
||||
MarkerManager.prototype.isHidden = function () {
|
||||
return !this.show_;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Shows the manager if it's currently hidden.
|
||||
*/
|
||||
MarkerManager.prototype.show = function () {
|
||||
this.show_ = true;
|
||||
this.refresh();
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Hides the manager if it's currently visible
|
||||
*/
|
||||
MarkerManager.prototype.hide = function () {
|
||||
this.show_ = false;
|
||||
this.refresh();
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Toggles the visibility of the manager.
|
||||
*/
|
||||
MarkerManager.prototype.toggle = function () {
|
||||
this.show_ = !this.show_;
|
||||
this.refresh();
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Refresh forces the marker-manager into a good state.
|
||||
* <ol>
|
||||
* <li>If never before initialized, shows all the markers.</li>
|
||||
* <li>If previously initialized, removes and re-adds all markers.</li>
|
||||
* </ol>
|
||||
*/
|
||||
MarkerManager.prototype.refresh = function () {
|
||||
if (this.shownMarkers_ > 0) {
|
||||
this.processAll_(this.shownBounds_, this.removeOverlay_);
|
||||
}
|
||||
// An extra check on this.show_ to increase performance (no need to processAll_)
|
||||
if (this.show_) {
|
||||
this.processAll_(this.shownBounds_, this.addOverlay_);
|
||||
}
|
||||
this.notifyListeners_();
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* After the viewport may have changed, add or remove markers as needed.
|
||||
*/
|
||||
MarkerManager.prototype.updateMarkers_ = function () {
|
||||
this.mapZoom_ = this.map_.getZoom();
|
||||
var newBounds = this.getMapGridBounds_();
|
||||
|
||||
// If the move does not include new grid sections,
|
||||
// we have no work to do:
|
||||
if (newBounds.equals(this.shownBounds_) && newBounds.z === this.shownBounds_.z) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (newBounds.z !== this.shownBounds_.z) {
|
||||
this.processAll_(this.shownBounds_, this.removeOverlay_);
|
||||
if (this.show_) { // performance
|
||||
this.processAll_(newBounds, this.addOverlay_);
|
||||
}
|
||||
} else {
|
||||
// Remove markers:
|
||||
this.rectangleDiff_(this.shownBounds_, newBounds, this.removeCellMarkers_);
|
||||
|
||||
// Add markers:
|
||||
if (this.show_) { // performance
|
||||
this.rectangleDiff_(newBounds, this.shownBounds_, this.addCellMarkers_);
|
||||
}
|
||||
}
|
||||
this.shownBounds_ = newBounds;
|
||||
|
||||
this.notifyListeners_();
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Notify listeners when the state of what is displayed changes.
|
||||
*/
|
||||
MarkerManager.prototype.notifyListeners_ = function () {
|
||||
google.maps.event.trigger(this, 'changed', this.shownBounds_, this.shownMarkers_);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Process all markers in the bounds provided, using a callback.
|
||||
*
|
||||
* @param {Bounds} bounds The bounds in grid space.
|
||||
* @param {Function} callback The function to call for each marker.
|
||||
*/
|
||||
MarkerManager.prototype.processAll_ = function (bounds, callback) {
|
||||
for (var x = bounds.minX; x <= bounds.maxX; x++) {
|
||||
for (var y = bounds.minY; y <= bounds.maxY; y++) {
|
||||
this.processCellMarkers_(x, y, bounds.z, callback);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Process all markers in the grid cell, using a callback.
|
||||
*
|
||||
* @param {Number} x The x coordinate of the cell.
|
||||
* @param {Number} y The y coordinate of the cell.
|
||||
* @param {Number} z The z coordinate of the cell.
|
||||
* @param {Function} callback The function to call for each marker.
|
||||
*/
|
||||
MarkerManager.prototype.processCellMarkers_ = function (x, y, z, callback) {
|
||||
var cell = this.getGridCellNoCreate_(x, y, z);
|
||||
if (cell) {
|
||||
for (var i = cell.length - 1; i >= 0; i--) {
|
||||
callback(cell[i]);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Remove all markers in a grid cell.
|
||||
*
|
||||
* @param {Number} x The x coordinate of the cell.
|
||||
* @param {Number} y The y coordinate of the cell.
|
||||
* @param {Number} z The z coordinate of the cell.
|
||||
*/
|
||||
MarkerManager.prototype.removeCellMarkers_ = function (x, y, z) {
|
||||
this.processCellMarkers_(x, y, z, this.removeOverlay_);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Add all markers in a grid cell.
|
||||
*
|
||||
* @param {Number} x The x coordinate of the cell.
|
||||
* @param {Number} y The y coordinate of the cell.
|
||||
* @param {Number} z The z coordinate of the cell.
|
||||
*/
|
||||
MarkerManager.prototype.addCellMarkers_ = function (x, y, z) {
|
||||
this.processCellMarkers_(x, y, z, this.addOverlay_);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Use the rectangleDiffCoords_ function to process all grid cells
|
||||
* that are in bounds1 but not bounds2, using a callback, and using
|
||||
* the current MarkerManager object as the instance.
|
||||
*
|
||||
* Pass the z parameter to the callback in addition to x and y.
|
||||
*
|
||||
* @param {Bounds} bounds1 The bounds of all points we may process.
|
||||
* @param {Bounds} bounds2 The bounds of points to exclude.
|
||||
* @param {Function} callback The callback function to call
|
||||
* for each grid coordinate (x, y, z).
|
||||
*/
|
||||
MarkerManager.prototype.rectangleDiff_ = function (bounds1, bounds2, callback) {
|
||||
var me = this;
|
||||
me.rectangleDiffCoords_(bounds1, bounds2, function (x, y) {
|
||||
callback.apply(me, [x, y, bounds1.z]);
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Calls the function for all points in bounds1, not in bounds2
|
||||
*
|
||||
* @param {Bounds} bounds1 The bounds of all points we may process.
|
||||
* @param {Bounds} bounds2 The bounds of points to exclude.
|
||||
* @param {Function} callback The callback function to call
|
||||
* for each grid coordinate.
|
||||
*/
|
||||
MarkerManager.prototype.rectangleDiffCoords_ = function (bounds1, bounds2, callback) {
|
||||
var minX1 = bounds1.minX;
|
||||
var minY1 = bounds1.minY;
|
||||
var maxX1 = bounds1.maxX;
|
||||
var maxY1 = bounds1.maxY;
|
||||
var minX2 = bounds2.minX;
|
||||
var minY2 = bounds2.minY;
|
||||
var maxX2 = bounds2.maxX;
|
||||
var maxY2 = bounds2.maxY;
|
||||
|
||||
var x, y;
|
||||
for (x = minX1; x <= maxX1; x++) { // All x in R1
|
||||
// All above:
|
||||
for (y = minY1; y <= maxY1 && y < minY2; y++) { // y in R1 above R2
|
||||
callback(x, y);
|
||||
}
|
||||
// All below:
|
||||
for (y = Math.max(maxY2 + 1, minY1); // y in R1 below R2
|
||||
y <= maxY1; y++) {
|
||||
callback(x, y);
|
||||
}
|
||||
}
|
||||
|
||||
for (y = Math.max(minY1, minY2);
|
||||
y <= Math.min(maxY1, maxY2); y++) { // All y in R2 and in R1
|
||||
// Strictly left:
|
||||
for (x = Math.min(maxX1 + 1, minX2) - 1;
|
||||
x >= minX1; x--) { // x in R1 left of R2
|
||||
callback(x, y);
|
||||
}
|
||||
// Strictly right:
|
||||
for (x = Math.max(minX1, maxX2 + 1); // x in R1 right of R2
|
||||
x <= maxX1; x++) {
|
||||
callback(x, y);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Removes value from array. O(N).
|
||||
*
|
||||
* @param {Array} array The array to modify.
|
||||
* @param {any} value The value to remove.
|
||||
* @param {Boolean} opt_notype Flag to disable type checking in equality.
|
||||
* @return {Number} The number of instances of value that were removed.
|
||||
*/
|
||||
MarkerManager.prototype.removeFromArray_ = function (array, value, opt_notype) {
|
||||
var shift = 0;
|
||||
for (var i = 0; i < array.length; ++i) {
|
||||
if (array[i] === value || (opt_notype && array[i] === value)) {
|
||||
array.splice(i--, 1);
|
||||
shift++;
|
||||
}
|
||||
}
|
||||
return shift;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Projection overlay helper. Helps in calculating
|
||||
* that markers get into the right grid.
|
||||
* @constructor
|
||||
* @param {Map} map The map to manage.
|
||||
**/
|
||||
function ProjectionHelperOverlay(map) {
|
||||
|
||||
this.setMap(map);
|
||||
|
||||
var TILEFACTOR = 8;
|
||||
var TILESIDE = 1 << TILEFACTOR;
|
||||
var RADIUS = 7;
|
||||
|
||||
this._map = map;
|
||||
this._zoom = -1;
|
||||
this._X0 =
|
||||
this._Y0 =
|
||||
this._X1 =
|
||||
this._Y1 = -1;
|
||||
|
||||
|
||||
}
|
||||
if (typeof(google) != 'undefined' && google.maps) { // make sure it exists -- amalo
|
||||
ProjectionHelperOverlay.prototype = new google.maps.OverlayView();
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function to convert Lng to X
|
||||
* @private
|
||||
* @param {float} lng
|
||||
**/
|
||||
ProjectionHelperOverlay.prototype.LngToX_ = function (lng) {
|
||||
return (1 + lng / 180);
|
||||
};
|
||||
|
||||
/**
|
||||
* Helper function to convert Lat to Y
|
||||
* @private
|
||||
* @param {float} lat
|
||||
**/
|
||||
ProjectionHelperOverlay.prototype.LatToY_ = function (lat) {
|
||||
var sinofphi = Math.sin(lat * Math.PI / 180);
|
||||
return (1 - 0.5 / Math.PI * Math.log((1 + sinofphi) / (1 - sinofphi)));
|
||||
};
|
||||
|
||||
/**
|
||||
* Old school LatLngToPixel
|
||||
* @param {LatLng} latlng google.maps.LatLng object
|
||||
* @param {Number} zoom Zoom level
|
||||
* @return {position} {x: pixelPositionX, y: pixelPositionY}
|
||||
**/
|
||||
ProjectionHelperOverlay.prototype.LatLngToPixel = function (latlng, zoom) {
|
||||
var map = this._map;
|
||||
var div = this.getProjection().fromLatLngToDivPixel(latlng);
|
||||
var abs = {x: ~~(0.5 + this.LngToX_(latlng.lng()) * (2 << (zoom + 6))), y: ~~(0.5 + this.LatToY_(latlng.lat()) * (2 << (zoom + 6)))};
|
||||
return abs;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Draw function only triggers a ready event for
|
||||
* MarkerManager to know projection can proceed to
|
||||
* initialize.
|
||||
*/
|
||||
ProjectionHelperOverlay.prototype.draw = function () {
|
||||
if (!this.ready) {
|
||||
this.ready = true;
|
||||
google.maps.event.trigger(this, 'ready');
|
||||
}
|
||||
};
|
5
compile-dev
Executable file
5
compile-dev
Executable file
@ -0,0 +1,5 @@
|
||||
#!/bin/sh
|
||||
|
||||
# -Wwrite-strings
|
||||
# -Wconversion
|
||||
CFLAGS="-ggdb -std=c89 -pedantic -Wnested-externs -Wmissing-declarations -Wmissing-prototypes -Wcast-qual -Wcast-align -Wbad-function-cast -Wshadow -Wundef -Wdeclaration-after-statement -Wstrict-overflow=4 -Wmissing-include-dirs -Winit-self -Wextra -Wall -Werror -Wno-overlength-strings -Wno-long-long -Wno-unused-parameter -Wno-missing-field-initializers" exec make clean compile
|
190
docs/BENCHMARKS
Normal file
190
docs/BENCHMARKS
Normal file
@ -0,0 +1,190 @@
|
||||
$ python3.3 -OO bench.py bench/*.js
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
slimit_0_7 not available for python 3...
|
||||
Python Release: 3.3.2
|
||||
|
||||
Benchmarking 'bench/apiviewer.js'... (953.2 KiB)
|
||||
Timing simple_port ... (951.5 KiB *) 3072.57 ms
|
||||
Timing jsmin_2_0_2 ... (951.4 KiB <) 617.54 ms (factor: 4.98)
|
||||
Timing rjsmin ... (951.5 KiB =) 87.38 ms (factor: 35.16, 7.07)
|
||||
Timing _rjsmin ... (951.5 KiB =) 3.54 ms (factor: 868.91, 174.64, 24.71)
|
||||
|
||||
Benchmarking 'bench/bootstrap.js'... (49.0 KiB)
|
||||
Timing simple_port ... ( 26.4 KiB *) 130.17 ms
|
||||
Timing jsmin_2_0_2 ... ( 26.4 KiB >) 27.26 ms (factor: 4.78)
|
||||
Timing rjsmin ... ( 26.4 KiB >) 21.41 ms (factor: 6.08, 1.27)
|
||||
Timing _rjsmin ... ( 26.4 KiB >) 0.24 ms (factor: 543.67, 113.84, 89.44)
|
||||
|
||||
Benchmarking 'bench/jquery-1.7.1.js'... (242.4 KiB)
|
||||
Timing simple_port ... (135.9 KiB *) 682.02 ms
|
||||
Timing jsmin_2_0_2 ... (136.5 KiB >) 142.79 ms (factor: 4.78)
|
||||
Timing rjsmin ... (135.9 KiB =) 143.68 ms (factor: 4.75, 0.99)
|
||||
Timing _rjsmin ... (135.9 KiB =) 1.28 ms (factor: 533.42, 111.68, 112.37)
|
||||
|
||||
Benchmarking 'bench/knockout-2.0.0.js'... (38.9 KiB)
|
||||
Timing simple_port ... ( 38.6 KiB *) 122.96 ms
|
||||
Timing jsmin_2_0_2 ... ( 38.6 KiB >) 26.48 ms (factor: 4.64)
|
||||
Timing rjsmin ... ( 38.6 KiB >) 4.81 ms (factor: 25.58, 5.51)
|
||||
Timing _rjsmin ... ( 38.6 KiB >) 0.14 ms (factor: 874.54, 188.31, 34.19)
|
||||
|
||||
Benchmarking 'bench/markermanager.js'... (28.6 KiB)
|
||||
Timing simple_port ... ( 11.6 KiB *) 63.52 ms
|
||||
Timing jsmin_2_0_2 ... ( 11.6 KiB >) 14.63 ms (factor: 4.34)
|
||||
Timing rjsmin ... ( 11.6 KiB =) 9.14 ms (factor: 6.95, 1.60)
|
||||
Timing _rjsmin ... ( 11.6 KiB =) 0.12 ms (factor: 524.54, 120.83, 75.46)
|
||||
|
||||
|
||||
$ python3.2 -OO bench.py bench/*.js
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
slimit_0_7 not available for python 3...
|
||||
Python Release: 3.2.3
|
||||
|
||||
Benchmarking 'bench/apiviewer.js'... (953.2 KiB)
|
||||
Timing simple_port ... (951.5 KiB *) 2880.13 ms
|
||||
Timing jsmin_2_0_2 ... (951.4 KiB <) 503.52 ms (factor: 5.72)
|
||||
Timing rjsmin ... (951.5 KiB =) 75.16 ms (factor: 38.32, 6.70)
|
||||
Timing _rjsmin ... (951.5 KiB =) 2.60 ms (factor: 1108.00, 193.71, 28.92)
|
||||
|
||||
Benchmarking 'bench/bootstrap.js'... (49.0 KiB)
|
||||
Timing simple_port ... ( 26.4 KiB *) 118.18 ms
|
||||
Timing jsmin_2_0_2 ... ( 26.4 KiB >) 21.84 ms (factor: 5.41)
|
||||
Timing rjsmin ... ( 26.4 KiB >) 18.23 ms (factor: 6.48, 1.20)
|
||||
Timing _rjsmin ... ( 26.4 KiB >) 0.19 ms (factor: 618.06, 114.22, 95.31)
|
||||
|
||||
Benchmarking 'bench/jquery-1.7.1.js'... (242.4 KiB)
|
||||
Timing simple_port ... (135.9 KiB *) 620.88 ms
|
||||
Timing jsmin_2_0_2 ... (136.5 KiB >) 115.48 ms (factor: 5.38)
|
||||
Timing rjsmin ... (135.9 KiB =) 122.68 ms (factor: 5.06, 0.94)
|
||||
Timing _rjsmin ... (135.9 KiB =) 1.11 ms (factor: 560.97, 104.34, 110.84)
|
||||
|
||||
Benchmarking 'bench/knockout-2.0.0.js'... (38.9 KiB)
|
||||
Timing simple_port ... ( 38.6 KiB *) 115.03 ms
|
||||
Timing jsmin_2_0_2 ... ( 38.6 KiB >) 21.07 ms (factor: 5.46)
|
||||
Timing rjsmin ... ( 38.6 KiB >) 3.94 ms (factor: 29.18, 5.35)
|
||||
Timing _rjsmin ... ( 38.6 KiB >) 0.10 ms (factor: 1158.40, 212.23, 39.70)
|
||||
|
||||
Benchmarking 'bench/markermanager.js'... (28.6 KiB)
|
||||
Timing simple_port ... ( 11.6 KiB *) 56.81 ms
|
||||
Timing jsmin_2_0_2 ... ( 11.6 KiB >) 11.61 ms (factor: 4.89)
|
||||
Timing rjsmin ... ( 11.6 KiB =) 7.61 ms (factor: 7.46, 1.52)
|
||||
Timing _rjsmin ... ( 11.6 KiB =) 0.09 ms (factor: 642.56, 131.31, 86.11)
|
||||
|
||||
|
||||
i$ python3.1 -OO bench.py bench/*.js
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
slimit_0_7 not available for python 3...
|
||||
Python Release: 3.1.5
|
||||
|
||||
Benchmarking 'bench/apiviewer.js'... (953.2 KiB)
|
||||
Timing simple_port ... (951.5 KiB *) 3006.80 ms
|
||||
Timing jsmin_2_0_2 ... (951.4 KiB <) 505.56 ms (factor: 5.95)
|
||||
Timing rjsmin ... (951.5 KiB =) 83.47 ms (factor: 36.02, 6.06)
|
||||
Timing _rjsmin ... (951.5 KiB =) 2.60 ms (factor: 1155.26, 194.24, 32.07)
|
||||
|
||||
Benchmarking 'bench/bootstrap.js'... (49.0 KiB)
|
||||
Timing simple_port ... ( 26.4 KiB *) 123.10 ms
|
||||
Timing jsmin_2_0_2 ... ( 26.4 KiB >) 21.98 ms (factor: 5.60)
|
||||
Timing rjsmin ... ( 26.4 KiB >) 19.52 ms (factor: 6.31, 1.13)
|
||||
Timing _rjsmin ... ( 26.4 KiB >) 0.19 ms (factor: 643.17, 114.86, 101.97)
|
||||
|
||||
Benchmarking 'bench/jquery-1.7.1.js'... (242.4 KiB)
|
||||
Timing simple_port ... (135.9 KiB *) 647.61 ms
|
||||
Timing jsmin_2_0_2 ... (136.5 KiB >) 116.21 ms (factor: 5.57)
|
||||
Timing rjsmin ... (135.9 KiB =) 131.60 ms (factor: 4.92, 0.88)
|
||||
Timing _rjsmin ... (135.9 KiB =) 1.11 ms (factor: 584.97, 104.96, 118.87)
|
||||
|
||||
Benchmarking 'bench/knockout-2.0.0.js'... (38.9 KiB)
|
||||
Timing simple_port ... ( 38.6 KiB *) 120.51 ms
|
||||
Timing jsmin_2_0_2 ... ( 38.6 KiB >) 21.28 ms (factor: 5.66)
|
||||
Timing rjsmin ... ( 38.6 KiB >) 4.34 ms (factor: 27.78, 4.91)
|
||||
Timing _rjsmin ... ( 38.6 KiB >) 0.10 ms (factor: 1212.43, 214.10, 43.64)
|
||||
|
||||
Benchmarking 'bench/markermanager.js'... (28.6 KiB)
|
||||
Timing simple_port ... ( 11.6 KiB *) 59.60 ms
|
||||
Timing jsmin_2_0_2 ... ( 11.6 KiB >) 11.63 ms (factor: 5.13)
|
||||
Timing rjsmin ... ( 11.6 KiB =) 8.20 ms (factor: 7.27, 1.42)
|
||||
Timing _rjsmin ... ( 11.6 KiB =) 0.09 ms (factor: 671.95, 131.11, 92.48)
|
||||
|
||||
|
||||
$ python2.7 -OO bench.py bench/*.js
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
Python Release: 2.7.3
|
||||
|
||||
Benchmarking 'bench/apiviewer.js'... (953.2 KiB)
|
||||
Timing simple_port ... (951.5 KiB *) 3598.04 ms
|
||||
Timing jsmin_2_0_2 ... (951.4 KiB <) 733.59 ms (factor: 4.90)
|
||||
Timing slimit_0_7 ... (944.3 KiB <) 16410.85 ms (factor: 0.22, 0.04)
|
||||
Timing slimit_0_7_mangle ... (922.8 KiB <) 20213.29 ms (factor: 0.18, 0.04, 0.81)
|
||||
Timing rjsmin ... (951.5 KiB =) 65.71 ms (factor: 54.76, 11.16, 249.76, 307.64)
|
||||
Timing _rjsmin ... (951.5 KiB =) 3.17 ms (factor: 1136.32, 231.68, 5182.83, 6383.70, 20.75)
|
||||
|
||||
Benchmarking 'bench/bootstrap.js'... (49.0 KiB)
|
||||
Timing simple_port ... ( 26.4 KiB *) 145.62 ms
|
||||
Timing jsmin_2_0_2 ... ( 26.4 KiB >) 31.66 ms (factor: 4.60)
|
||||
Timing slimit_0_7 ... ( 26.5 KiB >) 465.21 ms (factor: 0.31, 0.07)
|
||||
Timing slimit_0_7_mangle ... ( 22.2 KiB <) 496.30 ms (factor: 0.29, 0.06, 0.94)
|
||||
Timing rjsmin ... ( 26.4 KiB >) 17.40 ms (factor: 8.37, 1.82, 26.73, 28.52)
|
||||
Timing _rjsmin ... ( 26.4 KiB >) 0.22 ms (factor: 663.08, 144.16, 2118.35, 2259.92, 79.24)
|
||||
|
||||
Benchmarking 'bench/jquery-1.7.1.js'... (242.4 KiB)
|
||||
Timing simple_port ... (135.9 KiB *) 765.49 ms
|
||||
Timing jsmin_2_0_2 ... (136.5 KiB >) 171.20 ms (factor: 4.47)
|
||||
Timing slimit_0_7 ... (134.0 KiB <) 2187.47 ms (factor: 0.35, 0.08)
|
||||
Timing slimit_0_7_mangle ... ( 95.0 KiB <) 2614.89 ms (factor: 0.29, 0.07, 0.84)
|
||||
Timing rjsmin ... (135.9 KiB =) 117.15 ms (factor: 6.53, 1.46, 18.67, 22.32)
|
||||
Timing _rjsmin ... (135.9 KiB =) 1.22 ms (factor: 628.38, 140.53, 1795.66, 2146.52, 96.17)
|
||||
|
||||
Benchmarking 'bench/knockout-2.0.0.js'... (38.9 KiB)
|
||||
Timing simple_port ... ( 38.6 KiB *) 146.34 ms
|
||||
Timing jsmin_2_0_2 ... ( 38.6 KiB >) 31.57 ms (factor: 4.64)
|
||||
Timing slimit_0_7 ... ( 39.0 KiB >) 858.22 ms (factor: 0.17, 0.04)
|
||||
Timing slimit_0_7_mangle ... ( 38.9 KiB >) 1036.05 ms (factor: 0.14, 0.03, 0.83)
|
||||
Timing rjsmin ... ( 38.6 KiB >) 3.73 ms (factor: 39.29, 8.47, 230.39, 278.13)
|
||||
Timing _rjsmin ... ( 38.6 KiB >) 0.14 ms (factor: 1057.38, 228.08, 6200.89, 7485.80, 26.91)
|
||||
|
||||
Benchmarking 'bench/markermanager.js'... (28.6 KiB)
|
||||
Timing simple_port ... ( 11.6 KiB *) 72.23 ms
|
||||
Timing jsmin_2_0_2 ... ( 11.6 KiB >) 17.08 ms (factor: 4.23)
|
||||
Timing slimit_0_7 ... ( 11.5 KiB <) 177.14 ms (factor: 0.41, 0.10)
|
||||
Timing slimit_0_7_mangle ... ( 9.3 KiB <) 202.09 ms (factor: 0.36, 0.08, 0.88)
|
||||
Timing rjsmin ... ( 11.6 KiB =) 7.32 ms (factor: 9.86, 2.33, 24.18, 27.59)
|
||||
Timing _rjsmin ... ( 11.6 KiB =) 0.10 ms (factor: 698.55, 165.22, 1713.12, 1954.45, 70.84)
|
||||
|
||||
|
||||
$ python2.6 -OO bench.py bench/*.js
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
slimit_0_7 not installed for python 2.6...
|
||||
Python Release: 2.6.8
|
||||
|
||||
Benchmarking 'bench/apiviewer.js'... (953.2 KiB)
|
||||
Timing simple_port ... (951.5 KiB *) 3400.55 ms
|
||||
Timing jsmin_2_0_2 ... (951.4 KiB <) 775.37 ms (factor: 4.39)
|
||||
Timing rjsmin ... (951.5 KiB =) 68.39 ms (factor: 49.72, 11.34)
|
||||
Timing _rjsmin ... (951.5 KiB =) 3.16 ms (factor: 1074.49, 245.00, 21.61)
|
||||
|
||||
Benchmarking 'bench/bootstrap.js'... (49.0 KiB)
|
||||
Timing simple_port ... ( 26.4 KiB *) 138.10 ms
|
||||
Timing jsmin_2_0_2 ... ( 26.4 KiB >) 33.80 ms (factor: 4.09)
|
||||
Timing rjsmin ... ( 26.4 KiB >) 17.47 ms (factor: 7.90, 1.93)
|
||||
Timing _rjsmin ... ( 26.4 KiB >) 0.22 ms (factor: 629.45, 154.05, 79.64)
|
||||
|
||||
Benchmarking 'bench/jquery-1.7.1.js'... (242.4 KiB)
|
||||
Timing simple_port ... (135.9 KiB *) 728.82 ms
|
||||
Timing jsmin_2_0_2 ... (136.5 KiB >) 182.44 ms (factor: 3.99)
|
||||
Timing rjsmin ... (135.9 KiB =) 118.96 ms (factor: 6.13, 1.53)
|
||||
Timing _rjsmin ... (135.9 KiB =) 1.22 ms (factor: 597.89, 149.67, 97.59)
|
||||
|
||||
Benchmarking 'bench/knockout-2.0.0.js'... (38.9 KiB)
|
||||
Timing simple_port ... ( 38.6 KiB *) 135.16 ms
|
||||
Timing jsmin_2_0_2 ... ( 38.6 KiB >) 33.30 ms (factor: 4.06)
|
||||
Timing rjsmin ... ( 38.6 KiB >) 3.73 ms (factor: 36.21, 8.92)
|
||||
Timing _rjsmin ... ( 38.6 KiB >) 0.14 ms (factor: 981.50, 241.80, 27.11)
|
||||
|
||||
Benchmarking 'bench/markermanager.js'... (28.6 KiB)
|
||||
Timing simple_port ... ( 11.6 KiB *) 68.13 ms
|
||||
Timing jsmin_2_0_2 ... ( 11.6 KiB >) 18.29 ms (factor: 3.72)
|
||||
Timing rjsmin ... ( 11.6 KiB =) 7.52 ms (factor: 9.06, 2.43)
|
||||
Timing _rjsmin ... ( 11.6 KiB =) 0.10 ms (factor: 660.88, 177.46, 72.95)
|
||||
|
||||
|
||||
# vim: nowrap
|
58
docs/CHANGES
Normal file
58
docs/CHANGES
Normal file
@ -0,0 +1,58 @@
|
||||
Changes with version 1.0.7
|
||||
|
||||
*) Fix inconsistency between Python and C (Python implementation was buggy).
|
||||
Spotted by: Dave Smith <dave thesmithfam.org>
|
||||
|
||||
*) Added support for jython 2.7
|
||||
|
||||
|
||||
Changes with version 1.0.6
|
||||
|
||||
*) Added compat option to setup.py supporting the pip installer
|
||||
|
||||
*) Added support for pypy (1.9, 2.0)
|
||||
|
||||
*) Added support for jython (2.5)
|
||||
|
||||
|
||||
Changes with version 1.0.5
|
||||
|
||||
*) Newline removal before ! operator was made more sensible.
|
||||
|
||||
|
||||
Changes with version 1.0.4
|
||||
|
||||
*) Added support for Python 3.3
|
||||
|
||||
*) Collapsion protection was reduced to "+ +" and "- -" sequences (which
|
||||
still includes longer sequences like "+ ++")
|
||||
|
||||
|
||||
Changes with version 1.0.3
|
||||
|
||||
*) "+ ++" and "- --" sequences are no longer collapsed. They were before,
|
||||
because the original jsmin collapsed them, too.
|
||||
|
||||
*) Updated benchmarks, added slimit and removed jsmin v8 (because it produced
|
||||
invalid results).
|
||||
|
||||
*) Removed "classic" regex variant.
|
||||
|
||||
|
||||
Changes with version 1.0.2
|
||||
|
||||
*) Although it should work, python 2.3 is no longer supported.
|
||||
(No suitable test environment)
|
||||
|
||||
*) "return /regex/" is now recognized as regex expression. It wasn't before,
|
||||
because the original jsmin ignored that, too.
|
||||
|
||||
|
||||
Changes with version 1.0.1
|
||||
|
||||
*) Add C extension reimplementing the regex from rjsmin.py
|
||||
|
||||
|
||||
Changes with version 1.0.0
|
||||
|
||||
*) First stable release.
|
19
docs/CLASSIFIERS
Normal file
19
docs/CLASSIFIERS
Normal file
@ -0,0 +1,19 @@
|
||||
Development Status :: 5 - Production/Stable
|
||||
Environment :: Web Environment
|
||||
Intended Audience :: Developers
|
||||
License :: OSI Approved
|
||||
License :: OSI Approved :: Apache License, Version 2.0
|
||||
Operating System :: OS Independent
|
||||
Programming Language :: C
|
||||
Programming Language :: Python
|
||||
Programming Language :: Python :: 2
|
||||
Programming Language :: Python :: 3
|
||||
Programming Language :: Python :: Implementation :: CPython
|
||||
Programming Language :: Python :: Implementation :: Jython
|
||||
Programming Language :: Python :: Implementation :: PyPy
|
||||
Topic :: Internet :: WWW/HTTP :: Dynamic Content
|
||||
Topic :: Software Development :: Libraries
|
||||
Topic :: Software Development :: Libraries :: Python Modules
|
||||
Topic :: Text Processing
|
||||
Topic :: Text Processing :: Filters
|
||||
Topic :: Utilities
|
70
docs/DESCRIPTION
Normal file
70
docs/DESCRIPTION
Normal file
@ -0,0 +1,70 @@
|
||||
=====================
|
||||
Javascript Minifier
|
||||
=====================
|
||||
|
||||
rJSmin is a javascript minifier written in python.
|
||||
|
||||
The minifier is based on the semantics of `jsmin.c by Douglas Crockford`_\.
|
||||
|
||||
The module is a re-implementation aiming for speed, so it can be used at
|
||||
runtime (rather than during a preprocessing step). Usually it produces the
|
||||
same results as the original ``jsmin.c``. It differs in the following ways:
|
||||
|
||||
- there is no error detection: unterminated string, regex and comment
|
||||
literals are treated as regular javascript code and minified as such.
|
||||
- Control characters inside string and regex literals are left untouched; they
|
||||
are not converted to spaces (nor to \n)
|
||||
- Newline characters are not allowed inside string and regex literals, except
|
||||
for line continuations in string literals (ECMA-5).
|
||||
- "return /regex/" is recognized correctly.
|
||||
- "+ +" and "- -" sequences are not collapsed to '++' or '--'
|
||||
- Newlines before ! operators are removed more sensibly
|
||||
- rJSmin does not handle streams, but only complete strings. (However, the
|
||||
module provides a "streamy" interface).
|
||||
|
||||
Since most parts of the logic are handled by the regex engine it's way
|
||||
faster than the original python port of ``jsmin.c`` by Baruch Even. The speed
|
||||
factor varies between about 6 and 55 depending on input and python version
|
||||
(it gets faster the more compressed the input already is). Compared to the
|
||||
speed-refactored python port by Dave St.Germain the performance gain is less
|
||||
dramatic but still between 1.2 and 7. See the docs/BENCHMARKS file for
|
||||
details.
|
||||
|
||||
rjsmin.c is a reimplementation of rjsmin.py in C and speeds it up even more.
|
||||
|
||||
Both python 2 (>=2.4) and python 3 are supported.
|
||||
|
||||
.. _jsmin.c by Douglas Crockford: http://www.crockford.com/javascript/jsmin.c
|
||||
|
||||
|
||||
Copyright and License
|
||||
~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Copyright 2011 - 2013
|
||||
André Malo or his licensors, as applicable.
|
||||
|
||||
The whole package (except for the files in the bench/ directory) is
|
||||
distributed under the Apache License Version 2.0. You'll find a copy in the
|
||||
root directory of the distribution or online at:
|
||||
<http://www.apache.org/licenses/LICENSE-2.0>.
|
||||
|
||||
|
||||
Bugs
|
||||
~~~~
|
||||
|
||||
No bugs, of course. ;-)
|
||||
But if you've found one or have an idea how to improve rjsmin, please
|
||||
send a mail to <rjsmin-bugs@perlig.de>.
|
||||
|
||||
|
||||
Author Information
|
||||
~~~~~~~~~~~~~~~~~~
|
||||
|
||||
André "nd" Malo <nd perlig.de>
|
||||
GPG: 0x8103A37E
|
||||
|
||||
|
||||
If God intended people to be naked, they would be born that way.
|
||||
-- Oscar Wilde
|
||||
|
||||
.. vim:tw=72 syntax=rest
|
1
docs/PROVIDES
Normal file
1
docs/PROVIDES
Normal file
@ -0,0 +1 @@
|
||||
rjsmin (1.0)
|
1
docs/SUMMARY
Normal file
1
docs/SUMMARY
Normal file
@ -0,0 +1 @@
|
||||
Javascript Minifier
|
23
docs/_userdoc/_static/ci.css
Normal file
23
docs/_userdoc/_static/ci.css
Normal file
@ -0,0 +1,23 @@
|
||||
.ci {
|
||||
font-variant: small-caps;
|
||||
font-family: serif;
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
table.benchmark {
|
||||
width: 40em;
|
||||
}
|
||||
|
||||
table.benchmark th {
|
||||
text-align: center;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
table.benchmark td {
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
table.benchmark td + td {
|
||||
text-align: right;
|
||||
font-family: monospace;
|
||||
}
|
2
docs/_userdoc/_templates/layout.html
Normal file
2
docs/_userdoc/_templates/layout.html
Normal file
@ -0,0 +1,2 @@
|
||||
{% extends "default/layout.html" %}
|
||||
{% set css_files = css_files + ['_static/ci.css'] %}
|
174
docs/_userdoc/benchmark.txt
Normal file
174
docs/_userdoc/benchmark.txt
Normal file
@ -0,0 +1,174 @@
|
||||
.. license:
|
||||
Copyright 2011 - 2013
|
||||
André Malo or his licensors, as applicable
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
:orphan:
|
||||
|
||||
|
||||
====================
|
||||
rJSmin - Benchmark
|
||||
====================
|
||||
|
||||
The following numbers have been measured with the bench.py script
|
||||
provided in the source distribution. Since the numbers don't vary much
|
||||
between python minor releases (e.g. 2.6 vs 2.7), only the benchmarks for
|
||||
2.7 and 3.3 are given below. The :file:`docs/BENCHMARKS` file in the source
|
||||
distribution contains the full list.
|
||||
|
||||
Here's the list of benchmarked implementations:
|
||||
|
||||
- Simple port is the original jsmin.py port by Baruch Even
|
||||
- jsmin 2.0.2 is a speed-refactored python port by Dave St.Germain
|
||||
- slimit 0.7 is a minifier based on a parse/generate-iteration. It's
|
||||
available for python 2 only.
|
||||
- slimit 0.7 (mangle) is slimit 0.7 with name mangeling enabled
|
||||
- |rjsmin| is this very project
|
||||
- _\ |rjsmin| is the C reimplementation of |rjsmin|
|
||||
|
||||
Note that jsmin 2.0.2 and slimit produce output different from
|
||||
the original jsmin.c. Also the simple port was modified to use cStringIO
|
||||
if available (it's faster then) or io (for python 3).
|
||||
|
||||
And here's a list of the benchmarked javascript files:
|
||||
|
||||
- apiviewer is a file from the qooxdoo framework. Very big and already
|
||||
compressed.
|
||||
- bootstrap is the popular twitter toolkit, version 2.0.4
|
||||
- jquery is jquery-1.7.1.js; the uncompressed development download.
|
||||
- knockout is knockout-2.0.0.js, the compressed download.
|
||||
- markermanager is the V3 port of the google maps markermanager.
|
||||
|
||||
Inside the parentheses are size information in KiB (actually: number of
|
||||
characters/1024). The sign behind the size value denotes the size difference
|
||||
in relation to the simple port (i.e. jsmin itself).
|
||||
|
||||
|
||||
Python 3.3.2
|
||||
~~~~~~~~~~~~
|
||||
|
||||
.. rst-class:: benchmark
|
||||
|
||||
+---------------------+-----------------------+----------------------+
|
||||
| Name | apiviewer (953.2) | bootstrap (49.0) |
|
||||
+=====================+=======================+======================+
|
||||
| Simple Port | 3072.57 ms (951.5 \*)| 130.17 ms (26.4 \*) |
|
||||
+---------------------+-----------------------+----------------------+
|
||||
| jsmin 2.0.2 | 617.54 ms (951.4 <) | 21.93 ms (26.4 >) |
|
||||
+---------------------+-----------------------+----------------------+
|
||||
| slimit 0.7 | n/a | n/a |
|
||||
+---------------------+-----------------------+----------------------+
|
||||
| slimit 0.7 (mangle) | n/a | n/a |
|
||||
+---------------------+-----------------------+----------------------+
|
||||
| |rjsmin| | 87.38 ms (951.5 =) | 21.41 ms (26.4 >) |
|
||||
+---------------------+-----------------------+----------------------+
|
||||
| _\ |rjsmin| | 3.54 ms (951.5 =) | 0.24 ms (26.4 >) |
|
||||
+---------------------+-----------------------+----------------------+
|
||||
|
||||
.. rst-class:: benchmark
|
||||
|
||||
+---------------------+-----------------------+----------------------+
|
||||
| Name | jquery (242.4) | knockout (38.9) |
|
||||
+=====================+=======================+======================+
|
||||
| Simple Port | 682.02 ms (135.9 \*)| 122.96 ms (38.6 \*) |
|
||||
+---------------------+-----------------------+----------------------+
|
||||
| jsmin 2.0.2 | 142.79 ms (136.5 >) | 26.48 ms (38.6 >) |
|
||||
+---------------------+-----------------------+----------------------+
|
||||
| slimit 0.7 | n/a | n/a |
|
||||
+---------------------+-----------------------+----------------------+
|
||||
| slimit 0.7 (mangle) | n/a | n/a |
|
||||
+---------------------+-----------------------+----------------------+
|
||||
| |rjsmin| | 143.68 ms (135.9 =) | 4.81 ms (38.6 >) |
|
||||
+---------------------+-----------------------+----------------------+
|
||||
| _\ |rjsmin| | 1.28 ms (135.9 =) | 0.14 ms (38.6 >) |
|
||||
+---------------------+-----------------------+----------------------+
|
||||
|
||||
.. rst-class:: benchmark
|
||||
|
||||
+---------------------+-----------------------+----------------------+
|
||||
| Name | markermanager (28.6) | |
|
||||
+=====================+=======================+======================+
|
||||
| Simple Port | 63.52 ms (11.6 \*) | |
|
||||
+---------------------+-----------------------+----------------------+
|
||||
| jsmin 2.0.2 | 14.63 ms (11.6 >) | |
|
||||
+---------------------+-----------------------+----------------------+
|
||||
| slimit 0.7 | n/a | |
|
||||
+---------------------+-----------------------+----------------------+
|
||||
| slimit 0.7 (mangle) | n/a | |
|
||||
+---------------------+-----------------------+----------------------+
|
||||
| |rjsmin| | 9.14 ms (11.6 =) | |
|
||||
+---------------------+-----------------------+----------------------+
|
||||
| _\ |rjsmin| | 0.12 ms (11.6 =) | |
|
||||
+---------------------+-----------------------+----------------------+
|
||||
|
||||
|
||||
Python 2.7.3
|
||||
~~~~~~~~~~~~
|
||||
|
||||
.. rst-class:: benchmark
|
||||
|
||||
+---------------------+-----------------------+----------------------+
|
||||
| Name | apiviewer (953.2) | bootstrap (49.0) |
|
||||
+=====================+=======================+======================+
|
||||
| Simple Port | 3598.04 ms (951.5 \*)| 145.62 ms (26.4 \*) |
|
||||
+---------------------+-----------------------+----------------------+
|
||||
| jsmin 2.0.2 | 733.59 ms (951.4 <) | 31.66 ms (26.4 >) |
|
||||
+---------------------+-----------------------+----------------------+
|
||||
| slimit 0.7 | 16410.85 ms (944.3 <) | 465.21 ms (26.5 >) |
|
||||
+---------------------+-----------------------+----------------------+
|
||||
| slimit 0.7 (mangle) | 20213.29 ms (922.8 <) | 496.30 ms (22.2 <) |
|
||||
+---------------------+-----------------------+----------------------+
|
||||
| |rjsmin| | 65.71 ms (951.5 =) | 17.40 ms (26.4 >) |
|
||||
+---------------------+-----------------------+----------------------+
|
||||
| _\ |rjsmin| | 3.17 ms (951.5 =) | 0.22 ms (26.4 >) |
|
||||
+---------------------+-----------------------+----------------------+
|
||||
|
||||
.. rst-class:: benchmark
|
||||
|
||||
+---------------------+-----------------------+----------------------+
|
||||
| Name | jquery (242.4) | knockout (38.9) |
|
||||
+=====================+=======================+======================+
|
||||
| Simple Port | 765.49 ms (135.9 \*)| 146.34 ms (38.6 \*) |
|
||||
+---------------------+-----------------------+----------------------+
|
||||
| jsmin 2.0.2 | 171.20 ms (136.5 >) | 31.57 ms (38.6 >) |
|
||||
+---------------------+-----------------------+----------------------+
|
||||
| slimit 0.7 | 2187.47 ms (134.0 <) | 858.22 ms (39.0 >) |
|
||||
+---------------------+-----------------------+----------------------+
|
||||
| slimit 0.7 (mangle) | 2614.89 ms ( 95.0 <) | 1036.05 ms (38.9 >) |
|
||||
+---------------------+-----------------------+----------------------+
|
||||
| |rjsmin| | 117.15 ms (135.9 =) | 3.73 ms (38.6 >) |
|
||||
+---------------------+-----------------------+----------------------+
|
||||
| _\ |rjsmin| | 1.22 ms (135.9 =) | 0.14 ms (38.6 >) |
|
||||
+---------------------+-----------------------+----------------------+
|
||||
|
||||
.. rst-class:: benchmark
|
||||
|
||||
+---------------------+-----------------------+----------------------+
|
||||
| Name | markermanager (28.6) | |
|
||||
+=====================+=======================+======================+
|
||||
| Simple Port | 72.23 ms (11.6 \*) | |
|
||||
+---------------------+-----------------------+----------------------+
|
||||
| jsmin 2.0.2 | 17.08 ms (11.6 >) | |
|
||||
+---------------------+-----------------------+----------------------+
|
||||
| slimit 0.7 | 177.14 ms (11.5 <) | |
|
||||
+---------------------+-----------------------+----------------------+
|
||||
| slimit 0.7 (mangle) | 202.09 ms ( 9.3 <) | |
|
||||
+---------------------+-----------------------+----------------------+
|
||||
| |rjsmin| | 7.32 ms (11.6 =) | |
|
||||
+---------------------+-----------------------+----------------------+
|
||||
| _\ |rjsmin| | 0.10 ms (11.6 =) | |
|
||||
+---------------------+-----------------------+----------------------+
|
||||
|
||||
|
||||
.. vim: ft=rest tw=72
|
228
docs/_userdoc/conf.py
Normal file
228
docs/_userdoc/conf.py
Normal file
@ -0,0 +1,228 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# This file is execfile()d with the current directory set to its containing dir.
|
||||
#
|
||||
# Note that not all possible configuration values are present in this
|
||||
# autogenerated file.
|
||||
#
|
||||
# All configuration values have a default; values that are commented out
|
||||
# serve to show the default.
|
||||
|
||||
import sys, os
|
||||
|
||||
# If extensions (or modules to document with autodoc) are in another directory,
|
||||
# add these directories to sys.path here. If the directory is relative to the
|
||||
# documentation root, use os.path.abspath to make it absolute, like shown here.
|
||||
sys.path.append(os.path.abspath('.'))
|
||||
|
||||
# -- General configuration -----------------------------------------------------
|
||||
|
||||
# Add any Sphinx extension module names here, as strings. They can be extensions
|
||||
# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
|
||||
extensions = ['epydoc_sphinx']
|
||||
|
||||
# Add any paths that contain templates here, relative to this directory.
|
||||
templates_path = ['_templates']
|
||||
|
||||
# The suffix of source filenames.
|
||||
source_suffix = '.txt'
|
||||
|
||||
# The encoding of source files.
|
||||
#source_encoding = 'utf-8'
|
||||
|
||||
# The master toctree document.
|
||||
master_doc = 'index'
|
||||
|
||||
# General information about the project.
|
||||
project = u'rJSmin'
|
||||
copyright = u'2012 Andr\xe9 Malo'
|
||||
|
||||
# The version info for the project you're documenting, acts as replacement for
|
||||
# |version| and |release|, also used in various other places throughout the
|
||||
# built documents.
|
||||
#
|
||||
# The short X.Y version.
|
||||
version = '1.0'
|
||||
# The full version, including alpha/beta/rc tags.
|
||||
release = '1.0.7'
|
||||
|
||||
# The language for content autogenerated by Sphinx. Refer to documentation
|
||||
# for a list of supported languages.
|
||||
#language = None
|
||||
|
||||
# There are two options for replacing |today|: either, you set today to some
|
||||
# non-false value, then it is used:
|
||||
#today = ''
|
||||
# Else, today_fmt is used as the format for a strftime call.
|
||||
#today_fmt = '%B %d, %Y'
|
||||
|
||||
# List of documents that shouldn't be included in the build.
|
||||
unused_docs = ['website_download']
|
||||
|
||||
# List of directories, relative to source directory, that shouldn't be searched
|
||||
# for source files.
|
||||
exclude_trees = ['_build']
|
||||
|
||||
# The reST default role (used for this markup: `text`) to use for all documents.
|
||||
#default_role = None
|
||||
|
||||
# If true, '()' will be appended to :func: etc. cross-reference text.
|
||||
#add_function_parentheses = True
|
||||
|
||||
# If true, the current module name will be prepended to all description
|
||||
# unit titles (such as .. function::).
|
||||
#add_module_names = True
|
||||
|
||||
# If true, sectionauthor and moduleauthor directives will be shown in the
|
||||
# output. They are ignored by default.
|
||||
#show_authors = False
|
||||
|
||||
# The name of the Pygments (syntax highlighting) style to use.
|
||||
pygments_style = 'sphinx'
|
||||
|
||||
# A list of ignored prefixes for module index sorting.
|
||||
#modindex_common_prefix = []
|
||||
|
||||
|
||||
rst_prolog = """
|
||||
.. role:: product(emphasis)
|
||||
:class: ci
|
||||
|
||||
.. |rjsmin| replace:: :product:`rJSmin`
|
||||
|
||||
.. role:: productb(strong)
|
||||
:class: ci
|
||||
|
||||
.. |**rjsmin**| replace:: :productb:`rJSmin`
|
||||
"""
|
||||
|
||||
# -- Options for epydoc extension-----------------------------------------------
|
||||
|
||||
epydoc = dict(
|
||||
rjsmin=os.path.join(os.path.abspath(os.path.pardir), 'apidoc'),
|
||||
)
|
||||
|
||||
# -- Options for HTML output ---------------------------------------------------
|
||||
|
||||
# The theme to use for HTML and HTML Help pages. Major themes that come with
|
||||
# Sphinx are currently 'default' and 'sphinxdoc'.
|
||||
html_theme = 'default'
|
||||
|
||||
# Theme options are theme-specific and customize the look and feel of a theme
|
||||
# further. For a list of options available for each theme, see the
|
||||
# documentation.
|
||||
if html_theme == 'nature':
|
||||
html_theme_options = {}
|
||||
elif html_theme == 'agogo':
|
||||
html_theme_options = dict(
|
||||
pagewidth='100%',
|
||||
documentwidth='80%',
|
||||
sidebarwidth='20%',
|
||||
)
|
||||
elif html_theme == 'scrolls':
|
||||
html_theme_options = {}
|
||||
elif html_theme == 'haiku':
|
||||
html_theme_options = {}
|
||||
else:
|
||||
html_theme_options = dict(
|
||||
rightsidebar=True,
|
||||
)
|
||||
|
||||
html_sidebars = {
|
||||
'**': ['localtoc.html', 'relations.html'],
|
||||
}
|
||||
|
||||
# Add any paths that contain custom themes here, relative to this directory.
|
||||
#html_theme_path = []
|
||||
|
||||
# The name for this set of Sphinx documents. If None, it defaults to
|
||||
# "<project> v<release> documentation".
|
||||
#html_title = None
|
||||
|
||||
# A shorter title for the navigation bar. Default is the same as html_title.
|
||||
#html_short_title = None
|
||||
|
||||
# The name of an image file (relative to this directory) to place at the top
|
||||
# of the sidebar.
|
||||
#html_logo = None
|
||||
|
||||
# The name of an image file (within the static path) to use as favicon of the
|
||||
# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
|
||||
# pixels large.
|
||||
#html_favicon = None
|
||||
|
||||
# Add any paths that contain custom static files (such as style sheets) here,
|
||||
# relative to this directory. They are copied after the builtin static files,
|
||||
# so a file named "default.css" will overwrite the builtin "default.css".
|
||||
html_static_path = ['_static']
|
||||
|
||||
# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
|
||||
# using the given strftime format.
|
||||
#html_last_updated_fmt = '%b %d, %Y'
|
||||
|
||||
# If true, SmartyPants will be used to convert quotes and dashes to
|
||||
# typographically correct entities.
|
||||
#html_use_smartypants = True
|
||||
|
||||
# Custom sidebar templates, maps document names to template names.
|
||||
#html_sidebars = {}
|
||||
|
||||
# Additional templates that should be rendered to pages, maps page names to
|
||||
# template names.
|
||||
#html_additional_pages = {}
|
||||
|
||||
# If false, no module index is generated.
|
||||
html_use_modindex = False
|
||||
|
||||
# If false, no index is generated.
|
||||
html_use_index = False
|
||||
|
||||
# If true, the index is split into individual pages for each letter.
|
||||
#html_split_index = False
|
||||
|
||||
# If true, links to the reST sources are added to the pages.
|
||||
html_show_sourcelink = False
|
||||
|
||||
# If true, an OpenSearch description file will be output, and all pages will
|
||||
# contain a <link> tag referring to it. The value of this option must be the
|
||||
# base URL from which the finished HTML is served.
|
||||
#html_use_opensearch = ''
|
||||
|
||||
# If nonempty, this is the file name suffix for HTML files (e.g. ".xhtml").
|
||||
#html_file_suffix = ''
|
||||
|
||||
# Output file base name for HTML help builder.
|
||||
htmlhelp_basename = 'rJSmindoc'
|
||||
|
||||
|
||||
# -- Options for LaTeX output --------------------------------------------------
|
||||
|
||||
# The paper size ('letter' or 'a4').
|
||||
#latex_paper_size = 'letter'
|
||||
|
||||
# The font size ('10pt', '11pt' or '12pt').
|
||||
#latex_font_size = '10pt'
|
||||
|
||||
# Grouping the document tree into LaTeX files. List of tuples
|
||||
# (source start file, target name, title, author, documentclass [howto/manual]).
|
||||
latex_documents = [
|
||||
('index', 'rjsmin.tex', u'rJSmin Documentation',
|
||||
u'Andr\xe9 "nd" Malo', 'manual'),
|
||||
]
|
||||
|
||||
# The name of an image file (relative to this directory) to place at the top of
|
||||
# the title page.
|
||||
#latex_logo = None
|
||||
|
||||
# For "manual" documents, if this is true, then toplevel headings are parts,
|
||||
# not chapters.
|
||||
#latex_use_parts = False
|
||||
|
||||
# Additional stuff for the LaTeX preamble.
|
||||
#latex_preamble = ''
|
||||
|
||||
# Documents to append as an appendix to all manuals.
|
||||
#latex_appendices = []
|
||||
|
||||
# If false, no module index is generated.
|
||||
#latex_use_modindex = True
|
130
docs/_userdoc/epydoc_sphinx.py
Normal file
130
docs/_userdoc/epydoc_sphinx.py
Normal file
@ -0,0 +1,130 @@
|
||||
# -*- coding: ascii -*-
|
||||
#
|
||||
# Copyright 2010, 2011
|
||||
# Andr\xe9 Malo or his licensors, as applicable
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
import os
|
||||
import posixpath
|
||||
|
||||
from docutils import nodes
|
||||
|
||||
from sphinx.util import caption_ref_re
|
||||
|
||||
|
||||
def relpath(path, start=os.path.curdir):
|
||||
"""Return a relative version of a path - stolen from python2.6 """
|
||||
|
||||
if not path:
|
||||
raise ValueError("no path specified")
|
||||
|
||||
start_list = os.path.abspath(start).split(sep)
|
||||
path_list = os.path.abspath(path).split(sep)
|
||||
|
||||
# Work out how much of the filepath is shared by start and path.
|
||||
i = len(os.path.commonprefix([start_list, path_list]))
|
||||
|
||||
rel_list = [os.path.pardir] * (len(start_list)-i) + path_list[i:]
|
||||
if not rel_list:
|
||||
return os.path.curdir
|
||||
return os.path.join(*rel_list)
|
||||
|
||||
try:
|
||||
relpath = os.path.relpath
|
||||
except AttributeError:
|
||||
pass
|
||||
|
||||
|
||||
def make_roles(app):
|
||||
""" Make roles """
|
||||
epydoc = app.config.epydoc
|
||||
if epydoc is not None:
|
||||
for name, basedir in epydoc.iteritems():
|
||||
app.add_role(name, make_epydoc_role(app, basedir))
|
||||
|
||||
|
||||
def make_epydoc_role(app, epydoc):
|
||||
""" Make a single role """
|
||||
try:
|
||||
fp = open(os.path.join(epydoc, 'api-objects.txt'))
|
||||
try:
|
||||
apis = dict([
|
||||
line.strip().split(None, 1) for line in fp if line.strip()
|
||||
])
|
||||
finally:
|
||||
fp.close()
|
||||
except IOError:
|
||||
app.warn("Epydoc description at %s not found" % (epydoc,))
|
||||
apis = {}
|
||||
|
||||
def epydoc_role(role, rawtext, text, lineno, inliner, options={},
|
||||
content=[]):
|
||||
""" Actual role callback """
|
||||
match = caption_ref_re.match(text)
|
||||
if match:
|
||||
extra, (text, ref) = True, match.group(1, 2)
|
||||
text = text.strip()
|
||||
if text.startswith('|') and text.endswith('|'):
|
||||
text = text[1:-1]
|
||||
extra = False
|
||||
else:
|
||||
extra, text, ref = False, None, text
|
||||
if ref.endswith('()'):
|
||||
ref = ref[:-2].strip()
|
||||
parens = text is None
|
||||
else:
|
||||
parens = False
|
||||
|
||||
if '/' in ref:
|
||||
chunks = ref.split('/', 1)
|
||||
if not chunks[0]: # Main page
|
||||
uri = 'index.html'
|
||||
else:
|
||||
uri = apis.get(''.join(chunks))
|
||||
if text is None:
|
||||
text = chunks[1]
|
||||
else:
|
||||
uri = apis.get(ref)
|
||||
if not text:
|
||||
text = ref
|
||||
if parens:
|
||||
text += '()'
|
||||
|
||||
if uri is None:
|
||||
node = nodes.literal(rawtext, text)
|
||||
else:
|
||||
baseuri = relpath(
|
||||
epydoc,
|
||||
os.path.dirname(inliner.document.current_source)
|
||||
).split(os.path.sep)
|
||||
for idx, elem in enumerate(baseuri):
|
||||
if elem == os.path.curdir:
|
||||
baseuri[idx] = '.'
|
||||
elif elem == os.path.pardir:
|
||||
baseuri[idx] = '..'
|
||||
baseuri = '/'.join(baseuri)
|
||||
uri = posixpath.join(baseuri, uri)
|
||||
if not extra:
|
||||
text =u'\u2192\xa0' + text
|
||||
node = nodes.reference(rawtext, text, refuri=uri, **options)
|
||||
if not extra:
|
||||
node = nodes.literal(rawtext, '', node)
|
||||
return [node], []
|
||||
|
||||
return epydoc_role
|
||||
|
||||
|
||||
def setup(app):
|
||||
app.add_config_value('epydoc', None, 'html')
|
||||
app.connect('builder-inited', make_roles)
|
149
docs/_userdoc/index.txt
Normal file
149
docs/_userdoc/index.txt
Normal file
@ -0,0 +1,149 @@
|
||||
.. license:
|
||||
Copyright 2011 - 2013
|
||||
André Malo or his licensors, as applicable
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
|
||||
==============================
|
||||
rJSmin - Javascript Minifier
|
||||
==============================
|
||||
|
||||
|**rJSmin**| is a javascript minifier written in python.
|
||||
|
||||
The minifier is based on the semantics of `jsmin.c by Douglas Crockford`_\.
|
||||
|
||||
The module is a re-implementation aiming for :doc:`speed <benchmark>`, so it
|
||||
can be used at runtime (rather than during a preprocessing step). Usually it
|
||||
produces the same results as the original ``jsmin.c``. It differs in the
|
||||
following ways:
|
||||
|
||||
- there is no error detection: unterminated string, regex and comment
|
||||
literals are treated as regular javascript code and minified as such.
|
||||
- Control characters inside string and regex literals are left untouched; they
|
||||
are not converted to spaces (nor to \n)
|
||||
- Newline characters are not allowed inside string and regex literals, except
|
||||
for line continuations in string literals (ECMA-5).
|
||||
- "``return /regex/``" is recognized correctly.
|
||||
- "``+ +``" and "``- -``" sequences are not collapsed to '``++``' or
|
||||
'``--``'
|
||||
- Newlines before ``!`` operators are removed more sensibly
|
||||
- |rJSmin| does not handle streams, but only complete strings. (However, the
|
||||
module provides a "streamy" interface).
|
||||
|
||||
Since most parts of the logic are handled by the regex engine it's way
|
||||
faster than the original python port of ``jsmin.c`` by Baruch Even. The speed
|
||||
factor varies between about 6 and 55 depending on input and python version
|
||||
(it gets faster the more compressed the input already is). Compared to the
|
||||
speed-refactored python port by Dave St.Germain the performance gain is less
|
||||
dramatic but still between 1.2 and 7.
|
||||
|
||||
|rjsmin| comes with an optional C-reimplementation of the python/regex
|
||||
implementation, which speeds up the minifying process even more.
|
||||
|
||||
|rjsmin| works with both python 2 (starting with python 2.4) and python 3.
|
||||
|
||||
.. _jsmin.c by Douglas Crockford: http://www.crockford.com/javascript/jsmin.c
|
||||
|
||||
|
||||
Documentation
|
||||
~~~~~~~~~~~~~
|
||||
|
||||
A :rjsmin:`generated API documentation </>` is available. But you can
|
||||
just look into the module. It provides a simple function, called
|
||||
``jsmin`` which takes the script as a string and returns the minified
|
||||
script as a string.
|
||||
|
||||
The module additionally provides a "streamy" interface similar to the
|
||||
one jsmin.c provides:
|
||||
|
||||
.. sourcecode:: console
|
||||
|
||||
$ python -mrjsmin <script >minified
|
||||
|
||||
|
||||
Development Status
|
||||
~~~~~~~~~~~~~~~~~~
|
||||
|
||||
|rjsmin| is stable.
|
||||
|
||||
|
||||
License
|
||||
~~~~~~~
|
||||
|
||||
|rjsmin| is available under the terms and conditions of the "Apache License,
|
||||
Version 2.0." You'll find the detailed licensing terms in the root
|
||||
directory of the source distribution package or online at
|
||||
`http://www.apache.org/licenses/LICENSE-2.0
|
||||
<http://www.apache.org/licenses/LICENSE-2.0>`_.
|
||||
|
||||
|
||||
.. placeholder: Download
|
||||
|
||||
|
||||
Author Information
|
||||
~~~~~~~~~~~~~~~~~~
|
||||
|
||||
|rjsmin| was written and is maintained by André Malo.
|
||||
|
||||
|
||||
Acknowledgements
|
||||
----------------
|
||||
|
||||
- `Douglas Crockford <http://www.crockford.com/>`_
|
||||
- `Jeffrey Friedl <http://regex.info/>`_
|
||||
|
||||
|
||||
Trivia / Fun
|
||||
~~~~~~~~~~~~
|
||||
|
||||
|rJSmin| is a single pass substitution using a simple regular expression,
|
||||
which looks like this:
|
||||
|
||||
.. sourcecode:: text
|
||||
|
||||
pattern = (
|
||||
r'([^\047"/\000-\040]+)|((?:(?:\047[^\047\\\r\n]*(?:\\(?:[^\r\n]|\r?'
|
||||
r'\n|\r)[^\047\\\r\n]*)*\047)|(?:"[^"\\\r\n]*(?:\\(?:[^\r\n]|\r?\n|'
|
||||
r'\r)[^"\\\r\n]*)*"))[^\047"/\000-\040]*)|(?<=[(,=:\[!&|?{};\r\n])(?'
|
||||
r':[\000-\011\013\014\016-\040]|(?:/\*[^*]*\*+(?:[^/*][^*]*\*+)*/))*'
|
||||
r'(?:(?:(?://[^\r\n]*)?[\r\n])(?:[\000-\011\013\014\016-\040]|(?:/\*'
|
||||
r'[^*]*\*+(?:[^/*][^*]*\*+)*/))*)*((?:/(?![\r\n/*])[^/\\\[\r\n]*(?:('
|
||||
r'?:\\[^\r\n]|(?:\[[^\\\]\r\n]*(?:\\[^\r\n][^\\\]\r\n]*)*\]))[^/\\\['
|
||||
r'\r\n]*)*/)[^\047"/\000-\040]*)|(?<=[\000-#%-,./:-@\[-^`{-~-]return'
|
||||
r')(?:[\000-\011\013\014\016-\040]|(?:/\*[^*]*\*+(?:[^/*][^*]*\*+)*/'
|
||||
r'))*(?:(?:(?://[^\r\n]*)?[\r\n])(?:[\000-\011\013\014\016-\040]|(?:'
|
||||
r'/\*[^*]*\*+(?:[^/*][^*]*\*+)*/)))*((?:/(?![\r\n/*])[^/\\\[\r\n]*(?'
|
||||
r':(?:\\[^\r\n]|(?:\[[^\\\]\r\n]*(?:\\[^\r\n][^\\\]\r\n]*)*\]))[^/'
|
||||
r'\\\[\r\n]*)*/)[^\047"/\000-\040]*)|(?<=[^\000-!#%&(*,./:-@\[\\^`{|'
|
||||
r'~])(?:[\000-\011\013\014\016-\040]|(?:/\*[^*]*\*+(?:[^/*][^*]*\*+)'
|
||||
r'*/))*(?:((?:(?://[^\r\n]*)?[\r\n]))(?:[\000-\011\013\014\016-\040]'
|
||||
r'|(?:/\*[^*]*\*+(?:[^/*][^*]*\*+)*/))*)+(?=[^\000-\040"#%-\047)*,./'
|
||||
r':-@\\-^`|-~])|(?<=[^\000-#%-,./:-@\[-^`{-~-])((?:[\000-\011\013\01'
|
||||
r'4\016-\040]|(?:/\*[^*]*\*+(?:[^/*][^*]*\*+)*/)))+(?=[^\000-#%-,./:'
|
||||
r'-@\[-^`{-~-])|(?<=\+)((?:[\000-\011\013\014\016-\040]|(?:/\*[^*]*'
|
||||
r'\*+(?:[^/*][^*]*\*+)*/)))+(?=\+)|(?<=-)((?:[\000-\011\013\014\016-'
|
||||
r'\040]|(?:/\*[^*]*\*+(?:[^/*][^*]*\*+)*/)))+(?=-)|(?:[\000-\011\013'
|
||||
r'\014\016-\040]|(?:/\*[^*]*\*+(?:[^/*][^*]*\*+)*/))+|(?:(?:(?://[^'
|
||||
r'\r\n]*)?[\r\n])(?:[\000-\011\013\014\016-\040]|(?:/\*[^*]*\*+(?:[^'
|
||||
r'/*][^*]*\*+)*/))*)+'
|
||||
)
|
||||
|
||||
|
||||
Related
|
||||
~~~~~~~
|
||||
|
||||
- `CSS Minifier rCSSmin <http://opensource.perlig.de/rcssmin/>`_
|
||||
|
||||
|
||||
.. vim: ft=rest tw=72
|
57
docs/_userdoc/website_download.txt
Normal file
57
docs/_userdoc/website_download.txt
Normal file
@ -0,0 +1,57 @@
|
||||
Download
|
||||
~~~~~~~~
|
||||
|
||||
Change Log
|
||||
----------
|
||||
|
||||
`CHANGES file <http://storage.perlig.de/rjsmin/CHANGES-1.0.7>`_
|
||||
|
||||
|
||||
Source Packages
|
||||
---------------
|
||||
|
||||
.. begin stable
|
||||
|
||||
Current Stable Version
|
||||
''''''''''''''''''''''
|
||||
|
||||
- `rjsmin-1.0.7.tar.xz <http://storage.perlig.de/rjsmin/rjsmin-1.0.7.tar.xz>`_
|
||||
- `rjsmin-1.0.7.tar.bz2 <http://storage.perlig.de/rjsmin/rjsmin-1.0.7.tar.bz2>`_
|
||||
- `rjsmin-1.0.7.tar.gz <http://storage.perlig.de/rjsmin/rjsmin-1.0.7.tar.gz>`_
|
||||
- `rjsmin-1.0.7.zip <http://storage.perlig.de/rjsmin/rjsmin-1.0.7.zip>`_
|
||||
- `rjsmin-1.0.7.digests <http://storage.perlig.de/rjsmin/rjsmin-1.0.7.digests>`_
|
||||
|
||||
.. end stable
|
||||
|
||||
|
||||
Integrity Check
|
||||
---------------
|
||||
|
||||
There are hashes (MD5, SHA1 and SHA256) of the download packages stored
|
||||
in the `digests file
|
||||
<http://storage.perlig.de/rjsmin/rjsmin-1.0.7.digests>`_\.
|
||||
In order to check the integrity of the downloaded file, use a tool like
|
||||
md5sum (or sha1sum, sha256sum accordingly), e.g.:
|
||||
|
||||
.. sourcecode:: console
|
||||
|
||||
$ md5sum -c rjsmin-1.0.7.digests
|
||||
rjsmin-1.0.7.tar.bz2: OK
|
||||
rjsmin-1.0.7.tar.gz: OK
|
||||
rjsmin-1.0.7.tar.xz: OK
|
||||
rjsmin-1.0.7.zip: OK
|
||||
|
||||
In order to check the integrity of the digest file itself, you can check
|
||||
the PGP signature of that file. The file is signed by André Malo, Key-ID
|
||||
0x8103A37E:
|
||||
|
||||
.. sourcecode:: console
|
||||
|
||||
$ gpg --verify rjsmin-1.0.7.digests
|
||||
gpg: Signature made Sun Jun 30 16:10:42 2013 CEST using DSA key ID 8103A37E
|
||||
gpg: Good signature from "Andre Malo <nd@apache.org>"
|
||||
gpg: aka "Andr\xe9\x20Malo <nd@perlig.de>"
|
||||
gpg: aka "Andre Malo <ndparker@gmx.net>"
|
||||
|
||||
|
||||
.. vim: ft=rest tw=72
|
57
docs/_userdoc/website_download.txt.in
Normal file
57
docs/_userdoc/website_download.txt.in
Normal file
@ -0,0 +1,57 @@
|
||||
Download
|
||||
~~~~~~~~
|
||||
|
||||
Change Log
|
||||
----------
|
||||
|
||||
`CHANGES file <http://storage.perlig.de/rjsmin/CHANGES-@@VERSION@@>`_
|
||||
|
||||
|
||||
Source Packages
|
||||
---------------
|
||||
|
||||
.. begin stable
|
||||
|
||||
Current Stable Version
|
||||
''''''''''''''''''''''
|
||||
|
||||
- `rjsmin-@@VERSION@@.tar.xz <http://storage.perlig.de/rjsmin/rjsmin-@@VERSION@@.tar.xz>`_
|
||||
- `rjsmin-@@VERSION@@.tar.bz2 <http://storage.perlig.de/rjsmin/rjsmin-@@VERSION@@.tar.bz2>`_
|
||||
- `rjsmin-@@VERSION@@.tar.gz <http://storage.perlig.de/rjsmin/rjsmin-@@VERSION@@.tar.gz>`_
|
||||
- `rjsmin-@@VERSION@@.zip <http://storage.perlig.de/rjsmin/rjsmin-@@VERSION@@.zip>`_
|
||||
- `rjsmin-@@VERSION@@.digests <http://storage.perlig.de/rjsmin/rjsmin-@@VERSION@@.digests>`_
|
||||
|
||||
.. end stable
|
||||
|
||||
|
||||
Integrity Check
|
||||
---------------
|
||||
|
||||
There are hashes (MD5, SHA1 and SHA256) of the download packages stored
|
||||
in the `digests file
|
||||
<http://storage.perlig.de/rjsmin/@@PATH@@rjsmin-@@VERSION@@.digests>`_\.
|
||||
In order to check the integrity of the downloaded file, use a tool like
|
||||
md5sum (or sha1sum, sha256sum accordingly), e.g.:
|
||||
|
||||
.. sourcecode:: console
|
||||
|
||||
$ md5sum -c rjsmin-@@VERSION@@.digests
|
||||
rjsmin-@@VERSION@@.tar.bz2: OK
|
||||
rjsmin-@@VERSION@@.tar.gz: OK
|
||||
rjsmin-@@VERSION@@.tar.xz: OK
|
||||
rjsmin-@@VERSION@@.zip: OK
|
||||
|
||||
In order to check the integrity of the digest file itself, you can check
|
||||
the PGP signature of that file. The file is signed by André Malo, Key-ID
|
||||
0x8103A37E:
|
||||
|
||||
.. sourcecode:: console
|
||||
|
||||
$ gpg --verify rjsmin-@@VERSION@@.digests
|
||||
gpg: Signature made Sun Jun 30 16:10:42 2013 CEST using DSA key ID 8103A37E
|
||||
gpg: Good signature from "Andre Malo <nd@apache.org>"
|
||||
gpg: aka "Andr\xe9\x20Malo <nd@perlig.de>"
|
||||
gpg: aka "Andre Malo <ndparker@gmx.net>"
|
||||
|
||||
|
||||
.. vim: ft=rest tw=72
|
22
docs/epydoc.conf
Normal file
22
docs/epydoc.conf
Normal file
@ -0,0 +1,22 @@
|
||||
[epydoc]
|
||||
|
||||
verbosity = 1
|
||||
modules =
|
||||
rjsmin
|
||||
|
||||
output = html
|
||||
url = http://opensource.perlig.de/rjsmin/
|
||||
link = <a href="http://opensource.perlig.de/rjsmin/" target="_top">Visit rjsmin Online</a>
|
||||
top = rjsmin
|
||||
frames = no
|
||||
sourcecode = yes
|
||||
|
||||
#graphs are ugly
|
||||
#graph = classtree
|
||||
|
||||
target = docs/apidoc/
|
||||
docformat = plaintext
|
||||
|
||||
private = no
|
||||
parse = yes
|
||||
introspect = yes
|
78
gen_chartable.py
Executable file
78
gen_chartable.py
Executable file
@ -0,0 +1,78 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: ascii -*-
|
||||
#
|
||||
# Copyright 2011
|
||||
# Andr\xe9 Malo or his licensors, as applicable
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
import re as _re
|
||||
|
||||
TPL = r"""
|
||||
static const unsigned short rjsmin_charmask[128] = {
|
||||
@@mask@@
|
||||
};
|
||||
""".strip() + "\n"
|
||||
|
||||
def _make_charmask():
|
||||
dull = r'[^\047"/\000-\040]'
|
||||
pre_regex = r'[(,=:\[!&|?{};\r\n]'
|
||||
regex_dull = r'[^/\\\[\r\n]'
|
||||
regex_cc_dull = r'[^\\\]\r\n]'
|
||||
|
||||
newline = r'[\r\n]'
|
||||
|
||||
id_literal = r'[^\000-#%-,./:-@\[-^`{-~-]'
|
||||
id_literal_open = r'[^\000-\040"#%-\047)*,./:-@\\-^`|-~]'
|
||||
id_literal_close = r'[^\000-!#%&(*,./:-@\[\\^`{|~]'
|
||||
|
||||
string_dull = r'[^\047"\\\r\n]'
|
||||
|
||||
space = r'[\000-\011\013\014\016-\040]'
|
||||
|
||||
charmask = []
|
||||
for x in range(8):
|
||||
maskline = []
|
||||
for y in range(16):
|
||||
c, mask = chr(x*16 + y), 0
|
||||
if _re.match(dull, c):
|
||||
mask |= 1
|
||||
if _re.match(pre_regex, c):
|
||||
mask |= 2
|
||||
if _re.match(regex_dull, c):
|
||||
mask |= 4
|
||||
if _re.match(regex_cc_dull, c):
|
||||
mask |= 8
|
||||
if _re.match(id_literal, c):
|
||||
mask |= 16
|
||||
if _re.match(id_literal_open, c):
|
||||
mask |= 32
|
||||
if _re.match(id_literal_close, c):
|
||||
mask |= 64
|
||||
if _re.match(string_dull, c):
|
||||
mask |= 128
|
||||
if _re.match(space, c):
|
||||
mask |= 256
|
||||
|
||||
if mask < 10:
|
||||
mask = ' ' + str(mask)
|
||||
elif mask < 100:
|
||||
mask = ' ' + str(mask)
|
||||
maskline.append(str(mask))
|
||||
if y == 7:
|
||||
charmask.append(', '.join(maskline))
|
||||
maskline = []
|
||||
charmask.append(', '.join(maskline))
|
||||
return TPL.replace('@@mask@@', ',\n '.join(charmask))
|
||||
|
||||
print _make_charmask()
|
618
make.py
Executable file
618
make.py
Executable file
@ -0,0 +1,618 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: ascii -*-
|
||||
#
|
||||
# Copyright 2006 - 2013
|
||||
# Andr\xe9 Malo or his licensors, as applicable
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
"""
|
||||
===============
|
||||
Build targets
|
||||
===============
|
||||
|
||||
Build targets.
|
||||
"""
|
||||
__author__ = "Andr\xe9 Malo"
|
||||
__author__ = getattr(__author__, 'decode', lambda x: __author__)('latin-1')
|
||||
__docformat__ = "restructuredtext en"
|
||||
|
||||
import errno as _errno
|
||||
import os as _os
|
||||
import re as _re
|
||||
import sys as _sys
|
||||
|
||||
from _setup import dist
|
||||
from _setup import shell
|
||||
from _setup import make
|
||||
from _setup import term
|
||||
from _setup.make import targets, default_targets
|
||||
|
||||
|
||||
class Target(make.Target):
|
||||
def init(self):
|
||||
self.dirs = {
|
||||
'lib': '.',
|
||||
'docs': 'docs',
|
||||
'apidoc': 'docs/apidoc',
|
||||
'userdoc': 'docs/userdoc',
|
||||
'userdoc_source': 'docs/_userdoc',
|
||||
'userdoc_build': 'docs/_userdoc/_build',
|
||||
'website': 'dist/website',
|
||||
'_website': '_website', # source dir
|
||||
'dist': 'dist',
|
||||
'build': 'build',
|
||||
'bench': 'bench',
|
||||
'ebuild': '_pkg/ebuilds',
|
||||
}
|
||||
libpath = shell.native(self.dirs['lib'])
|
||||
if libpath != _sys.path[0]:
|
||||
while libpath in _sys.path:
|
||||
_sys.path.remove(libpath)
|
||||
_sys.path.insert(0, libpath)
|
||||
|
||||
self.ebuild_files = {
|
||||
'rjsmin.ebuild.in':
|
||||
'rjsmin-%(VERSION)s.ebuild',
|
||||
}
|
||||
|
||||
|
||||
Manifest = targets.Manifest
|
||||
|
||||
class Distribution(targets.Distribution):
|
||||
def init(self):
|
||||
self._dist = 'dist'
|
||||
self._ebuilds = '_pkg/ebuilds'
|
||||
self._changes = 'docs/CHANGES'
|
||||
|
||||
|
||||
class MakefileTarget(default_targets.MakefileTarget):
|
||||
def extend(self, names):
|
||||
names.append('jsmin')
|
||||
return '\n\n'.join([
|
||||
'jsmin: bench/jsmin',
|
||||
'bench/jsmin: bench/jsmin.c\n\tgcc -o bench/jsmin bench/jsmin.c',
|
||||
])
|
||||
|
||||
|
||||
class Benchmark(Target):
|
||||
""" Benchmark """
|
||||
NAME = "bench"
|
||||
DEPS = ["compile-quiet"]
|
||||
python = None
|
||||
|
||||
def run(self):
|
||||
files = list(shell.files(self.dirs['bench'], '*.js'))
|
||||
if self.python is None:
|
||||
python = _sys.executable
|
||||
else:
|
||||
python = shell.frompath(self.python)
|
||||
return not shell.spawn(*[
|
||||
python,
|
||||
shell.native('bench.py'),
|
||||
'-c10'
|
||||
] + files)
|
||||
|
||||
def clean(self, scm, dist):
|
||||
term.green("Removing bytecode files...")
|
||||
for filename in shell.dirs('.', '__pycache__'):
|
||||
shell.rm_rf(filename)
|
||||
for filename in shell.files('.', '*.py[co]'):
|
||||
shell.rm(filename)
|
||||
for filename in shell.files('.', '*$py.class'):
|
||||
shell.rm(filename)
|
||||
shell.rm(shell.native('bench/jsmin'))
|
||||
|
||||
|
||||
class Benchmark2(Benchmark):
|
||||
""" Benchmark """
|
||||
NAME = "bench2"
|
||||
python = "python2"
|
||||
|
||||
def clean(self, scm, dist):
|
||||
pass
|
||||
|
||||
|
||||
class Benchmark3(Benchmark):
|
||||
""" Benchmark """
|
||||
NAME = "bench3"
|
||||
python = "python3"
|
||||
|
||||
def clean(self, scm, dist):
|
||||
pass
|
||||
|
||||
|
||||
class Check(Target):
|
||||
""" Check the python code """
|
||||
NAME = "check"
|
||||
DEPS = ["compile-quiet"]
|
||||
|
||||
def run(self):
|
||||
from _setup.dev import analysis
|
||||
term.green('Linting rjsmin sources...')
|
||||
res = analysis.pylint('_pkg/pylint.conf', 'rjsmin')
|
||||
if res == 2:
|
||||
make.warn('pylint not found', self.NAME)
|
||||
|
||||
|
||||
class Compile(Target):
|
||||
""" Compile the python code """
|
||||
NAME = "compile"
|
||||
#DEPS = None
|
||||
|
||||
def run(self):
|
||||
import setup
|
||||
|
||||
_old_argv = _sys.argv
|
||||
try:
|
||||
_sys.argv = ['setup.py', '-q', 'build']
|
||||
if not self.HIDDEN:
|
||||
_sys.argv.remove('-q')
|
||||
setup.setup()
|
||||
if 'java' not in _sys.platform.lower():
|
||||
_sys.argv = [
|
||||
'setup.py', '-q', 'install_lib', '--install-dir',
|
||||
shell.native(self.dirs['lib']),
|
||||
'--optimize', '2',
|
||||
]
|
||||
if not self.HIDDEN:
|
||||
_sys.argv.remove('-q')
|
||||
setup.setup()
|
||||
finally:
|
||||
_sys.argv = _old_argv
|
||||
|
||||
self.compile('rjsmin.py')
|
||||
term.write("%(ERASE)s")
|
||||
|
||||
term.green("All files successfully compiled.")
|
||||
|
||||
def compile(self, name):
|
||||
path = shell.native(name)
|
||||
term.write("%(ERASE)s%(BOLD)s>>> Compiling %(name)s...%(NORMAL)s",
|
||||
name=name)
|
||||
from distutils import util
|
||||
try:
|
||||
from distutils import log
|
||||
except ImportError:
|
||||
util.byte_compile([path], verbose=0, force=True)
|
||||
else:
|
||||
log.set_verbosity(0)
|
||||
util.byte_compile([path], force=True)
|
||||
|
||||
def clean(self, scm, dist):
|
||||
term.green("Removing python byte code...")
|
||||
for name in shell.dirs('.', '__pycache__'):
|
||||
shell.rm_rf(name)
|
||||
for name in shell.files('.', '*.py[co]'):
|
||||
shell.rm(name)
|
||||
|
||||
term.green("Removing c extensions...")
|
||||
for name in shell.files('.', '*.so'):
|
||||
shell.rm(name)
|
||||
for name in shell.files('.', '*.pyd'):
|
||||
shell.rm(name)
|
||||
|
||||
shell.rm_rf(self.dirs['build'])
|
||||
|
||||
|
||||
class CompileQuiet(Compile):
|
||||
NAME = "compile-quiet"
|
||||
HIDDEN = True
|
||||
|
||||
def clean(self, scm, dist):
|
||||
pass
|
||||
|
||||
|
||||
class Doc(Target):
|
||||
""" Build the docs (api + user) """
|
||||
NAME = "doc"
|
||||
DEPS = ['apidoc', 'userdoc']
|
||||
|
||||
|
||||
class ApiDoc(Target):
|
||||
""" Build the API docs """
|
||||
NAME = "apidoc"
|
||||
|
||||
def run(self):
|
||||
from _setup.dev import apidoc
|
||||
apidoc.epydoc(
|
||||
prepend=[
|
||||
shell.native(self.dirs['lib']),
|
||||
],
|
||||
)
|
||||
|
||||
def clean(self, scm, dist):
|
||||
if scm:
|
||||
term.green("Removing apidocs...")
|
||||
shell.rm_rf(self.dirs['apidoc'])
|
||||
|
||||
|
||||
class UserDoc(Target):
|
||||
""" Build the user docs """
|
||||
NAME = "userdoc"
|
||||
#DEPS = None
|
||||
|
||||
def run(self):
|
||||
from _setup.dev import userdoc
|
||||
userdoc.sphinx(
|
||||
build=shell.native(self.dirs['userdoc_build']),
|
||||
source=shell.native(self.dirs['userdoc_source']),
|
||||
target=shell.native(self.dirs['userdoc']),
|
||||
)
|
||||
|
||||
def clean(self, scm, dist):
|
||||
if scm:
|
||||
term.green("Removing userdocs...")
|
||||
shell.rm_rf(self.dirs['userdoc'])
|
||||
shell.rm_rf(self.dirs['userdoc_build'])
|
||||
|
||||
|
||||
class Website(Target):
|
||||
""" Build the website """
|
||||
NAME = "website"
|
||||
DEPS = ["apidoc"]
|
||||
|
||||
def run(self):
|
||||
from _setup.util import SafeConfigParser as parser
|
||||
parser = parser()
|
||||
parser.read('package.cfg')
|
||||
strversion = parser.get('package', 'version.number')
|
||||
shortversion = tuple(map(int, strversion.split('.')[:2]))
|
||||
|
||||
shell.rm_rf(self.dirs['_website'])
|
||||
shell.cp_r(
|
||||
self.dirs['userdoc_source'],
|
||||
_os.path.join(self.dirs['_website'], 'src')
|
||||
)
|
||||
shell.rm_rf(_os.path.join(self.dirs['_website'], 'build'))
|
||||
shell.rm_rf(self.dirs['website'])
|
||||
_os.makedirs(self.dirs['website'])
|
||||
filename = _os.path.join(
|
||||
self.dirs['_website'], 'src', 'website_download.txt'
|
||||
)
|
||||
fp = open(filename)
|
||||
try:
|
||||
download = fp.read()
|
||||
finally:
|
||||
fp.close()
|
||||
filename = _os.path.join(self.dirs['_website'], 'src', 'index.txt')
|
||||
fp = open(filename)
|
||||
try:
|
||||
indexlines = fp.readlines()
|
||||
finally:
|
||||
fp.close()
|
||||
|
||||
fp = open(filename, 'w')
|
||||
try:
|
||||
for line in indexlines:
|
||||
if line.startswith('.. placeholder: Download'):
|
||||
line = download
|
||||
fp.write(line)
|
||||
finally:
|
||||
fp.close()
|
||||
|
||||
shell.cp_r(
|
||||
self.dirs['apidoc'],
|
||||
_os.path.join(self.dirs['website'], 'doc-%d.%d' % shortversion)
|
||||
)
|
||||
shell.cp_r(
|
||||
self.dirs['apidoc'],
|
||||
_os.path.join(
|
||||
self.dirs['_website'], 'src', 'doc-%d.%d' % shortversion
|
||||
)
|
||||
)
|
||||
fp = open(_os.path.join(
|
||||
self.dirs['_website'], 'src', 'conf.py'
|
||||
), 'a')
|
||||
try:
|
||||
fp.write("\nepydoc = dict(rjsmin=%r)\n" % (
|
||||
_os.path.join(
|
||||
shell.native(self.dirs['_website']),
|
||||
"src",
|
||||
"doc-%d.%d" % shortversion,
|
||||
),
|
||||
))
|
||||
fp.write("\nexclude_trees.append(%r)\n" %
|
||||
"doc-%d.%d" % shortversion
|
||||
)
|
||||
finally:
|
||||
fp.close()
|
||||
from _setup.dev import userdoc
|
||||
userdoc.sphinx(
|
||||
build=shell.native(_os.path.join(self.dirs['_website'], 'build')),
|
||||
source=shell.native(_os.path.join(self.dirs['_website'], 'src')),
|
||||
target=shell.native(self.dirs['website']),
|
||||
)
|
||||
shell.rm(_os.path.join(self.dirs['website'], '.buildinfo'))
|
||||
|
||||
def clean(self, scm, dist):
|
||||
if scm:
|
||||
term.green("Removing website...")
|
||||
shell.rm_rf(self.dirs['website'])
|
||||
shell.rm_rf(self.dirs['_website'])
|
||||
|
||||
|
||||
class PreCheck(Target):
|
||||
""" Run clean, doc, check """
|
||||
NAME = "precheck"
|
||||
DEPS = ["clean", "doc", "check"]
|
||||
|
||||
|
||||
class SVNRelease(Target):
|
||||
""" Release current version """
|
||||
#NAME = "release"
|
||||
DEPS = None
|
||||
|
||||
def run(self):
|
||||
self._check_committed()
|
||||
self._update_versions()
|
||||
self._tag_release()
|
||||
self.runner('dist', seen={})
|
||||
|
||||
def _tag_release(self):
|
||||
""" Tag release """
|
||||
from _setup.util import SafeConfigParser as parser
|
||||
parser = parser()
|
||||
parser.read('package.cfg')
|
||||
strversion = parser.get('package', 'version.number')
|
||||
version = strversion
|
||||
trunk_url = self._repo_url()
|
||||
if not trunk_url.endswith('/trunk'):
|
||||
rex = _re.compile(r'/branches/\d+(?:\.\d+)*\.[xX]$').search
|
||||
match = rex(trunk_url)
|
||||
if not match:
|
||||
make.fail("Not in trunk or release branch!")
|
||||
found = match.start(0)
|
||||
else:
|
||||
found = -len('/trunk')
|
||||
release_url = trunk_url[:found] + '/releases/' + version
|
||||
|
||||
svn = shell.frompath('svn')
|
||||
shell.spawn(
|
||||
svn, 'copy', '-m', 'Release version ' + version, '--',
|
||||
trunk_url, release_url,
|
||||
echo=True,
|
||||
)
|
||||
|
||||
def _update_versions(self):
|
||||
""" Update versions """
|
||||
self.runner('version', seen={})
|
||||
svn = shell.frompath('svn')
|
||||
shell.spawn(svn, 'commit', '-m', 'Pre-release: version update',
|
||||
echo=True
|
||||
)
|
||||
|
||||
def _repo_url(self):
|
||||
""" Determine URL """
|
||||
from xml.dom import minidom
|
||||
svn = shell.frompath('svn')
|
||||
info = minidom.parseString(
|
||||
shell.spawn(svn, 'info', '--xml', stdout=True)
|
||||
)
|
||||
try:
|
||||
url = info.getElementsByTagName('url')[0]
|
||||
text = []
|
||||
for node in url.childNodes:
|
||||
if node.nodeType == node.TEXT_NODE:
|
||||
text.append(node.data)
|
||||
finally:
|
||||
info.unlink()
|
||||
return ''.join(text).encode('utf-8')
|
||||
|
||||
def _check_committed(self):
|
||||
""" Check if everything is committed """
|
||||
if not self._repo_url().endswith('/trunk'):
|
||||
rex = _re.compile(r'/branches/\d+(?:\.\d+)*\.[xX]$').search
|
||||
match = rex(self._repo_url())
|
||||
if not match:
|
||||
make.fail("Not in trunk or release branch!")
|
||||
svn = shell.frompath('svn')
|
||||
lines = shell.spawn(svn, 'stat', '--ignore-externals',
|
||||
stdout=True, env=dict(_os.environ, LC_ALL='C'),
|
||||
).splitlines()
|
||||
for line in lines:
|
||||
if line.startswith('X'):
|
||||
continue
|
||||
make.fail("Uncommitted changes!")
|
||||
|
||||
|
||||
class GitRelease(Target):
|
||||
""" Release current version """
|
||||
#NAME = "release"
|
||||
DEPS = None
|
||||
|
||||
def run(self):
|
||||
self._check_committed()
|
||||
self._update_versions()
|
||||
self._tag_release()
|
||||
self.runner('dist', seen={})
|
||||
|
||||
def _tag_release(self):
|
||||
""" Tag release """
|
||||
from _setup.util import SafeConfigParser as parser
|
||||
parser = parser()
|
||||
parser.read('package.cfg')
|
||||
strversion = parser.get('package', 'version.number')
|
||||
version = strversion
|
||||
git = shell.frompath('git')
|
||||
shell.spawn(
|
||||
git, 'tag', '-a', '-m', 'Release version ' + version, '--',
|
||||
version,
|
||||
echo=True,
|
||||
)
|
||||
|
||||
def _update_versions(self):
|
||||
""" Update versions """
|
||||
self.runner('version', seen={})
|
||||
git = shell.frompath('git')
|
||||
shell.spawn(git, 'commit', '-a', '-m', 'Pre-release: version update',
|
||||
echo=True
|
||||
)
|
||||
|
||||
def _check_committed(self):
|
||||
""" Check if everything is committed """
|
||||
git = shell.frompath('git')
|
||||
lines = shell.spawn(git, 'branch', '--color=never',
|
||||
stdout=True, env=dict(_os.environ, LC_ALL='C')
|
||||
).splitlines()
|
||||
for line in lines:
|
||||
if line.startswith('*'):
|
||||
branch = line.split(None, 1)[1]
|
||||
break
|
||||
else:
|
||||
make.fail("Could not determine current branch.")
|
||||
if branch != 'master':
|
||||
rex = _re.compile(r'^\d+(?:\.\d+)*\.[xX]$').match
|
||||
match = rex(branch)
|
||||
if not match:
|
||||
make.fail("Not in master or release branch.")
|
||||
|
||||
lines = shell.spawn(git, 'status', '--porcelain',
|
||||
stdout=True, env=dict(_os.environ, LC_ALL='C'),
|
||||
)
|
||||
if lines:
|
||||
make.fail("Uncommitted changes!")
|
||||
|
||||
|
||||
class Release(GitRelease):
|
||||
NAME = "release"
|
||||
#DEPS = None
|
||||
|
||||
|
||||
class Version(Target):
|
||||
""" Insert the program version into all relevant files """
|
||||
NAME = "version"
|
||||
#DEPS = None
|
||||
|
||||
def run(self):
|
||||
from _setup.util import SafeConfigParser as parser
|
||||
parser = parser()
|
||||
parser.read('package.cfg')
|
||||
strversion = parser.get('package', 'version.number')
|
||||
|
||||
self._version_init(strversion)
|
||||
self._version_userdoc(strversion)
|
||||
self._version_download(strversion)
|
||||
self._version_changes(strversion)
|
||||
|
||||
parm = {'VERSION': strversion}
|
||||
for src, dest in self.ebuild_files.items():
|
||||
src = "%s/%s" % (self.dirs['ebuild'], src)
|
||||
dest = "%s/%s" % (self.dirs['ebuild'], dest % parm)
|
||||
term.green("Creating %(name)s...", name=dest)
|
||||
shell.cp(src, dest)
|
||||
|
||||
def _version_init(self, strversion):
|
||||
""" Modify version in __init__ """
|
||||
filename = _os.path.join(self.dirs['lib'], 'rjsmin.py')
|
||||
fp = open(filename)
|
||||
try:
|
||||
initlines = fp.readlines()
|
||||
finally:
|
||||
fp.close()
|
||||
fp = open(filename, 'w')
|
||||
replaced = False
|
||||
try:
|
||||
for line in initlines:
|
||||
if line.startswith('__version__'):
|
||||
line = '__version__ = %r\n' % (strversion,)
|
||||
replaced = True
|
||||
fp.write(line)
|
||||
finally:
|
||||
fp.close()
|
||||
assert replaced, "__version__ not found in rjsmin.py"
|
||||
|
||||
def _version_changes(self, strversion):
|
||||
""" Modify version in changes """
|
||||
filename = _os.path.join(shell.native(self.dirs['docs']), 'CHANGES')
|
||||
fp = open(filename)
|
||||
try:
|
||||
initlines = fp.readlines()
|
||||
finally:
|
||||
fp.close()
|
||||
fp = open(filename, 'w')
|
||||
try:
|
||||
for line in initlines:
|
||||
if line.rstrip() == "Changes with version":
|
||||
line = "%s %s\n" % (line.rstrip(), strversion)
|
||||
fp.write(line)
|
||||
finally:
|
||||
fp.close()
|
||||
|
||||
def _version_userdoc(self, strversion):
|
||||
""" Modify version in userdoc """
|
||||
filename = _os.path.join(self.dirs['userdoc_source'], 'conf.py')
|
||||
shortversion = '.'.join(strversion.split('.')[:2])
|
||||
longversion = strversion
|
||||
fp = open(filename)
|
||||
try:
|
||||
initlines = fp.readlines()
|
||||
finally:
|
||||
fp.close()
|
||||
replaced = 0
|
||||
fp = open(filename, 'w')
|
||||
try:
|
||||
for line in initlines:
|
||||
if line.startswith('version'):
|
||||
line = 'version = %r\n' % shortversion
|
||||
replaced |= 1
|
||||
elif line.startswith('release'):
|
||||
line = 'release = %r\n' % longversion
|
||||
replaced |= 2
|
||||
fp.write(line)
|
||||
finally:
|
||||
fp.close()
|
||||
assert replaced & 3 != 0, "version/release not found in conf.py"
|
||||
|
||||
def _version_download(self, strversion):
|
||||
""" Modify version in website download docs """
|
||||
filename = _os.path.join(
|
||||
self.dirs['userdoc_source'], 'website_download.txt'
|
||||
)
|
||||
VERSION, PATH = strversion, ''
|
||||
fp = open(filename + '.in')
|
||||
try:
|
||||
dllines = fp.readlines()
|
||||
finally:
|
||||
fp.close()
|
||||
instable = []
|
||||
fp = open(filename, 'w')
|
||||
try:
|
||||
for line in dllines:
|
||||
if instable:
|
||||
instable.append(line)
|
||||
if line.startswith('.. end stable'):
|
||||
res = (''.join(instable)
|
||||
.replace('@@VERSION@@', strversion)
|
||||
.replace('@@PATH@@', '')
|
||||
)
|
||||
fp.write(res)
|
||||
instable = []
|
||||
elif line.startswith('.. begin stable'):
|
||||
instable.append(line)
|
||||
else:
|
||||
fp.write(line
|
||||
.replace('@@VERSION@@', VERSION)
|
||||
.replace('@@PATH@@', PATH)
|
||||
)
|
||||
finally:
|
||||
fp.close()
|
||||
|
||||
def clean(self, scm, dist):
|
||||
""" Clean versioned files """
|
||||
if scm:
|
||||
term.green("Removing generated ebuild files")
|
||||
for name in shell.files(self.dirs['ebuild'], '*.ebuild'):
|
||||
shell.rm(name)
|
||||
|
||||
|
||||
make.main(name=__name__)
|
78
package.cfg
Normal file
78
package.cfg
Normal file
@ -0,0 +1,78 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Copyright 2009 - 2013
|
||||
# André Malo or his licensors, as applicable
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
[package]
|
||||
name = rjsmin
|
||||
|
||||
python.min = 2.3
|
||||
python.max = 3.3
|
||||
pypy.min = 1.9
|
||||
pypy.max = 2.0
|
||||
jython.min = 2.5
|
||||
jython.max = 2.7
|
||||
|
||||
version.number = 1.0.7
|
||||
|
||||
author.name = André Malo
|
||||
author.email = nd@perlig.de
|
||||
#maintainer.name =
|
||||
#maintainer.email =
|
||||
url.homepage = http://opensource.perlig.de/rjsmin/
|
||||
url.download = http://storage.perlig.de/rjsmin/
|
||||
|
||||
|
||||
[docs]
|
||||
meta.classifiers = docs/CLASSIFIERS
|
||||
meta.description = docs/DESCRIPTION
|
||||
meta.summary = docs/SUMMARY
|
||||
meta.provides = docs/PROVIDES
|
||||
meta.license = LICENSE
|
||||
meta.keywords =
|
||||
Javascript
|
||||
Minimization
|
||||
|
||||
apidoc.dir = docs/apidoc
|
||||
apidoc.strip = 1
|
||||
#apidoc.ignore =
|
||||
|
||||
#userdoc.dir = docs/userdoc
|
||||
#userdoc.strip = 1
|
||||
#userdoc.ignore =
|
||||
# .buildinfo
|
||||
|
||||
#examples.dir = docs/examples
|
||||
#examples.strip = 1
|
||||
#examples.ignore =
|
||||
|
||||
#man =
|
||||
|
||||
extra =
|
||||
README.rst
|
||||
docs/CHANGES
|
||||
docs/BENCHMARKS
|
||||
|
||||
|
||||
[manifest]
|
||||
#packages.lib = .
|
||||
#packages.collect =
|
||||
modules = rjsmin
|
||||
|
||||
#scripts =
|
||||
|
||||
dist =
|
||||
bench.py
|
||||
bench
|
420
rjsmin.c
Normal file
420
rjsmin.c
Normal file
@ -0,0 +1,420 @@
|
||||
/*
|
||||
* Copyright 2011, 2012
|
||||
* Andr\xe9 Malo or his licensors, as applicable
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "cext.h"
|
||||
EXT_INIT_FUNC;
|
||||
|
||||
#define RJSMIN_DULL_BIT (1 << 0)
|
||||
#define RJSMIN_PRE_REGEX_BIT (1 << 1)
|
||||
#define RJSMIN_REGEX_DULL_BIT (1 << 2)
|
||||
#define RJSMIN_REGEX_CC_DULL_BIT (1 << 3)
|
||||
#define RJSMIN_ID_LIT_BIT (1 << 4)
|
||||
#define RJSMIN_ID_LIT_O_BIT (1 << 5)
|
||||
#define RJSMIN_ID_LIT_C_BIT (1 << 6)
|
||||
#define RJSMIN_STRING_DULL_BIT (1 << 7)
|
||||
#define RJSMIN_SPACE_BIT (1 << 8)
|
||||
|
||||
#ifdef EXT3
|
||||
typedef Py_UNICODE rchar;
|
||||
#else
|
||||
typedef unsigned char rchar;
|
||||
#endif
|
||||
#define U(c) ((rchar)(c))
|
||||
|
||||
#define RJSMIN_IS_DULL(c) ((U(c) > 127) || \
|
||||
(rjsmin_charmask[U(c) & 0x7F] & RJSMIN_DULL_BIT))
|
||||
|
||||
#define RJSMIN_IS_REGEX_DULL(c) ((U(c) > 127) || \
|
||||
(rjsmin_charmask[U(c) & 0x7F] & RJSMIN_REGEX_DULL_BIT))
|
||||
|
||||
#define RJSMIN_IS_REGEX_CC_DULL(c) ((U(c) > 127) || \
|
||||
(rjsmin_charmask[U(c) & 0x7F] & RJSMIN_REGEX_CC_DULL_BIT))
|
||||
|
||||
#define RJSMIN_IS_STRING_DULL(c) ((U(c) > 127) || \
|
||||
(rjsmin_charmask[U(c) & 0x7F] & RJSMIN_STRING_DULL_BIT))
|
||||
|
||||
#define RJSMIN_IS_ID_LITERAL(c) ((U(c) > 127) || \
|
||||
(rjsmin_charmask[U(c) & 0x7F] & RJSMIN_ID_LIT_BIT))
|
||||
|
||||
#define RJSMIN_IS_ID_LITERAL_OPEN(c) ((U(c) > 127) || \
|
||||
(rjsmin_charmask[U(c) & 0x7F] & RJSMIN_ID_LIT_O_BIT))
|
||||
|
||||
#define RJSMIN_IS_ID_LITERAL_CLOSE(c) ((U(c) > 127) || \
|
||||
(rjsmin_charmask[U(c) & 0x7F] & RJSMIN_ID_LIT_C_BIT))
|
||||
|
||||
#define RJSMIN_IS_SPACE(c) ((U(c) <= 127) && \
|
||||
(rjsmin_charmask[U(c) & 0x7F] & RJSMIN_SPACE_BIT))
|
||||
|
||||
#define RJSMIN_IS_PRE_REGEX_1(c) ((U(c) <= 127) && \
|
||||
(rjsmin_charmask[U(c) & 0x7F] & RJSMIN_PRE_REGEX_BIT))
|
||||
|
||||
|
||||
static const unsigned short rjsmin_charmask[128] = {
|
||||
396, 396, 396, 396, 396, 396, 396, 396,
|
||||
396, 396, 2, 396, 396, 2, 396, 396,
|
||||
396, 396, 396, 396, 396, 396, 396, 396,
|
||||
396, 396, 396, 396, 396, 396, 396, 396,
|
||||
396, 175, 76, 141, 253, 141, 143, 76,
|
||||
175, 205, 141, 237, 143, 237, 141, 136,
|
||||
253, 253, 253, 253, 253, 253, 253, 253,
|
||||
253, 253, 143, 143, 141, 143, 141, 143,
|
||||
141, 253, 253, 253, 253, 253, 253, 253,
|
||||
253, 253, 253, 253, 253, 253, 253, 253,
|
||||
253, 253, 253, 253, 253, 253, 253, 253,
|
||||
253, 253, 253, 171, 1, 197, 141, 253,
|
||||
141, 253, 253, 253, 253, 253, 253, 253,
|
||||
253, 253, 253, 253, 253, 253, 253, 253,
|
||||
253, 253, 253, 253, 253, 253, 253, 253,
|
||||
253, 253, 253, 175, 143, 207, 141, 253
|
||||
};
|
||||
|
||||
static Py_ssize_t
|
||||
rjsmin(const rchar *source, rchar *target, Py_ssize_t length)
|
||||
{
|
||||
const rchar *reset, *sentinel = source + length;
|
||||
rchar *tstart = target;
|
||||
rchar c, quote;
|
||||
|
||||
while (source < sentinel) {
|
||||
c = *source++;
|
||||
if (RJSMIN_IS_DULL(c)) {
|
||||
*target++ = c;
|
||||
continue;
|
||||
}
|
||||
switch (c) {
|
||||
|
||||
/* String */
|
||||
case U('\''): case U('"'):
|
||||
reset = source;
|
||||
*target++ = quote = c;
|
||||
while (source < sentinel) {
|
||||
c = *source++;
|
||||
*target++ = c;
|
||||
if (RJSMIN_IS_STRING_DULL(c))
|
||||
continue;
|
||||
switch (c) {
|
||||
case U('\''): case U('"'):
|
||||
if (c == quote)
|
||||
goto cont;
|
||||
continue;
|
||||
case U('\\'):
|
||||
if (source < sentinel) {
|
||||
c = *source++;
|
||||
*target++ = c;
|
||||
if (c == U('\r') && source < sentinel
|
||||
&& *source == U('\n'))
|
||||
*target++ = *source++;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
target -= source - reset;
|
||||
source = reset;
|
||||
continue;
|
||||
|
||||
/* Comment or Regex or something else entirely */
|
||||
case U('/'):
|
||||
if (!(source < sentinel)) {
|
||||
*target++ = c;
|
||||
}
|
||||
else {
|
||||
switch (*source) {
|
||||
/* Comment */
|
||||
case U('*'): case U('/'):
|
||||
goto skip_or_copy_ws;
|
||||
|
||||
default:
|
||||
if ( target == tstart
|
||||
|| RJSMIN_IS_PRE_REGEX_1(*(target - 1))
|
||||
|| (
|
||||
(target - tstart >= 6)
|
||||
&& *(target - 1) == U('n')
|
||||
&& *(target - 2) == U('r')
|
||||
&& *(target - 3) == U('u')
|
||||
&& *(target - 4) == U('t')
|
||||
&& *(target - 5) == U('e')
|
||||
&& *(target - 6) == U('r')
|
||||
&& (
|
||||
target - tstart == 6
|
||||
|| !RJSMIN_IS_ID_LITERAL(*(target - 7))
|
||||
)
|
||||
)) {
|
||||
|
||||
/* Regex */
|
||||
reset = source;
|
||||
*target++ = U('/');
|
||||
while (source < sentinel) {
|
||||
c = *source++;
|
||||
*target++ = c;
|
||||
if (RJSMIN_IS_REGEX_DULL(c))
|
||||
continue;
|
||||
switch (c) {
|
||||
case U('/'):
|
||||
goto cont;
|
||||
case U('\\'):
|
||||
if (source < sentinel) {
|
||||
c = *source++;
|
||||
*target++ = c;
|
||||
if (c == U('\r') || c == U('\n'))
|
||||
break;
|
||||
}
|
||||
continue;
|
||||
case U('['):
|
||||
while (source < sentinel) {
|
||||
c = *source++;
|
||||
*target++ = c;
|
||||
if (RJSMIN_IS_REGEX_CC_DULL(c))
|
||||
continue;
|
||||
switch (c) {
|
||||
case U('\\'):
|
||||
if (source < sentinel) {
|
||||
c = *source++;
|
||||
*target++ = c;
|
||||
if (c == U('\r') || c == U('\n'))
|
||||
break;
|
||||
}
|
||||
continue;
|
||||
case U(']'):
|
||||
goto cont_regex;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
cont_regex:
|
||||
continue;
|
||||
}
|
||||
target -= source - reset;
|
||||
source = reset;
|
||||
}
|
||||
else {
|
||||
/* Just a slash */
|
||||
*target++ = c;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
}
|
||||
continue;
|
||||
|
||||
/* Whitespace */
|
||||
default:
|
||||
skip_or_copy_ws:
|
||||
quote = U(' ');
|
||||
--source;
|
||||
while (source < sentinel) {
|
||||
c = *source++;
|
||||
if (RJSMIN_IS_SPACE(c))
|
||||
continue;
|
||||
switch (c) {
|
||||
case U('\r'): case U('\n'):
|
||||
quote = U('\n');
|
||||
continue;
|
||||
case U('/'):
|
||||
if (source < sentinel) {
|
||||
switch (*source) {
|
||||
case U('*'):
|
||||
reset = source;
|
||||
c = *source++;
|
||||
while (source < sentinel) {
|
||||
c = *source++;
|
||||
if (c == U('*') && source < sentinel
|
||||
&& *source == U('/')) {
|
||||
++source;
|
||||
reset = NULL;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!reset)
|
||||
continue;
|
||||
source = reset;
|
||||
*target++ = U('/');
|
||||
goto cont;
|
||||
case U('/'):
|
||||
++source;
|
||||
while (source < sentinel) {
|
||||
c = *source++;
|
||||
switch (c) {
|
||||
case U('\n'):
|
||||
break;
|
||||
case U('\r'):
|
||||
if (source < sentinel
|
||||
&& *source == U('\n'))
|
||||
++source;
|
||||
break;
|
||||
default:
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
quote = U('\n');
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
--source;
|
||||
break;
|
||||
}
|
||||
|
||||
if ((tstart < target && source < sentinel)
|
||||
&& ((quote == U('\n')
|
||||
&& RJSMIN_IS_ID_LITERAL_CLOSE(*(target - 1))
|
||||
&& RJSMIN_IS_ID_LITERAL_OPEN(*source))
|
||||
||
|
||||
(quote == U(' ')
|
||||
&& ((RJSMIN_IS_ID_LITERAL(*(target - 1))
|
||||
&& RJSMIN_IS_ID_LITERAL(*source))
|
||||
|| (source < sentinel
|
||||
&& ((*(target - 1) == U('+')
|
||||
&& *source == U('+'))
|
||||
|| (*(target - 1) == U('-')
|
||||
&& *source == U('-'))))))))
|
||||
*target++ = quote;
|
||||
}
|
||||
cont:
|
||||
continue;
|
||||
}
|
||||
return (Py_ssize_t)(target - tstart);
|
||||
}
|
||||
|
||||
|
||||
PyDoc_STRVAR(rjsmin_jsmin__doc__,
|
||||
"jsmin(script)\n\
|
||||
\n\
|
||||
Minify javascript based on `jsmin.c by Douglas Crockford`_\\.\n\
|
||||
\n\
|
||||
Instead of parsing the stream char by char, it uses a regular\n\
|
||||
expression approach which minifies the whole script with one big\n\
|
||||
substitution regex.\n\
|
||||
\n\
|
||||
.. _jsmin.c by Douglas Crockford:\n\
|
||||
http://www.crockford.com/javascript/jsmin.c\n\
|
||||
\n\
|
||||
:Note: This is a hand crafted C implementation built on the regex\n\
|
||||
semantics.\n\
|
||||
\n\
|
||||
:Parameters:\n\
|
||||
`script` : ``str``\n\
|
||||
Script to minify\n\
|
||||
\n\
|
||||
:Return: Minified script\n\
|
||||
:Rtype: ``str``");
|
||||
|
||||
static PyObject *
|
||||
rjsmin_jsmin(PyObject *self, PyObject *args, PyObject *kwds)
|
||||
{
|
||||
PyObject *script, *result;
|
||||
static char *kwlist[] = {"script", NULL};
|
||||
Py_ssize_t slength, length;
|
||||
#ifdef EXT2
|
||||
int uni;
|
||||
#define UOBJ "O"
|
||||
#endif
|
||||
#ifdef EXT3
|
||||
#define UOBJ "U"
|
||||
#endif
|
||||
|
||||
if (!PyArg_ParseTupleAndKeywords(args, kwds, UOBJ, kwlist,
|
||||
&script))
|
||||
return NULL;
|
||||
|
||||
#ifdef EXT2
|
||||
if (PyUnicode_Check(script)) {
|
||||
if (!(script = PyUnicode_AsUTF8String(script)))
|
||||
return NULL;
|
||||
uni = 1;
|
||||
}
|
||||
else {
|
||||
if (!(script = PyObject_Str(script)))
|
||||
return NULL;
|
||||
uni = 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef EXT3
|
||||
Py_INCREF(script);
|
||||
#define PyString_GET_SIZE PyUnicode_GET_SIZE
|
||||
#define PyString_AS_STRING PyUnicode_AS_UNICODE
|
||||
#define _PyString_Resize PyUnicode_Resize
|
||||
#define PyString_FromStringAndSize PyUnicode_FromUnicode
|
||||
#endif
|
||||
|
||||
slength = PyString_GET_SIZE(script);
|
||||
if (!(result = PyString_FromStringAndSize(NULL, slength))) {
|
||||
Py_DECREF(script);
|
||||
return NULL;
|
||||
}
|
||||
Py_BEGIN_ALLOW_THREADS
|
||||
length = rjsmin((rchar *)PyString_AS_STRING(script),
|
||||
(rchar *)PyString_AS_STRING(result),
|
||||
slength);
|
||||
Py_END_ALLOW_THREADS
|
||||
|
||||
Py_DECREF(script);
|
||||
if (length < 0) {
|
||||
Py_DECREF(result);
|
||||
return NULL;
|
||||
}
|
||||
if (length != slength && _PyString_Resize(&result, length) == -1)
|
||||
return NULL;
|
||||
|
||||
#ifdef EXT2
|
||||
if (uni) {
|
||||
script = PyUnicode_DecodeUTF8(PyString_AS_STRING(result),
|
||||
PyString_GET_SIZE(result), "strict");
|
||||
Py_DECREF(result);
|
||||
if (!script)
|
||||
return NULL;
|
||||
result = script;
|
||||
}
|
||||
#endif
|
||||
return result;
|
||||
}
|
||||
|
||||
/* ------------------------ BEGIN MODULE DEFINITION ------------------------ */
|
||||
|
||||
EXT_METHODS = {
|
||||
{"jsmin",
|
||||
(PyCFunction)rjsmin_jsmin, METH_VARARGS | METH_KEYWORDS,
|
||||
rjsmin_jsmin__doc__},
|
||||
|
||||
{NULL} /* Sentinel */
|
||||
};
|
||||
|
||||
PyDoc_STRVAR(EXT_DOCS_VAR,
|
||||
"C implementation of rjsmin\n\
|
||||
==========================\n\
|
||||
\n\
|
||||
C implementation of rjsmin.");
|
||||
|
||||
|
||||
EXT_DEFINE(EXT_MODULE_NAME, EXT_METHODS_VAR, EXT_DOCS_VAR);
|
||||
|
||||
EXT_INIT_FUNC {
|
||||
PyObject *m;
|
||||
|
||||
/* Create the module and populate stuff */
|
||||
if (!(m = EXT_CREATE(&EXT_DEFINE_VAR)))
|
||||
EXT_INIT_ERROR(NULL);
|
||||
|
||||
EXT_ADD_UNICODE(m, "__author__", "Andr\xe9 Malo", "latin-1");
|
||||
EXT_ADD_STRING(m, "__docformat__", "restructuredtext en");
|
||||
|
||||
EXT_INIT_RETURN(m);
|
||||
}
|
||||
|
||||
/* ------------------------- END MODULE DEFINITION ------------------------- */
|
300
rjsmin.py
Executable file
300
rjsmin.py
Executable file
@ -0,0 +1,300 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: ascii -*-
|
||||
#
|
||||
# Copyright 2011 - 2013
|
||||
# Andr\xe9 Malo or his licensors, as applicable
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
r"""
|
||||
=====================
|
||||
Javascript Minifier
|
||||
=====================
|
||||
|
||||
rJSmin is a javascript minifier written in python.
|
||||
|
||||
The minifier is based on the semantics of `jsmin.c by Douglas Crockford`_\.
|
||||
|
||||
The module is a re-implementation aiming for speed, so it can be used at
|
||||
runtime (rather than during a preprocessing step). Usually it produces the
|
||||
same results as the original ``jsmin.c``. It differs in the following ways:
|
||||
|
||||
- there is no error detection: unterminated string, regex and comment
|
||||
literals are treated as regular javascript code and minified as such.
|
||||
- Control characters inside string and regex literals are left untouched; they
|
||||
are not converted to spaces (nor to \n)
|
||||
- Newline characters are not allowed inside string and regex literals, except
|
||||
for line continuations in string literals (ECMA-5).
|
||||
- "return /regex/" is recognized correctly.
|
||||
- "+ +" and "- -" sequences are not collapsed to '++' or '--'
|
||||
- Newlines before ! operators are removed more sensibly
|
||||
- rJSmin does not handle streams, but only complete strings. (However, the
|
||||
module provides a "streamy" interface).
|
||||
|
||||
Since most parts of the logic are handled by the regex engine it's way
|
||||
faster than the original python port of ``jsmin.c`` by Baruch Even. The speed
|
||||
factor varies between about 6 and 55 depending on input and python version
|
||||
(it gets faster the more compressed the input already is). Compared to the
|
||||
speed-refactored python port by Dave St.Germain the performance gain is less
|
||||
dramatic but still between 1.2 and 7. See the docs/BENCHMARKS file for
|
||||
details.
|
||||
|
||||
rjsmin.c is a reimplementation of rjsmin.py in C and speeds it up even more.
|
||||
|
||||
Both python 2 and python 3 are supported.
|
||||
|
||||
.. _jsmin.c by Douglas Crockford:
|
||||
http://www.crockford.com/javascript/jsmin.c
|
||||
"""
|
||||
__author__ = "Andr\xe9 Malo"
|
||||
__author__ = getattr(__author__, 'decode', lambda x: __author__)('latin-1')
|
||||
__docformat__ = "restructuredtext en"
|
||||
__license__ = "Apache License, Version 2.0"
|
||||
__version__ = '1.0.7'
|
||||
__all__ = ['jsmin']
|
||||
|
||||
import re as _re
|
||||
|
||||
|
||||
def _make_jsmin(python_only=False):
|
||||
"""
|
||||
Generate JS minifier based on `jsmin.c by Douglas Crockford`_
|
||||
|
||||
.. _jsmin.c by Douglas Crockford:
|
||||
http://www.crockford.com/javascript/jsmin.c
|
||||
|
||||
:Parameters:
|
||||
`python_only` : ``bool``
|
||||
Use only the python variant. If true, the c extension is not even
|
||||
tried to be loaded.
|
||||
|
||||
:Return: Minifier
|
||||
:Rtype: ``callable``
|
||||
"""
|
||||
# pylint: disable = R0912, R0914, W0612
|
||||
if not python_only:
|
||||
try:
|
||||
import _rjsmin
|
||||
except ImportError:
|
||||
pass
|
||||
else:
|
||||
return _rjsmin.jsmin
|
||||
try:
|
||||
xrange
|
||||
except NameError:
|
||||
xrange = range # pylint: disable = W0622
|
||||
|
||||
space_chars = r'[\000-\011\013\014\016-\040]'
|
||||
|
||||
line_comment = r'(?://[^\r\n]*)'
|
||||
space_comment = r'(?:/\*[^*]*\*+(?:[^/*][^*]*\*+)*/)'
|
||||
string1 = \
|
||||
r'(?:\047[^\047\\\r\n]*(?:\\(?:[^\r\n]|\r?\n|\r)[^\047\\\r\n]*)*\047)'
|
||||
string2 = r'(?:"[^"\\\r\n]*(?:\\(?:[^\r\n]|\r?\n|\r)[^"\\\r\n]*)*")'
|
||||
strings = r'(?:%s|%s)' % (string1, string2)
|
||||
|
||||
charclass = r'(?:\[[^\\\]\r\n]*(?:\\[^\r\n][^\\\]\r\n]*)*\])'
|
||||
nospecial = r'[^/\\\[\r\n]'
|
||||
regex = r'(?:/(?![\r\n/*])%s*(?:(?:\\[^\r\n]|%s)%s*)*/)' % (
|
||||
nospecial, charclass, nospecial
|
||||
)
|
||||
space = r'(?:%s|%s)' % (space_chars, space_comment)
|
||||
newline = r'(?:%s?[\r\n])' % line_comment
|
||||
|
||||
def fix_charclass(result):
|
||||
""" Fixup string of chars to fit into a regex char class """
|
||||
pos = result.find('-')
|
||||
if pos >= 0:
|
||||
result = r'%s%s-' % (result[:pos], result[pos + 1:])
|
||||
|
||||
def sequentize(string):
|
||||
"""
|
||||
Notate consecutive characters as sequence
|
||||
|
||||
(1-4 instead of 1234)
|
||||
"""
|
||||
first, last, result = None, None, []
|
||||
for char in map(ord, string):
|
||||
if last is None:
|
||||
first = last = char
|
||||
elif last + 1 == char:
|
||||
last = char
|
||||
else:
|
||||
result.append((first, last))
|
||||
first = last = char
|
||||
if last is not None:
|
||||
result.append((first, last))
|
||||
return ''.join(['%s%s%s' % (
|
||||
chr(first),
|
||||
last > first + 1 and '-' or '',
|
||||
last != first and chr(last) or ''
|
||||
) for first, last in result])
|
||||
|
||||
return _re.sub(r'([\000-\040\047])', # for better portability
|
||||
lambda m: '\\%03o' % ord(m.group(1)), (sequentize(result)
|
||||
.replace('\\', '\\\\')
|
||||
.replace('[', '\\[')
|
||||
.replace(']', '\\]')
|
||||
)
|
||||
)
|
||||
|
||||
def id_literal_(what):
|
||||
""" Make id_literal like char class """
|
||||
match = _re.compile(what).match
|
||||
result = ''.join([
|
||||
chr(c) for c in xrange(127) if not match(chr(c))
|
||||
])
|
||||
return '[^%s]' % fix_charclass(result)
|
||||
|
||||
def not_id_literal_(keep):
|
||||
""" Make negated id_literal like char class """
|
||||
match = _re.compile(id_literal_(keep)).match
|
||||
result = ''.join([
|
||||
chr(c) for c in xrange(127) if not match(chr(c))
|
||||
])
|
||||
return r'[%s]' % fix_charclass(result)
|
||||
|
||||
not_id_literal = not_id_literal_(r'[a-zA-Z0-9_$]')
|
||||
preregex1 = r'[(,=:\[!&|?{};\r\n]'
|
||||
preregex2 = r'%(not_id_literal)sreturn' % locals()
|
||||
|
||||
id_literal = id_literal_(r'[a-zA-Z0-9_$]')
|
||||
id_literal_open = id_literal_(r'[a-zA-Z0-9_${\[(!+-]')
|
||||
id_literal_close = id_literal_(r'[a-zA-Z0-9_$}\])"\047+-]')
|
||||
|
||||
dull = r'[^\047"/\000-\040]'
|
||||
|
||||
space_sub = _re.compile((
|
||||
r'(%(dull)s+)'
|
||||
r'|(%(strings)s%(dull)s*)'
|
||||
r'|(?<=%(preregex1)s)'
|
||||
r'%(space)s*(?:%(newline)s%(space)s*)*'
|
||||
r'(%(regex)s%(dull)s*)'
|
||||
r'|(?<=%(preregex2)s)'
|
||||
r'%(space)s*(?:%(newline)s%(space)s)*'
|
||||
r'(%(regex)s%(dull)s*)'
|
||||
r'|(?<=%(id_literal_close)s)'
|
||||
r'%(space)s*(?:(%(newline)s)%(space)s*)+'
|
||||
r'(?=%(id_literal_open)s)'
|
||||
r'|(?<=%(id_literal)s)(%(space)s)+(?=%(id_literal)s)'
|
||||
r'|(?<=\+)(%(space)s)+(?=\+)'
|
||||
r'|(?<=-)(%(space)s)+(?=-)'
|
||||
r'|%(space)s+'
|
||||
r'|(?:%(newline)s%(space)s*)+'
|
||||
) % locals()).sub
|
||||
#print space_sub.__self__.pattern
|
||||
|
||||
def space_subber(match):
|
||||
""" Substitution callback """
|
||||
# pylint: disable = C0321, R0911
|
||||
groups = match.groups()
|
||||
if groups[0]: return groups[0]
|
||||
elif groups[1]: return groups[1]
|
||||
elif groups[2]: return groups[2]
|
||||
elif groups[3]: return groups[3]
|
||||
elif groups[4]: return '\n'
|
||||
elif groups[5] or groups[6] or groups[7]: return ' '
|
||||
else: return ''
|
||||
|
||||
def jsmin(script): # pylint: disable = W0621
|
||||
r"""
|
||||
Minify javascript based on `jsmin.c by Douglas Crockford`_\.
|
||||
|
||||
Instead of parsing the stream char by char, it uses a regular
|
||||
expression approach which minifies the whole script with one big
|
||||
substitution regex.
|
||||
|
||||
.. _jsmin.c by Douglas Crockford:
|
||||
http://www.crockford.com/javascript/jsmin.c
|
||||
|
||||
:Parameters:
|
||||
`script` : ``str``
|
||||
Script to minify
|
||||
|
||||
:Return: Minified script
|
||||
:Rtype: ``str``
|
||||
"""
|
||||
return space_sub(space_subber, '\n%s\n' % script).strip()
|
||||
|
||||
return jsmin
|
||||
|
||||
jsmin = _make_jsmin()
|
||||
|
||||
|
||||
def jsmin_for_posers(script):
|
||||
r"""
|
||||
Minify javascript based on `jsmin.c by Douglas Crockford`_\.
|
||||
|
||||
Instead of parsing the stream char by char, it uses a regular
|
||||
expression approach which minifies the whole script with one big
|
||||
substitution regex.
|
||||
|
||||
.. _jsmin.c by Douglas Crockford:
|
||||
http://www.crockford.com/javascript/jsmin.c
|
||||
|
||||
:Warning: This function is the digest of a _make_jsmin() call. It just
|
||||
utilizes the resulting regex. It's just for fun here and may
|
||||
vanish any time. Use the `jsmin` function instead.
|
||||
|
||||
:Parameters:
|
||||
`script` : ``str``
|
||||
Script to minify
|
||||
|
||||
:Return: Minified script
|
||||
:Rtype: ``str``
|
||||
"""
|
||||
def subber(match):
|
||||
""" Substitution callback """
|
||||
groups = match.groups()
|
||||
return (
|
||||
groups[0] or
|
||||
groups[1] or
|
||||
groups[2] or
|
||||
groups[3] or
|
||||
(groups[4] and '\n') or
|
||||
(groups[5] and ' ') or
|
||||
(groups[6] and ' ') or
|
||||
(groups[7] and ' ') or
|
||||
''
|
||||
)
|
||||
|
||||
return _re.sub(
|
||||
r'([^\047"/\000-\040]+)|((?:(?:\047[^\047\\\r\n]*(?:\\(?:[^\r\n]|\r?'
|
||||
r'\n|\r)[^\047\\\r\n]*)*\047)|(?:"[^"\\\r\n]*(?:\\(?:[^\r\n]|\r?\n|'
|
||||
r'\r)[^"\\\r\n]*)*"))[^\047"/\000-\040]*)|(?<=[(,=:\[!&|?{};\r\n])(?'
|
||||
r':[\000-\011\013\014\016-\040]|(?:/\*[^*]*\*+(?:[^/*][^*]*\*+)*/))*'
|
||||
r'(?:(?:(?://[^\r\n]*)?[\r\n])(?:[\000-\011\013\014\016-\040]|(?:/\*'
|
||||
r'[^*]*\*+(?:[^/*][^*]*\*+)*/))*)*((?:/(?![\r\n/*])[^/\\\[\r\n]*(?:('
|
||||
r'?:\\[^\r\n]|(?:\[[^\\\]\r\n]*(?:\\[^\r\n][^\\\]\r\n]*)*\]))[^/\\\['
|
||||
r'\r\n]*)*/)[^\047"/\000-\040]*)|(?<=[\000-#%-,./:-@\[-^`{-~-]return'
|
||||
r')(?:[\000-\011\013\014\016-\040]|(?:/\*[^*]*\*+(?:[^/*][^*]*\*+)*/'
|
||||
r'))*(?:(?:(?://[^\r\n]*)?[\r\n])(?:[\000-\011\013\014\016-\040]|(?:'
|
||||
r'/\*[^*]*\*+(?:[^/*][^*]*\*+)*/)))*((?:/(?![\r\n/*])[^/\\\[\r\n]*(?'
|
||||
r':(?:\\[^\r\n]|(?:\[[^\\\]\r\n]*(?:\\[^\r\n][^\\\]\r\n]*)*\]))[^/'
|
||||
r'\\\[\r\n]*)*/)[^\047"/\000-\040]*)|(?<=[^\000-!#%&(*,./:-@\[\\^`{|'
|
||||
r'~])(?:[\000-\011\013\014\016-\040]|(?:/\*[^*]*\*+(?:[^/*][^*]*\*+)'
|
||||
r'*/))*(?:((?:(?://[^\r\n]*)?[\r\n]))(?:[\000-\011\013\014\016-\040]'
|
||||
r'|(?:/\*[^*]*\*+(?:[^/*][^*]*\*+)*/))*)+(?=[^\000-\040"#%-\047)*,./'
|
||||
r':-@\\-^`|-~])|(?<=[^\000-#%-,./:-@\[-^`{-~-])((?:[\000-\011\013\01'
|
||||
r'4\016-\040]|(?:/\*[^*]*\*+(?:[^/*][^*]*\*+)*/)))+(?=[^\000-#%-,./:'
|
||||
r'-@\[-^`{-~-])|(?<=\+)((?:[\000-\011\013\014\016-\040]|(?:/\*[^*]*'
|
||||
r'\*+(?:[^/*][^*]*\*+)*/)))+(?=\+)|(?<=-)((?:[\000-\011\013\014\016-'
|
||||
r'\040]|(?:/\*[^*]*\*+(?:[^/*][^*]*\*+)*/)))+(?=-)|(?:[\000-\011\013'
|
||||
r'\014\016-\040]|(?:/\*[^*]*\*+(?:[^/*][^*]*\*+)*/))+|(?:(?:(?://[^'
|
||||
r'\r\n]*)?[\r\n])(?:[\000-\011\013\014\016-\040]|(?:/\*[^*]*\*+(?:[^'
|
||||
r'/*][^*]*\*+)*/))*)+', subber, '\n%s\n' % script
|
||||
).strip()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
import sys as _sys
|
||||
_sys.stdout.write(jsmin(_sys.stdin.read()))
|
42
setup.py
Normal file
42
setup.py
Normal file
@ -0,0 +1,42 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: ascii -*-
|
||||
#
|
||||
# Copyright 2006 - 2013
|
||||
# Andr\xe9 Malo or his licensors, as applicable
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
import sys as _sys
|
||||
from _setup import run
|
||||
|
||||
|
||||
def setup(args=None, _manifest=0):
|
||||
""" Main setup function """
|
||||
from _setup.ext import Extension
|
||||
|
||||
if 'java' in _sys.platform.lower():
|
||||
# no c extension for jython
|
||||
ext = None
|
||||
else:
|
||||
ext=[Extension('_rjsmin', sources=['rjsmin.c'])]
|
||||
|
||||
return run(script_args=args, ext=ext, manifest_only=_manifest)
|
||||
|
||||
|
||||
def manifest():
|
||||
""" Create List of packaged files """
|
||||
return setup((), _manifest=1)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
setup()
|
Loading…
x
Reference in New Issue
Block a user